@forgeax/engine-render 0.1.28 → 0.1.30

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 (768) hide show
  1. package/README.md +856 -126
  2. package/dist/assembly/atmosphere-shader-prewarm.d.ts +6 -0
  3. package/dist/assembly/atmosphere-shader-prewarm.d.ts.map +1 -0
  4. package/dist/assembly/device-feature-admission.d.ts +4 -3
  5. package/dist/assembly/device-feature-admission.d.ts.map +1 -1
  6. package/dist/assembly/dynamic-geometry-host.d.ts +27 -0
  7. package/dist/assembly/dynamic-geometry-host.d.ts.map +1 -1
  8. package/dist/assembly/dynamic-geometry-runtime.d.ts +20 -0
  9. package/dist/assembly/dynamic-geometry-runtime.d.ts.map +1 -0
  10. package/dist/assembly/factory.d.ts +3 -1
  11. package/dist/assembly/factory.d.ts.map +1 -1
  12. package/dist/assembly/gpu-driven-owner.d.ts +10 -0
  13. package/dist/assembly/gpu-driven-owner.d.ts.map +1 -0
  14. package/dist/assembly/host-contract.d.ts +14 -0
  15. package/dist/assembly/host-contract.d.ts.map +1 -1
  16. package/dist/assembly/material/assembly.d.ts +31 -1
  17. package/dist/assembly/material/assembly.d.ts.map +1 -1
  18. package/dist/assembly/material/pipeline-helpers.d.ts +24 -0
  19. package/dist/assembly/material/pipeline-helpers.d.ts.map +1 -0
  20. package/dist/assembly/material-shader-policy.d.ts +3 -1
  21. package/dist/assembly/material-shader-policy.d.ts.map +1 -1
  22. package/dist/assembly/recovery/device-loss-fanout.d.ts.map +1 -1
  23. package/dist/assembly/recovery/failure-location.d.ts +12 -0
  24. package/dist/assembly/recovery/failure-location.d.ts.map +1 -0
  25. package/dist/assembly/recovery/recovery-attempt.d.ts +1 -6
  26. package/dist/assembly/recovery/recovery-attempt.d.ts.map +1 -1
  27. package/dist/assembly/recovery/renderer-recover.d.ts +7 -4
  28. package/dist/assembly/recovery/renderer-recover.d.ts.map +1 -1
  29. package/dist/assembly/renderer-facade.d.ts.map +1 -1
  30. package/dist/assembly/renderer-feature-inspection.d.ts +5 -0
  31. package/dist/assembly/renderer-feature-inspection.d.ts.map +1 -0
  32. package/dist/assembly/renderer-frame-transaction.d.ts +19 -0
  33. package/dist/assembly/renderer-frame-transaction.d.ts.map +1 -1
  34. package/dist/assembly/renderer-helpers.d.ts +3 -0
  35. package/dist/assembly/renderer-helpers.d.ts.map +1 -1
  36. package/dist/assembly/renderer-inspection.d.ts +4 -0
  37. package/dist/assembly/renderer-inspection.d.ts.map +1 -1
  38. package/dist/assembly/shader-prewarm-policy.d.ts +7 -1
  39. package/dist/assembly/shader-prewarm-policy.d.ts.map +1 -1
  40. package/dist/assembly/skin-palette-owner.d.ts +8 -0
  41. package/dist/assembly/skin-palette-owner.d.ts.map +1 -0
  42. package/dist/assembly/ssr-shader-prewarm.d.ts +6 -0
  43. package/dist/assembly/ssr-shader-prewarm.d.ts.map +1 -0
  44. package/dist/assembly/webgpu-device-loss.d.ts +15 -0
  45. package/dist/assembly/webgpu-device-loss.d.ts.map +1 -0
  46. package/dist/assembly/webgpu-pbr-ready.d.ts +38 -0
  47. package/dist/assembly/webgpu-pbr-ready.d.ts.map +1 -0
  48. package/dist/assembly/webgpu-ready-mipmap.d.ts +11 -0
  49. package/dist/assembly/webgpu-ready-mipmap.d.ts.map +1 -0
  50. package/dist/assembly/webgpu-ready.d.ts +7 -3
  51. package/dist/assembly/webgpu-ready.d.ts.map +1 -1
  52. package/dist/assembly/webgpu-renderer-bootstrap.d.ts +10 -0
  53. package/dist/assembly/webgpu-renderer-bootstrap.d.ts.map +1 -0
  54. package/dist/assembly/webgpu-renderer-contract.d.ts +62 -0
  55. package/dist/assembly/webgpu-renderer-contract.d.ts.map +1 -0
  56. package/dist/assembly/webgpu-renderer-guards.d.ts +9 -0
  57. package/dist/assembly/webgpu-renderer-guards.d.ts.map +1 -0
  58. package/dist/assembly/webgpu-renderer-observation.d.ts +6 -0
  59. package/dist/assembly/webgpu-renderer-observation.d.ts.map +1 -0
  60. package/dist/assembly/webgpu-renderer-recovery-failure.d.ts +12 -0
  61. package/dist/assembly/webgpu-renderer-recovery-failure.d.ts.map +1 -0
  62. package/dist/assembly/webgpu-renderer.d.ts +7 -141
  63. package/dist/assembly/webgpu-renderer.d.ts.map +1 -1
  64. package/dist/assembly/webgpu-vertex-layouts.d.ts +28 -84
  65. package/dist/assembly/webgpu-vertex-layouts.d.ts.map +1 -1
  66. package/dist/authoring.mjs +2 -2
  67. package/dist/capture/scene-projection.d.ts +41 -0
  68. package/dist/capture/scene-projection.d.ts.map +1 -0
  69. package/dist/{chunk-J52NMQKR.mjs → chunk-7MQ3XBSP.mjs} +1098 -844
  70. package/dist/chunk-7MQ3XBSP.mjs.map +1 -0
  71. package/dist/{chunk-GF523LHF.mjs → chunk-BLXGONR2.mjs} +30 -12
  72. package/dist/chunk-BLXGONR2.mjs.map +1 -0
  73. package/dist/{chunk-VSL23LZE.mjs → chunk-C3DDSXYK.mjs} +1188 -463
  74. package/dist/chunk-C3DDSXYK.mjs.map +1 -0
  75. package/dist/{chunk-IQMKJLNU.mjs → chunk-FUUO4UND.mjs} +443 -30
  76. package/dist/chunk-FUUO4UND.mjs.map +1 -0
  77. package/dist/{chunk-J6KACNOH.mjs → chunk-JRBDO2KB.mjs} +617 -7
  78. package/dist/chunk-JRBDO2KB.mjs.map +1 -0
  79. package/dist/{chunk-GE3SDD72.mjs → chunk-MDQJPY3T.mjs} +20 -40
  80. package/dist/chunk-MDQJPY3T.mjs.map +1 -0
  81. package/dist/{chunk-MYJ5RPJO.mjs → chunk-NO4WZCAH.mjs} +3 -3
  82. package/dist/chunk-NO4WZCAH.mjs.map +1 -0
  83. package/dist/{chunk-RBDBZ5R7.mjs → chunk-PA5DRJNI.mjs} +2 -2
  84. package/dist/chunk-PA5DRJNI.mjs.map +1 -0
  85. package/dist/{chunk-MBU4ZVE7.mjs → chunk-PSEQ6QPH.mjs} +4655 -892
  86. package/dist/chunk-PSEQ6QPH.mjs.map +1 -0
  87. package/dist/{chunk-JAASCMXA.mjs → chunk-S5UE2T5P.mjs} +289 -41
  88. package/dist/chunk-S5UE2T5P.mjs.map +1 -0
  89. package/dist/components/camera.d.ts +62 -2
  90. package/dist/components/camera.d.ts.map +1 -1
  91. package/dist/components/directional-light.d.ts +2 -2
  92. package/dist/components/dynamic-resolution.d.ts +15 -0
  93. package/dist/components/dynamic-resolution.d.ts.map +1 -0
  94. package/dist/components/index.d.ts +2 -0
  95. package/dist/components/index.d.ts.map +1 -1
  96. package/dist/components/instances.d.ts +6 -20
  97. package/dist/components/instances.d.ts.map +1 -1
  98. package/dist/components/light-helpers.d.ts.map +1 -1
  99. package/dist/components/reflection-probe.d.ts +1 -0
  100. package/dist/components/reflection-probe.d.ts.map +1 -1
  101. package/dist/components/scene-instance.d.ts +2 -1
  102. package/dist/components/scene-instance.d.ts.map +1 -1
  103. package/dist/components/screen-space-reflection.d.ts +14 -0
  104. package/dist/components/screen-space-reflection.d.ts.map +1 -0
  105. package/dist/components/skylight.d.ts +4 -1
  106. package/dist/components/skylight.d.ts.map +1 -1
  107. package/dist/construct-renderer.mjs +14809 -7570
  108. package/dist/construct-renderer.mjs.map +1 -1
  109. package/dist/device/device-scope.d.ts +2 -0
  110. package/dist/device/device-scope.d.ts.map +1 -1
  111. package/dist/device/gpu-residency.d.ts +3 -14
  112. package/dist/device/gpu-residency.d.ts.map +1 -1
  113. package/dist/dynamic-geometry.d.ts.map +1 -1
  114. package/dist/environment/background.d.ts +7 -0
  115. package/dist/environment/background.d.ts.map +1 -0
  116. package/dist/environment/ibl.d.ts +11 -0
  117. package/dist/environment/ibl.d.ts.map +1 -0
  118. package/dist/environment/storage.d.ts +14 -0
  119. package/dist/environment/storage.d.ts.map +1 -0
  120. package/dist/errors/gpu-driven.d.ts +6 -3
  121. package/dist/errors/gpu-driven.d.ts.map +1 -1
  122. package/dist/errors/render.d.ts +41 -4
  123. package/dist/errors/render.d.ts.map +1 -1
  124. package/dist/extract/camera.d.ts.map +1 -1
  125. package/dist/extract/contracts.d.ts +7 -0
  126. package/dist/extract/contracts.d.ts.map +1 -1
  127. package/dist/extract/gpu-driven.d.ts +50 -3
  128. package/dist/extract/gpu-driven.d.ts.map +1 -1
  129. package/dist/features/host.d.ts +23 -1
  130. package/dist/features/host.d.ts.map +1 -1
  131. package/dist/features/noise-texture.d.ts +17 -0
  132. package/dist/features/noise-texture.d.ts.map +1 -0
  133. package/dist/features/plan.d.ts +83 -2
  134. package/dist/features/plan.d.ts.map +1 -1
  135. package/dist/features/prepared-gpu-work.d.ts +37 -4
  136. package/dist/features/prepared-gpu-work.d.ts.map +1 -1
  137. package/dist/features/prepared-graphics-store.d.ts.map +1 -1
  138. package/dist/features/prepared-graphics.d.ts +5 -0
  139. package/dist/features/prepared-graphics.d.ts.map +1 -1
  140. package/dist/features/render-graph-compute.d.ts +5 -3
  141. package/dist/features/render-graph-compute.d.ts.map +1 -1
  142. package/dist/features/render-graph-contribution.d.ts +11 -3
  143. package/dist/features/render-graph-contribution.d.ts.map +1 -1
  144. package/dist/features/render-graph-raster.d.ts +19 -3
  145. package/dist/features/render-graph-raster.d.ts.map +1 -1
  146. package/dist/features/types.d.ts +11 -0
  147. package/dist/features/types.d.ts.map +1 -1
  148. package/dist/fullscreen-post-process-pass.d.ts +2 -0
  149. package/dist/fullscreen-post-process-pass.d.ts.map +1 -1
  150. package/dist/gpu-driven/batch-topology.d.ts +34 -1
  151. package/dist/gpu-driven/batch-topology.d.ts.map +1 -1
  152. package/dist/gpu-driven/material-artifacts.d.ts +24 -0
  153. package/dist/gpu-driven/material-artifacts.d.ts.map +1 -0
  154. package/dist/gpu-driven/material-bindings.d.ts +7 -0
  155. package/dist/gpu-driven/material-bindings.d.ts.map +1 -0
  156. package/dist/gpu-driven/pbr-program.d.ts +10 -0
  157. package/dist/gpu-driven/pbr-program.d.ts.map +1 -0
  158. package/dist/gpu-driven/prepared-draw.d.ts +2 -0
  159. package/dist/gpu-driven/prepared-draw.d.ts.map +1 -1
  160. package/dist/gpu-driven/production-raster.d.ts +169 -27
  161. package/dist/gpu-driven/production-raster.d.ts.map +1 -1
  162. package/dist/gpu-driven/shadow-views.d.ts +126 -0
  163. package/dist/gpu-driven/shadow-views.d.ts.map +1 -0
  164. package/dist/gpu-driven/view-gpu.d.ts +18 -2
  165. package/dist/gpu-driven/view-gpu.d.ts.map +1 -1
  166. package/dist/gpu-resource.d.ts +5 -2
  167. package/dist/gpu-resource.d.ts.map +1 -1
  168. package/dist/gpu-scene-schema.d.ts +2 -8
  169. package/dist/gpu-scene-schema.d.ts.map +1 -1
  170. package/dist/gpu-scene.d.ts +14 -0
  171. package/dist/gpu-scene.d.ts.map +1 -1
  172. package/dist/gpu-texture-usage.d.ts +1 -0
  173. package/dist/gpu-texture-usage.d.ts.map +1 -1
  174. package/dist/hdrp-buffers.d.ts +9 -0
  175. package/dist/hdrp-buffers.d.ts.map +1 -1
  176. package/dist/ibl/IblPipelineCache.d.ts +2 -0
  177. package/dist/ibl/IblPipelineCache.d.ts.map +1 -1
  178. package/dist/ibl/frame-resources.d.ts +8 -0
  179. package/dist/ibl/frame-resources.d.ts.map +1 -0
  180. package/dist/ibl/skylight-bind-group.d.ts +3 -1
  181. package/dist/ibl/skylight-bind-group.d.ts.map +1 -1
  182. package/dist/index.d.ts +87 -75
  183. package/dist/index.d.ts.map +1 -1
  184. package/dist/index.mjs +10 -8
  185. package/dist/index.mjs.map +1 -1
  186. package/dist/inspection-types.d.ts +180 -1
  187. package/dist/inspection-types.d.ts.map +1 -1
  188. package/dist/instances-derived-bounds.d.ts +11 -0
  189. package/dist/instances-derived-bounds.d.ts.map +1 -1
  190. package/dist/instances.d.ts +89 -44
  191. package/dist/instances.d.ts.map +1 -1
  192. package/dist/internal.d.ts +3 -0
  193. package/dist/internal.d.ts.map +1 -1
  194. package/dist/internal.mjs +117 -9
  195. package/dist/internal.mjs.map +1 -1
  196. package/dist/lifecycle.d.ts +2 -1
  197. package/dist/lifecycle.d.ts.map +1 -1
  198. package/dist/material-row.d.ts +15 -0
  199. package/dist/material-row.d.ts.map +1 -0
  200. package/dist/materials.d.ts +15 -0
  201. package/dist/materials.d.ts.map +1 -1
  202. package/dist/pbr-pipeline.d.ts +23 -5
  203. package/dist/pbr-pipeline.d.ts.map +1 -1
  204. package/dist/pipeline/render-extent.d.ts +51 -0
  205. package/dist/pipeline/render-extent.d.ts.map +1 -0
  206. package/dist/pipeline/standard-build-context.d.ts +7 -0
  207. package/dist/pipeline/standard-build-context.d.ts.map +1 -0
  208. package/dist/pipeline/standard-forward-lane.d.ts +3 -2
  209. package/dist/pipeline/standard-forward-lane.d.ts.map +1 -1
  210. package/dist/pipeline/standard-output/auto-exposure/capability.d.ts +12 -0
  211. package/dist/pipeline/standard-output/auto-exposure/capability.d.ts.map +1 -0
  212. package/dist/pipeline/standard-output/auto-exposure/gpu.d.ts +70 -0
  213. package/dist/pipeline/standard-output/auto-exposure/gpu.d.ts.map +1 -0
  214. package/dist/pipeline/standard-output/auto-exposure/graph.d.ts +75 -0
  215. package/dist/pipeline/standard-output/auto-exposure/graph.d.ts.map +1 -0
  216. package/dist/pipeline/standard-output/auto-exposure/inspection.d.ts +111 -0
  217. package/dist/pipeline/standard-output/auto-exposure/inspection.d.ts.map +1 -0
  218. package/dist/pipeline/standard-output/auto-exposure/oracle.d.ts +16 -0
  219. package/dist/pipeline/standard-output/auto-exposure/oracle.d.ts.map +1 -0
  220. package/dist/pipeline/standard-output/auto-exposure/preset.d.ts +14 -0
  221. package/dist/pipeline/standard-output/auto-exposure/preset.d.ts.map +1 -0
  222. package/dist/pipeline/standard-output/auto-exposure/state.d.ts +46 -0
  223. package/dist/pipeline/standard-output/auto-exposure/state.d.ts.map +1 -0
  224. package/dist/pipeline/standard-output/color-transform.d.ts +27 -0
  225. package/dist/pipeline/standard-output/color-transform.d.ts.map +1 -0
  226. package/dist/pipeline/standard-output/graph.d.ts +15 -0
  227. package/dist/pipeline/standard-output/graph.d.ts.map +1 -0
  228. package/dist/pipeline/standard-output/lut-admission.d.ts +29 -0
  229. package/dist/pipeline/standard-output/lut-admission.d.ts.map +1 -0
  230. package/dist/pipeline/standard-output/lut-gpu.d.ts +48 -0
  231. package/dist/pipeline/standard-output/lut-gpu.d.ts.map +1 -0
  232. package/dist/pipeline/standard-output/lut-state.d.ts +68 -0
  233. package/dist/pipeline/standard-output/lut-state.d.ts.map +1 -0
  234. package/dist/pipeline/standard-output/resources.d.ts +10 -0
  235. package/dist/pipeline/standard-output/resources.d.ts.map +1 -0
  236. package/dist/pipeline/standard-output/types.d.ts +39 -0
  237. package/dist/pipeline/standard-output/types.d.ts.map +1 -0
  238. package/dist/pipeline/standard-pipeline.d.ts.map +1 -1
  239. package/dist/pipeline/standard-post.d.ts +2 -2
  240. package/dist/pipeline/standard-post.d.ts.map +1 -1
  241. package/dist/pipeline/standard-profile.d.ts +2 -1
  242. package/dist/pipeline/standard-profile.d.ts.map +1 -1
  243. package/dist/pipeline-builder.d.ts +5 -2
  244. package/dist/pipeline-builder.d.ts.map +1 -1
  245. package/dist/pipeline-spec-types.d.ts +4 -0
  246. package/dist/pipeline-spec-types.d.ts.map +1 -1
  247. package/dist/pipeline-spec.d.ts +1 -9
  248. package/dist/pipeline-spec.d.ts.map +1 -1
  249. package/dist/plugin.d.ts.map +1 -1
  250. package/dist/points-lines/standard-owner.d.ts +1 -1
  251. package/dist/points-lines/standard-owner.d.ts.map +1 -1
  252. package/dist/post-process-errors.d.ts +9 -2
  253. package/dist/post-process-errors.d.ts.map +1 -1
  254. package/dist/prepare/extended-lighting/resources.d.ts +3 -3
  255. package/dist/prepare/prepared-graphics-resolver.d.ts +6 -1
  256. package/dist/prepare/prepared-graphics-resolver.d.ts.map +1 -1
  257. package/dist/record/dynamic-geometry-consumption.d.ts +15 -0
  258. package/dist/record/dynamic-geometry-consumption.d.ts.map +1 -0
  259. package/dist/record/frame-lighting.d.ts +3 -3
  260. package/dist/record/frame-lighting.d.ts.map +1 -1
  261. package/dist/record/frame-snapshot.d.ts +109 -13
  262. package/dist/record/frame-snapshot.d.ts.map +1 -1
  263. package/dist/record/frame-targets.d.ts.map +1 -1
  264. package/dist/record/frame.d.ts +41 -5
  265. package/dist/record/frame.d.ts.map +1 -1
  266. package/dist/record/main-pass-geometry.d.ts +13 -9
  267. package/dist/record/main-pass-geometry.d.ts.map +1 -1
  268. package/dist/record/main-pass-material.d.ts +43 -3
  269. package/dist/record/main-pass-material.d.ts.map +1 -1
  270. package/dist/record/main-pass-sprite-draws.d.ts +2 -10
  271. package/dist/record/main-pass-sprite-draws.d.ts.map +1 -1
  272. package/dist/record/main-pass.d.ts +14 -2
  273. package/dist/record/main-pass.d.ts.map +1 -1
  274. package/dist/record/mesh-ssbo.d.ts +15 -6
  275. package/dist/record/mesh-ssbo.d.ts.map +1 -1
  276. package/dist/record/prepared-material-bindings.d.ts +19 -0
  277. package/dist/record/prepared-material-bindings.d.ts.map +1 -0
  278. package/dist/record/recovery-pipeline.d.ts +1 -0
  279. package/dist/record/recovery-pipeline.d.ts.map +1 -1
  280. package/dist/record/render-context.d.ts +101 -22
  281. package/dist/record/render-context.d.ts.map +1 -1
  282. package/dist/record/shadow-pass.d.ts +62 -7
  283. package/dist/record/shadow-pass.d.ts.map +1 -1
  284. package/dist/record/skybox-post-pass.d.ts +1 -1
  285. package/dist/record/skybox-post-pass.d.ts.map +1 -1
  286. package/dist/record/typed-frame-graph.d.ts +39 -8
  287. package/dist/record/typed-frame-graph.d.ts.map +1 -1
  288. package/dist/record/view-ubo.d.ts +1 -0
  289. package/dist/record/view-ubo.d.ts.map +1 -1
  290. package/dist/recovery/render-system-candidate.d.ts +10 -2
  291. package/dist/recovery/render-system-candidate.d.ts.map +1 -1
  292. package/dist/recovery/render-system-roots.d.ts +11 -0
  293. package/dist/recovery/render-system-roots.d.ts.map +1 -0
  294. package/dist/recovery/types.d.ts +76 -0
  295. package/dist/recovery/types.d.ts.map +1 -0
  296. package/dist/reflection/background.d.ts +14 -0
  297. package/dist/reflection/background.d.ts.map +1 -0
  298. package/dist/reflection/filter.d.ts.map +1 -1
  299. package/dist/reflection/projection.d.ts +1 -0
  300. package/dist/reflection/projection.d.ts.map +1 -1
  301. package/dist/reflection/record-owner.d.ts +4 -4
  302. package/dist/reflection/record-owner.d.ts.map +1 -1
  303. package/dist/render-contract.d.ts +211 -53
  304. package/dist/render-contract.d.ts.map +1 -1
  305. package/dist/render-graph-primitives.d.ts +1 -0
  306. package/dist/render-graph-primitives.d.ts.map +1 -1
  307. package/dist/render-pipeline.d.ts +81 -6
  308. package/dist/render-pipeline.d.ts.map +1 -1
  309. package/dist/render-system-extract-tail.d.ts +15 -6
  310. package/dist/render-system-extract-tail.d.ts.map +1 -1
  311. package/dist/render-system-extract.d.ts +128 -41
  312. package/dist/render-system-extract.d.ts.map +1 -1
  313. package/dist/render-system-projections.d.ts +22 -0
  314. package/dist/render-system-projections.d.ts.map +1 -0
  315. package/dist/render-system.d.ts +27 -77
  316. package/dist/render-system.d.ts.map +1 -1
  317. package/dist/scene/render-scene-types.d.ts +14 -7
  318. package/dist/scene/render-scene-types.d.ts.map +1 -1
  319. package/dist/scene/render-scene.d.ts +31 -11
  320. package/dist/scene/render-scene.d.ts.map +1 -1
  321. package/dist/scene/shadow-visibility.d.ts +5 -0
  322. package/dist/scene/shadow-visibility.d.ts.map +1 -0
  323. package/dist/ssao-config.d.ts +8 -6
  324. package/dist/ssao-config.d.ts.map +1 -1
  325. package/dist/ssr/admission.d.ts +70 -1
  326. package/dist/ssr/admission.d.ts.map +1 -1
  327. package/dist/ssr/compose.d.ts +13 -0
  328. package/dist/ssr/compose.d.ts.map +1 -0
  329. package/dist/ssr/errors.d.ts +35 -0
  330. package/dist/ssr/errors.d.ts.map +1 -1
  331. package/dist/ssr/graph.d.ts +60 -0
  332. package/dist/ssr/graph.d.ts.map +1 -0
  333. package/dist/ssr/history.d.ts +97 -0
  334. package/dist/ssr/history.d.ts.map +1 -0
  335. package/dist/ssr/hiz.d.ts +37 -0
  336. package/dist/ssr/hiz.d.ts.map +1 -0
  337. package/dist/ssr/inspection.d.ts +42 -0
  338. package/dist/ssr/inspection.d.ts.map +1 -0
  339. package/dist/ssr/resources.d.ts +58 -0
  340. package/dist/ssr/resources.d.ts.map +1 -0
  341. package/dist/ssr/temporal.d.ts +38 -0
  342. package/dist/ssr/temporal.d.ts.map +1 -0
  343. package/dist/systems/skin-palette-allocator.d.ts +32 -10
  344. package/dist/systems/skin-palette-allocator.d.ts.map +1 -1
  345. package/dist/systems/skin-palette-types.d.ts +15 -0
  346. package/dist/systems/skin-palette-types.d.ts.map +1 -1
  347. package/dist/systems/transparent-dispatch.d.ts +9 -0
  348. package/dist/systems/transparent-dispatch.d.ts.map +1 -0
  349. package/dist/targets/material-source.d.ts +7 -0
  350. package/dist/targets/material-source.d.ts.map +1 -1
  351. package/dist/temporal/frame-coordinator.d.ts +7 -0
  352. package/dist/temporal/frame-coordinator.d.ts.map +1 -1
  353. package/dist/temporal/gpu.d.ts +8 -0
  354. package/dist/temporal/gpu.d.ts.map +1 -1
  355. package/dist/temporal/history.d.ts.map +1 -1
  356. package/dist/temporal/index.mjs +6 -6
  357. package/dist/temporal/inspection.d.ts.map +1 -1
  358. package/dist/temporal/standard-scene-data.d.ts +4 -2
  359. package/dist/temporal/standard-scene-data.d.ts.map +1 -1
  360. package/dist/temporal/target-coverage-attachment.d.ts +15 -0
  361. package/dist/temporal/target-coverage-attachment.d.ts.map +1 -0
  362. package/dist/temporal/temporal-view.d.ts +6 -0
  363. package/dist/temporal/temporal-view.d.ts.map +1 -1
  364. package/dist/temporal/view.d.ts +6 -0
  365. package/dist/temporal/view.d.ts.map +1 -1
  366. package/dist/typed-render-graph-primitives.d.ts +41 -1
  367. package/dist/typed-render-graph-primitives.d.ts.map +1 -1
  368. package/dist/typed-shadow-passes.d.ts +3 -1
  369. package/dist/typed-shadow-passes.d.ts.map +1 -1
  370. package/dist/volume/component.d.ts +1 -0
  371. package/dist/volume/component.d.ts.map +1 -1
  372. package/dist/volume/temporal.d.ts +6 -0
  373. package/dist/volume/temporal.d.ts.map +1 -1
  374. package/package.json +21 -20
  375. package/src/__tests__/auto-exposure-gpu-evidence.ts +291 -0
  376. package/src/__tests__/auto-exposure-inspection.unit.test.ts +80 -0
  377. package/src/__tests__/auto-exposure-transaction.integration.test.ts +99 -0
  378. package/src/__tests__/auto-exposure.browser.test.ts +33 -0
  379. package/src/__tests__/auto-exposure.dawn.test.ts +33 -0
  380. package/src/__tests__/capture-scene-projection.unit.test.ts +24 -0
  381. package/src/__tests__/detached-inspection.integration.test.ts +5 -0
  382. package/src/__tests__/device-feature-admission.unit.test.ts +15 -24
  383. package/src/__tests__/device-loss-fanout.unit.test.ts +43 -0
  384. package/src/__tests__/device-scope-lifecycle.unit.test.ts +18 -0
  385. package/src/__tests__/device-scope-stale-matrix.unit.test.ts +18 -0
  386. package/src/__tests__/docs-gate-green.unit.test.ts +3 -3
  387. package/src/__tests__/dynamic-geometry-batch.unit.test.ts +157 -0
  388. package/src/__tests__/dynamic-geometry.unit.test.ts +36 -0
  389. package/src/__tests__/dynamic-resolution-plugin.integration.test.ts +81 -0
  390. package/src/__tests__/factory-contract.integration.test.ts +231 -9
  391. package/src/__tests__/fallback-row-stride-surface.unit.test.ts +19 -0
  392. package/src/__tests__/feature-depth-input.dawn.test.ts +121 -0
  393. package/src/__tests__/feature-noise.unit.test.ts +38 -0
  394. package/src/__tests__/fixtures/taa-resolve-pinned-baseline.wgsl +301 -0
  395. package/src/__tests__/frame-camera-selection.unit.test.ts +131 -0
  396. package/src/__tests__/frame-observation.contract.test.ts +21 -0
  397. package/src/__tests__/frame-plan-contract.unit.test.ts +24 -0
  398. package/src/__tests__/frame-targets.unit.test.ts +24 -0
  399. package/src/__tests__/fullscreen-feature-plan.unit.test.ts +3 -0
  400. package/src/__tests__/gpu-driven-baseline.characterization.test.ts +79 -0
  401. package/src/__tests__/gpu-driven-batch-topology-pbr.unit.test.ts +307 -7
  402. package/src/__tests__/gpu-driven-indirect-raster-evidence.ts +122 -142
  403. package/src/__tests__/gpu-driven-indirect-raster.browser.test.ts +10 -1
  404. package/src/__tests__/gpu-driven-lod-cache.unit.test.ts +261 -0
  405. package/src/__tests__/gpu-driven-mesh-world-identity.unit.test.ts +346 -0
  406. package/src/__tests__/gpu-driven-pbr.dawn.test.ts +1422 -0
  407. package/src/__tests__/gpu-driven-pbr.integration.test.ts +21 -0
  408. package/src/__tests__/gpu-driven-production-fixture.ts +96 -0
  409. package/src/__tests__/gpu-driven-production.integration.test.ts +1076 -106
  410. package/src/__tests__/gpu-driven-scaling.unit.test.ts +1 -3
  411. package/src/__tests__/gpu-driven-shadow-views.browser.test.ts +63 -0
  412. package/src/__tests__/gpu-driven-shadow-views.dawn.test.ts +294 -0
  413. package/src/__tests__/gpu-driven-shadow-views.integration.test.ts +97 -0
  414. package/src/__tests__/gpu-driven-shadow-views.unit.test.ts +168 -0
  415. package/src/__tests__/gpu-driven-skin-contract.test-d.ts +11 -0
  416. package/src/__tests__/gpu-driven-view-gpu-evidence.ts +72 -20
  417. package/src/__tests__/gpu-driven-view-graph.integration.test.ts +30 -9
  418. package/src/__tests__/gpu-driven-view.unit.test.ts +160 -52
  419. package/src/__tests__/gpu-pass-timing-browser-runner.ts +15 -0
  420. package/src/__tests__/gpu-pass-timing.browser.test.ts +20 -2
  421. package/src/__tests__/gpu-resource-scope.unit.test.ts +71 -0
  422. package/src/__tests__/gpu-resource-store-stride.unit.test.ts +42 -0
  423. package/src/__tests__/gpu-scene-render-graph-gpu.ts +19 -5
  424. package/src/__tests__/gpu-scene.dawn.test.ts +40 -13
  425. package/src/__tests__/gpu-scene.unit.test.ts +613 -33
  426. package/src/__tests__/instances-culling.integration.test.ts +36 -10
  427. package/src/__tests__/instances-derived-bounds.unit.test.ts +54 -0
  428. package/src/__tests__/instances-store.unit.test.ts +242 -39
  429. package/src/__tests__/ktx2-basis-gpu-consumer.dawn.test.ts +6 -0
  430. package/src/__tests__/lighting-scene-roundtrip.integration.test.ts +13 -16
  431. package/src/__tests__/lut-lkg-transaction.integration.test.ts +122 -0
  432. package/src/__tests__/material-contract-inventory.unit.test.ts +5 -6
  433. package/src/__tests__/material-dispatch-shader-id.unit.test.ts +51 -0
  434. package/src/__tests__/material-lane-selection.unit.test.ts +60 -0
  435. package/src/__tests__/material-numeric-upload.unit.test.ts +53 -0
  436. package/src/__tests__/material-texture-handles.unit.test.ts +18 -0
  437. package/src/__tests__/material-texture-source.unit.test.ts +87 -0
  438. package/src/__tests__/materials-authoring-validation.unit.test.ts +41 -0
  439. package/src/__tests__/materials-standard-contract.unit.test.ts +57 -3
  440. package/src/__tests__/mesh-buffer-usage-surface.unit.test.ts +4 -0
  441. package/src/__tests__/mesh-submission-lifetime.unit.test.ts +8 -0
  442. package/src/__tests__/morph-neutral-admission.unit.test.ts +19 -0
  443. package/src/__tests__/normal-fallback.dawn.test.ts +122 -0
  444. package/src/__tests__/particle-material-input-layout.unit.test.ts +104 -0
  445. package/src/__tests__/physical-clearcoat.integration.test.ts +42 -3
  446. package/src/__tests__/pipeline-texture-specialization.unit.test.ts +138 -0
  447. package/src/__tests__/point-shadow-inspection.unit.test.ts +2 -0
  448. package/src/__tests__/post-process-error-policy-owner.unit.test.ts +6 -5
  449. package/src/__tests__/prepared-gpu-driven-pbr-contract.test-d.ts +31 -0
  450. package/src/__tests__/prepared-gpu-driven-pbr-contract.unit.test.ts +39 -0
  451. package/src/__tests__/prepared-gpu-driven-pbr.integration.test.ts +251 -9
  452. package/src/__tests__/prepared-graphics-capability.unit.test.ts +21 -0
  453. package/src/__tests__/prepared-graphics-pipeline-warmup.unit.test.ts +6 -2
  454. package/src/__tests__/profiler-phase-catalog.test.ts +5 -0
  455. package/src/__tests__/public-surface.test-d.ts +3 -0
  456. package/src/__tests__/recovery-candidate-prepare.contract.test.ts +30 -12
  457. package/src/__tests__/reflection-fallback-async-publication.unit.test.ts +171 -0
  458. package/src/__tests__/reflection-probe-authoring.unit.test.ts +12 -10
  459. package/src/__tests__/reflection-probe-box.dawn.test.ts +71 -0
  460. package/src/__tests__/reflection-probe-filter.unit.test.ts +9 -0
  461. package/src/__tests__/reflection-probe-orientation.dawn.test.ts +294 -0
  462. package/src/__tests__/reflection-probe-record-owner.characterization.unit.test.ts +5 -14
  463. package/src/__tests__/reflection-probe-updates.unit.test.ts +129 -0
  464. package/src/__tests__/render-error-code-owner.test-d.ts +7 -0
  465. package/src/__tests__/render-error-detail-ssot.test-d.ts +27 -1
  466. package/src/__tests__/render-error-exhaustive.test-d.ts +15 -0
  467. package/src/__tests__/render-extent.unit.test.ts +63 -0
  468. package/src/__tests__/render-feature-gpu-work.integration.test.ts +285 -2
  469. package/src/__tests__/render-feature-plan.unit.test.ts +245 -0
  470. package/src/__tests__/render-feature-shadow-order.unit.test.ts +228 -0
  471. package/src/__tests__/render-feature-zero-work.unit.test.ts +35 -1
  472. package/src/__tests__/render-graph-fallback.integration.test.ts +2 -2
  473. package/src/__tests__/render-owner-cohesion.unit.test.ts +55 -0
  474. package/src/__tests__/render-scene-mixed-updates.integration.test.ts +426 -0
  475. package/src/__tests__/render-scene-projection.unit.test.ts +915 -23
  476. package/src/__tests__/render-scene-resource-updates.integration.test.ts +214 -0
  477. package/src/__tests__/render-scene-skin-lifecycle.integration.test.ts +173 -0
  478. package/src/__tests__/render-scene-temporal-retry.unit.test.ts +133 -0
  479. package/src/__tests__/render-target-material-source.test-d.ts +27 -3
  480. package/src/__tests__/renderer-factory-material-contract.unit.test.ts +233 -9
  481. package/src/__tests__/renderer-frame-transaction.integration.test.ts +923 -5
  482. package/src/__tests__/shader-manifest-fixture.ts +45 -0
  483. package/src/__tests__/skin-motion-regression.unit.test.ts +0 -33
  484. package/src/__tests__/skin-palette-persistent.integration.test.ts +28 -0
  485. package/src/__tests__/skin-palette-persistent.unit.test.ts +247 -0
  486. package/src/__tests__/skinned-shadow-caster.test.ts +125 -14
  487. package/src/__tests__/specular-environment-scale.dawn.test.ts +158 -0
  488. package/src/__tests__/ssao-config.unit.test.ts +7 -0
  489. package/src/__tests__/ssao-surface.dawn.test.ts +252 -0
  490. package/src/__tests__/ssr-admission-matrix.integration.test.ts +7 -1
  491. package/src/__tests__/ssr-confidence-compose.unit.test.ts +84 -0
  492. package/src/__tests__/ssr-coordinate-oracle.unit.test.ts +28 -0
  493. package/src/__tests__/ssr-cube-silhouette.dawn.test.ts +270 -0
  494. package/src/__tests__/ssr-format-probe-gating.integration.test.ts +82 -0
  495. package/src/__tests__/ssr-gpu-dispatch.browser.test.ts +99 -0
  496. package/src/__tests__/ssr-gpu-dispatch.dawn.test.ts +116 -0
  497. package/src/__tests__/ssr-gpu-dispatch.ts +951 -0
  498. package/src/__tests__/ssr-graph-topology.unit.test.ts +104 -0
  499. package/src/__tests__/ssr-history-filter.dawn.test.ts +198 -0
  500. package/src/__tests__/ssr-hit-color.dawn.test.ts +273 -0
  501. package/src/__tests__/ssr-hiz-odd-reduction.dawn.test.ts +569 -0
  502. package/src/__tests__/ssr-hiz-rescue.dawn.test.ts +279 -0
  503. package/src/__tests__/ssr-hiz.browser.test.ts +150 -0
  504. package/src/__tests__/ssr-hiz.dawn.test.ts +150 -0
  505. package/src/__tests__/ssr-hiz.unit.test.ts +56 -0
  506. package/src/__tests__/ssr-inspection.unit.test.ts +105 -0
  507. package/src/__tests__/ssr-memory-budget.unit.test.ts +45 -0
  508. package/src/__tests__/ssr-performance-sequence-aggregation.unit.test.ts +15 -0
  509. package/src/__tests__/ssr-public-surface.test-d.ts +37 -0
  510. package/src/__tests__/ssr-receiver-coverage.dawn.test.ts +387 -0
  511. package/src/__tests__/ssr-reflection-mip-reducer.dawn.test.ts +309 -0
  512. package/src/__tests__/ssr-reprojection-probe.ts +90 -0
  513. package/src/__tests__/ssr-roughness-mip.dawn.test.ts +163 -0
  514. package/src/__tests__/ssr-shader-prewarm.unit.test.ts +59 -0
  515. package/src/__tests__/ssr-spatial.integration.test.ts +141 -0
  516. package/src/__tests__/ssr-stable-lattice.dawn.test.ts +475 -0
  517. package/src/__tests__/ssr-temporal-history.unit.test.ts +202 -0
  518. package/src/__tests__/ssr-texel-crossing.dawn.test.ts +448 -0
  519. package/src/__tests__/ssr-zero-work.integration.test.ts +87 -0
  520. package/src/__tests__/standard-cluster-variant-resolution.unit.test.ts +84 -12
  521. package/src/__tests__/standard-clustered-pipeline.unit.test.ts +29 -0
  522. package/src/__tests__/standard-output-chain-contract.unit.test.ts +99 -0
  523. package/src/__tests__/standard-output-chain.integration.test.ts +73 -0
  524. package/src/__tests__/standard-output-gpu-evidence.ts +205 -0
  525. package/src/__tests__/standard-output.browser.test.ts +15 -0
  526. package/src/__tests__/standard-output.dawn.test.ts +15 -0
  527. package/src/__tests__/standard-pbr-artifact-assembly.unit.test.ts +275 -0
  528. package/src/__tests__/standard-pipeline.integration.test.ts +320 -3
  529. package/src/__tests__/standard-profile-oracle.unit.test.ts +49 -0
  530. package/src/__tests__/standard-surface-lighting.unit.test.ts +41 -0
  531. package/src/__tests__/standard-texture-specialization.dawn.test.ts +141 -0
  532. package/src/__tests__/surface-adjacent-regressions.integration.test.ts +6 -3
  533. package/src/__tests__/taa-coverage-edge.dawn.test.ts +199 -0
  534. package/src/__tests__/taa-history-clipping.dawn.test.ts +328 -0
  535. package/src/__tests__/taa-neighborhood-equivalence.dawn.test.ts +782 -0
  536. package/src/__tests__/taa-stability-feedback.browser.test.ts +23 -0
  537. package/src/__tests__/taa-stability-feedback.dawn.test.ts +68 -0
  538. package/src/__tests__/taa-stability-feedback.ts +342 -0
  539. package/src/__tests__/temporal-history-lifecycle.unit.test.ts +49 -7
  540. package/src/__tests__/temporal-reset-matrix.unit.test.ts +9 -0
  541. package/src/__tests__/temporal-transaction.integration.test.ts +28 -0
  542. package/src/__tests__/temporal-view.unit.test.ts +17 -0
  543. package/src/__tests__/texture-usage-surface.unit.test.ts +4 -2
  544. package/src/__tests__/transmission-prewarm.unit.test.ts +57 -0
  545. package/src/__tests__/typed-pipeline-topology.unit.test.ts +109 -4
  546. package/src/__tests__/typed-scene-pass-material-cache.integration.test.ts +126 -0
  547. package/src/__tests__/vertex-layouts-ssot.unit.test.ts +47 -0
  548. package/src/__tests__/visibility-extract.perf.test.ts +20 -8
  549. package/src/__tests__/visibility-instances.integration.test.ts +19 -7
  550. package/src/__tests__/visibility-producer-matrix.integration.test.ts +20 -9
  551. package/src/__tests__/volumetric-fog-stage-readback.dawn.test.ts +62 -13
  552. package/src/__tests__/volumetric-fog-topology.unit.test.ts +7 -7
  553. package/src/assembly/atmosphere-shader-prewarm.ts +39 -0
  554. package/src/assembly/device-feature-admission.ts +9 -4
  555. package/src/assembly/dynamic-geometry-host.ts +284 -163
  556. package/src/assembly/dynamic-geometry-runtime.ts +71 -0
  557. package/src/assembly/factory.ts +4 -0
  558. package/src/assembly/gpu-driven-owner.ts +29 -0
  559. package/src/assembly/host-contract.ts +19 -0
  560. package/src/assembly/material/assembly.ts +383 -1
  561. package/src/assembly/material/pipeline-helpers.ts +100 -0
  562. package/src/assembly/material-shader-policy.ts +110 -46
  563. package/src/assembly/recovery/device-loss-fanout.ts +5 -0
  564. package/src/assembly/recovery/failure-location.ts +62 -0
  565. package/src/assembly/recovery/recovery-attempt.ts +2 -29
  566. package/src/assembly/recovery/renderer-recover.ts +16 -17
  567. package/src/assembly/renderer-facade.ts +34 -1
  568. package/src/assembly/renderer-feature-inspection.ts +13 -0
  569. package/src/assembly/renderer-frame-transaction.ts +63 -0
  570. package/src/assembly/renderer-helpers.ts +26 -0
  571. package/src/assembly/renderer-inspection.ts +6 -0
  572. package/src/assembly/shader-prewarm-policy.ts +46 -1
  573. package/src/assembly/skin-palette-owner.ts +21 -0
  574. package/src/assembly/ssr-shader-prewarm.ts +41 -0
  575. package/src/assembly/webgpu-device-loss.ts +75 -0
  576. package/src/assembly/webgpu-pbr-ready.ts +232 -0
  577. package/src/assembly/webgpu-ready-mipmap.ts +26 -0
  578. package/src/assembly/webgpu-ready.ts +161 -131
  579. package/src/assembly/webgpu-renderer-bootstrap.ts +85 -0
  580. package/src/assembly/webgpu-renderer-contract.ts +69 -0
  581. package/src/assembly/webgpu-renderer-guards.ts +32 -0
  582. package/src/assembly/webgpu-renderer-observation.ts +43 -0
  583. package/src/assembly/webgpu-renderer-recovery-failure.ts +62 -0
  584. package/src/assembly/webgpu-renderer.ts +744 -730
  585. package/src/assembly/webgpu-vertex-layouts.ts +233 -87
  586. package/src/capture/scene-projection.ts +37 -0
  587. package/src/components/__tests__/camera-exposure.contract.unit.test.ts +153 -0
  588. package/src/components/__tests__/dynamic-resolution-schema.unit.test.ts +65 -0
  589. package/src/components/__tests__/light-radius.integration.test.ts +59 -0
  590. package/src/components/camera.ts +287 -7
  591. package/src/components/directional-light.ts +3 -3
  592. package/src/components/dynamic-resolution.ts +67 -0
  593. package/src/components/index.ts +2 -0
  594. package/src/components/instances.ts +45 -18
  595. package/src/components/light-helpers.ts +6 -1
  596. package/src/components/reflection-probe.ts +1 -0
  597. package/src/components/scene-instance.ts +2 -1
  598. package/src/components/screen-space-reflection.ts +21 -0
  599. package/src/components/skylight.ts +4 -1
  600. package/src/components/sprite-animation.ts +2 -2
  601. package/src/components/sprite-instances.ts +1 -1
  602. package/src/device/device-scope.ts +13 -7
  603. package/src/device/gpu-residency.ts +45 -42
  604. package/src/dynamic-geometry.ts +13 -8
  605. package/src/environment/background.ts +281 -0
  606. package/src/environment/ibl.ts +211 -0
  607. package/src/environment/storage.ts +63 -0
  608. package/src/errors/gpu-driven.ts +49 -8
  609. package/src/errors/render.ts +91 -3
  610. package/src/extract/camera.ts +37 -1
  611. package/src/extract/contracts.ts +10 -0
  612. package/src/extract/gpu-driven.ts +240 -10
  613. package/src/features/host.ts +237 -19
  614. package/src/features/noise-texture.ts +91 -0
  615. package/src/features/plan.ts +553 -24
  616. package/src/features/prepared-gpu-work.ts +631 -49
  617. package/src/features/prepared-graphics-store.ts +31 -0
  618. package/src/features/prepared-graphics.ts +5 -0
  619. package/src/features/render-graph-compute.ts +41 -8
  620. package/src/features/render-graph-contribution.ts +141 -3
  621. package/src/features/render-graph-raster.ts +143 -30
  622. package/src/features/types.ts +11 -0
  623. package/src/fullscreen-post-process-pass.ts +3 -0
  624. package/src/gpu-driven/batch-topology.ts +452 -108
  625. package/src/gpu-driven/material-artifacts.ts +179 -0
  626. package/src/gpu-driven/material-bindings.ts +41 -0
  627. package/src/gpu-driven/pbr-program.ts +31 -0
  628. package/src/gpu-driven/prepared-draw.ts +42 -6
  629. package/src/gpu-driven/production-raster.ts +2806 -716
  630. package/src/gpu-driven/shadow-views.ts +539 -0
  631. package/src/gpu-driven/view-gpu.ts +188 -41
  632. package/src/gpu-resource.ts +21 -2
  633. package/src/gpu-scene-schema.ts +61 -11
  634. package/src/gpu-scene.ts +197 -99
  635. package/src/gpu-texture-usage.ts +1 -0
  636. package/src/hdrp-buffers.ts +141 -36
  637. package/src/ibl/IblPipelineCache.ts +5 -0
  638. package/src/ibl/frame-resources.ts +38 -0
  639. package/src/ibl/skylight-bind-group.ts +32 -21
  640. package/src/index.ts +194 -75
  641. package/src/inspection-types.ts +207 -1
  642. package/src/instances-derived-bounds.ts +258 -34
  643. package/src/instances.ts +459 -150
  644. package/src/internal.ts +22 -0
  645. package/src/lifecycle.ts +2 -0
  646. package/src/material-row.ts +194 -0
  647. package/src/materials.ts +44 -8
  648. package/src/pbr-pipeline.ts +172 -19
  649. package/src/pipeline/render-extent.ts +111 -0
  650. package/src/pipeline/standard-build-context.ts +7 -0
  651. package/src/pipeline/standard-forward-lane.ts +74 -29
  652. package/src/pipeline/standard-output/__tests__/lut-admission.unit.test.ts +103 -0
  653. package/src/pipeline/standard-output/auto-exposure/__tests__/capability.unit.test.ts +40 -0
  654. package/src/pipeline/standard-output/auto-exposure/__tests__/gpu.contract.unit.test.ts +125 -0
  655. package/src/pipeline/standard-output/auto-exposure/__tests__/graph.contract.unit.test.ts +94 -0
  656. package/src/pipeline/standard-output/auto-exposure/__tests__/oracle.test.ts +108 -0
  657. package/src/pipeline/standard-output/auto-exposure/__tests__/preset.test.ts +26 -0
  658. package/src/pipeline/standard-output/auto-exposure/capability.ts +38 -0
  659. package/src/pipeline/standard-output/auto-exposure/gpu.ts +567 -0
  660. package/src/pipeline/standard-output/auto-exposure/graph.ts +221 -0
  661. package/src/pipeline/standard-output/auto-exposure/inspection.ts +231 -0
  662. package/src/pipeline/standard-output/auto-exposure/oracle.ts +291 -0
  663. package/src/pipeline/standard-output/auto-exposure/preset.ts +28 -0
  664. package/src/pipeline/standard-output/auto-exposure/state.ts +156 -0
  665. package/src/pipeline/standard-output/color-transform.ts +124 -0
  666. package/src/pipeline/standard-output/graph.ts +139 -0
  667. package/src/pipeline/standard-output/lut-admission.ts +121 -0
  668. package/src/pipeline/standard-output/lut-gpu.ts +399 -0
  669. package/src/pipeline/standard-output/lut-state.ts +176 -0
  670. package/src/pipeline/standard-output/resources.ts +121 -0
  671. package/src/pipeline/standard-output/types.ts +58 -0
  672. package/src/pipeline/standard-pipeline.ts +232 -70
  673. package/src/pipeline/standard-post.ts +190 -27
  674. package/src/pipeline/standard-profile.ts +2 -1
  675. package/src/pipeline-builder.ts +28 -9
  676. package/src/pipeline-spec-types.ts +4 -0
  677. package/src/pipeline-spec.ts +37 -29
  678. package/src/plugin.ts +4 -0
  679. package/src/points-lines/standard-owner.ts +6 -14
  680. package/src/post-process-errors.ts +26 -18
  681. package/src/prepare/__tests__/extended-lighting-capability.unit.test.ts +2 -2
  682. package/src/prepare/extended-lighting/resources.ts +3 -3
  683. package/src/prepare/prepared-graphics-resolver.ts +9 -2
  684. package/src/record/__tests__/main-pass-geometry.unit.test.ts +68 -0
  685. package/src/record/__tests__/material-bg-cache.unit.test.ts +45 -0
  686. package/src/record/__tests__/material-slot-plan.unit.test.ts +57 -0
  687. package/src/record/__tests__/mesh-ssbo.unit.test.ts +40 -1
  688. package/src/record/__tests__/recovery-pipeline.unit.test.ts +20 -1
  689. package/src/record/__tests__/sprite-material-abi.unit.test.ts +41 -6
  690. package/src/record/__tests__/temporal-payload.unit.test.ts +2 -0
  691. package/src/record/__tests__/typed-frame-graph-plan.unit.test.ts +45 -0
  692. package/src/record/__tests__/view-ubo-layout.unit.test.ts +5 -0
  693. package/src/record/dynamic-geometry-consumption.ts +59 -0
  694. package/src/record/frame-lighting.ts +15 -12
  695. package/src/record/frame-snapshot.ts +146 -34
  696. package/src/record/frame-targets.ts +9 -0
  697. package/src/record/frame.ts +838 -170
  698. package/src/record/main-pass-geometry.ts +209 -103
  699. package/src/record/main-pass-material.ts +157 -40
  700. package/src/record/main-pass-sprite-draws.ts +16 -107
  701. package/src/record/main-pass.ts +141 -12
  702. package/src/record/material-uniforms.ts +1 -1
  703. package/src/record/mesh-ssbo.ts +59 -15
  704. package/src/record/prepared-material-bindings.ts +238 -0
  705. package/src/record/recovery-pipeline.ts +69 -90
  706. package/src/record/render-context.ts +123 -24
  707. package/src/record/shadow-pass.ts +1389 -230
  708. package/src/record/skybox-post-pass.ts +14 -3
  709. package/src/record/typed-frame-graph.ts +1064 -47
  710. package/src/record/view-ubo.ts +12 -1
  711. package/src/recovery/render-system-candidate.ts +135 -68
  712. package/src/recovery/render-system-roots.ts +113 -0
  713. package/src/recovery/types.ts +77 -0
  714. package/src/reflection/background.ts +151 -0
  715. package/src/reflection/filter.ts +3 -0
  716. package/src/reflection/projection.ts +16 -6
  717. package/src/reflection/record-owner.ts +308 -140
  718. package/src/render-contract.ts +237 -49
  719. package/src/render-graph-primitives.ts +34 -5
  720. package/src/render-pipeline.ts +90 -2
  721. package/src/render-system-extract-tail.ts +431 -162
  722. package/src/render-system-extract.ts +478 -119
  723. package/src/render-system-projections.ts +241 -0
  724. package/src/render-system.ts +715 -828
  725. package/src/scene/render-scene-types.ts +13 -4
  726. package/src/scene/render-scene.ts +577 -355
  727. package/src/scene/shadow-visibility.ts +21 -0
  728. package/src/ssao-config.ts +25 -8
  729. package/src/ssr/admission.ts +380 -14
  730. package/src/ssr/compose.ts +144 -0
  731. package/src/ssr/errors.ts +48 -0
  732. package/src/ssr/graph.ts +797 -0
  733. package/src/ssr/history.ts +436 -0
  734. package/src/ssr/hiz.ts +124 -0
  735. package/src/ssr/inspection.ts +124 -0
  736. package/src/ssr/resources.ts +202 -0
  737. package/src/ssr/temporal.ts +164 -0
  738. package/src/systems/skin-palette-allocator.ts +495 -148
  739. package/src/systems/skin-palette-types.ts +17 -0
  740. package/src/systems/transparent-dispatch.ts +90 -0
  741. package/src/targets/material-source.ts +34 -0
  742. package/src/temporal/coverage.ts +1 -1
  743. package/src/temporal/frame-coordinator.ts +23 -2
  744. package/src/temporal/gpu.ts +79 -12
  745. package/src/temporal/history.ts +3 -1
  746. package/src/temporal/inspection.ts +2 -1
  747. package/src/temporal/standard-scene-data.ts +10 -2
  748. package/src/temporal/target-coverage-attachment.ts +72 -0
  749. package/src/temporal/temporal-view.ts +11 -2
  750. package/src/temporal/view.ts +12 -2
  751. package/src/transmission/__tests__/standard-transmission.dawn.test.ts +219 -139
  752. package/src/typed-render-graph-primitives.ts +304 -74
  753. package/src/typed-shadow-passes.ts +122 -12
  754. package/src/volume/component.ts +1 -0
  755. package/src/volume/passes.ts +3 -3
  756. package/src/volume/temporal.ts +10 -0
  757. package/dist/chunk-GE3SDD72.mjs.map +0 -1
  758. package/dist/chunk-GF523LHF.mjs.map +0 -1
  759. package/dist/chunk-IQMKJLNU.mjs.map +0 -1
  760. package/dist/chunk-J52NMQKR.mjs.map +0 -1
  761. package/dist/chunk-J6KACNOH.mjs.map +0 -1
  762. package/dist/chunk-JAASCMXA.mjs.map +0 -1
  763. package/dist/chunk-MBU4ZVE7.mjs.map +0 -1
  764. package/dist/chunk-MYJ5RPJO.mjs.map +0 -1
  765. package/dist/chunk-RBDBZ5R7.mjs.map +0 -1
  766. package/dist/chunk-VSL23LZE.mjs.map +0 -1
  767. package/src/__tests__/instances-world-ownership.integration.test.ts +0 -62
  768. package/src/scene/__tests__/changed-block-summary.candidate.test.ts +0 -36
@@ -25,10 +25,19 @@ import { executeRendererFrameTransaction } from '../assembly/renderer-frame-tran
25
25
  import { type RenderError, RenderFeatureStageFailedError } from '../errors/render';
26
26
  import {
27
27
  getRenderFeaturePlanExecutionProjection,
28
+ hasSubmissionSensitiveFeatures,
28
29
  type RenderFeaturePlanExecution,
29
30
  } from '../features/host';
30
- import { type RenderFeaturePlannedFrame, renderFeaturePlanSignature } from '../features/plan';
31
- import { projectRenderFeaturePlans as projectPlanExecutions } from '../features/render-graph-contribution';
31
+ import {
32
+ type RenderFeaturePlannedFrame,
33
+ renderFeaturePlanSignature,
34
+ renderFeaturePlanSignatureEvidenceMatches,
35
+ } from '../features/plan';
36
+ import {
37
+ createRenderFeatureProjectionState,
38
+ projectRenderFeaturePlans as projectPlanExecutions,
39
+ projectRenderFeatureShadows,
40
+ } from '../features/render-graph-contribution';
32
41
  import type {
33
42
  RenderFeatureGraphBindingsResolution,
34
43
  RenderFeatureGraphTargetResolver,
@@ -46,13 +55,29 @@ import {
46
55
  GPU_TEXTURE_USAGE_COPY_DST,
47
56
  GPU_TEXTURE_USAGE_COPY_SRC,
48
57
  GPU_TEXTURE_USAGE_RENDER_ATTACHMENT,
58
+ GPU_TEXTURE_USAGE_STORAGE_BINDING,
49
59
  GPU_TEXTURE_USAGE_TEXTURE_BINDING,
50
60
  } from '../gpu-texture-usage';
61
+ import { GPU_BUFFER_USAGE_COPY_DST, GPU_BUFFER_USAGE_UNIFORM } from '../gpu-usage';
62
+ import { createStandardSurfaceLightingBindGroup } from '../hdrp-buffers';
63
+ import type { RenderFeatureGraphInspection } from '../inspection-types';
64
+ import type { RenderExtent } from '../pipeline/render-extent';
51
65
  import {
52
66
  type StandardTopologyInputValue,
53
67
  standardLightingTopologySignature,
54
68
  } from '../pipeline/standard-lighting/topology';
69
+ import {
70
+ importAutoExposureGraphResources,
71
+ retireAutoExposureGpuResources,
72
+ } from '../pipeline/standard-output/auto-exposure/gpu';
73
+ import { commitAutoExposureSubmission } from '../pipeline/standard-output/auto-exposure/state';
74
+ import { retireStandardLutGpuResources } from '../pipeline/standard-output/lut-gpu';
75
+ import {
76
+ commitStandardLutCandidate,
77
+ resetStandardLutState,
78
+ } from '../pipeline/standard-output/lut-state';
55
79
  import { resolveVolumetricFogProfile, STANDARD_PIPELINE_ID } from '../pipeline/standard-profile';
80
+ import { type ProbeBackgroundResources, recordProbeBackground } from '../reflection/background';
56
81
  import type { CameraSnapshot } from '../render-contract';
57
82
  import type {
58
83
  RenderPipelineFeatureTarget,
@@ -61,7 +86,7 @@ import type {
61
86
  } from '../render-pipeline';
62
87
  import type { ExtractedLights, ExtractedVolumetricFog } from '../render-system-extract';
63
88
  import { SHADOW_ATLAS_DEFAULT_FACE_SIZE, SHADOW_ATLAS_DEFAULT_LAYERS } from '../shadow-atlas';
64
- import type { SsrAdmissionResult } from '../ssr/admission';
89
+ import type { SsrAdmissionResult, SsrSpatialAdmission } from '../ssr/admission';
65
90
  import type { RenderTarget } from '../targets/contracts';
66
91
  import type { RenderTargetPhysical } from '../targets/physical';
67
92
  import {
@@ -71,15 +96,22 @@ import {
71
96
  hasPendingTemporalGpuSubmit,
72
97
  retireTemporalGpuState,
73
98
  retireTemporalGpuStateAfterFence,
99
+ TEMPORAL_HISTORY_FORMATS,
74
100
  temporalReadIndex,
75
101
  temporalWriteIndex,
76
102
  } from '../temporal/gpu';
77
103
  import { isSceneDataTarget } from '../temporal/scene-data';
104
+ import { createTargetCoverageAttachment } from '../temporal/target-coverage-attachment';
78
105
  import type { TransmissionDemand } from '../transmission/projection';
79
106
  import { hasVolumetricFogCapability } from '../volume/capability';
80
107
  import { deriveVolumetricFogExtent, deriveVolumetricFogResolvedExtent } from '../volume/resources';
81
108
  import { buildPerFrameBindGroups } from './frame-lighting';
82
- import { getTextureIdentity, type RenderFrameState } from './frame-snapshot';
109
+ import {
110
+ type GraphTargetPassReplayPrefixReceipt,
111
+ type GraphTargetPassReplayReceipt,
112
+ getTextureIdentity,
113
+ type RenderFrameState,
114
+ } from './frame-snapshot';
83
115
  import type { GpuPassTimingPassIdentity } from './gpu-pass-timing/contract.js';
84
116
  import type { GpuPassTimingCapture, GpuPassTimingSession } from './gpu-pass-timing/session.js';
85
117
  import type { GpuTimingCapture } from './gpu-timing';
@@ -198,13 +230,14 @@ export function commitReflectionFallbackGraph(
198
230
  function importTemporalHistoryTarget(
199
231
  graph: RenderGraphBuilder<RenderPipelineFrame>,
200
232
  label: string,
201
- kind: 'color' | 'temporal',
233
+ kind: 'color' | 'temporal' | 'stability',
202
234
  role: 'read' | 'write',
203
235
  ): import('../render-pipeline').RenderPipelineTarget {
236
+ const format = TEMPORAL_HISTORY_FORMATS[kind];
204
237
  const texture = graph.importTexture(
205
238
  label,
206
239
  {
207
- format: 'rgba16float',
240
+ format,
208
241
  size: 'surface',
209
242
  usage:
210
243
  GPU_TEXTURE_USAGE_COPY_SRC |
@@ -222,7 +255,7 @@ function importTemporalHistoryTarget(
222
255
  frame.targetH,
223
256
  );
224
257
  const index = role === 'read' ? temporalReadIndex(state) : temporalWriteIndex(state);
225
- return (kind === 'color' ? state.color[index] : state.temporal[index]).texture;
258
+ return state[kind][index].texture;
226
259
  },
227
260
  );
228
261
  if (!texture.ok) throw texture.error;
@@ -239,11 +272,11 @@ function importTemporalHistoryTarget(
239
272
  frame.targetH,
240
273
  );
241
274
  const index = role === 'read' ? temporalReadIndex(state) : temporalWriteIndex(state);
242
- return (kind === 'color' ? state.color[index] : state.temporal[index]).view;
275
+ return state[kind][index].view;
243
276
  },
244
277
  );
245
278
  if (!view.ok) throw view.error;
246
- return { texture: texture.value, view: view.value, format: 'rgba16float', sampleCount: 1 };
279
+ return { texture: texture.value, view: view.value, format, sampleCount: 1 };
247
280
  }
248
281
 
249
282
  function importTemporalHistoryTargets(
@@ -253,6 +286,18 @@ function importTemporalHistoryTargets(
253
286
  > {
254
287
  return {
255
288
  currentColor: importTemporalHistoryTarget(graph, 'taa-history-current-color', 'color', 'write'),
289
+ currentStability: importTemporalHistoryTarget(
290
+ graph,
291
+ 'taa-history-current-stability',
292
+ 'stability',
293
+ 'write',
294
+ ),
295
+ previousStability: importTemporalHistoryTarget(
296
+ graph,
297
+ 'taa-history-previous-stability',
298
+ 'stability',
299
+ 'read',
300
+ ),
256
301
  previousColor: importTemporalHistoryTarget(
257
302
  graph,
258
303
  'taa-history-previous-color',
@@ -274,6 +319,110 @@ function importTemporalHistoryTargets(
274
319
  };
275
320
  }
276
321
 
322
+ function importSsrHistoryTarget(
323
+ graph: RenderGraphBuilder<RenderPipelineFrame>,
324
+ label: string,
325
+ role: 'read' | 'write',
326
+ surface = false,
327
+ ): import('../render-pipeline').RenderPipelineTarget {
328
+ const texture = graph.importTexture(
329
+ label,
330
+ {
331
+ format: surface ? 'rgba8unorm' : 'rgba16float',
332
+ size: 'half-surface',
333
+ usage:
334
+ GPU_TEXTURE_USAGE_COPY_SRC |
335
+ GPU_TEXTURE_USAGE_COPY_DST |
336
+ GPU_TEXTURE_USAGE_RENDER_ATTACHMENT |
337
+ GPU_TEXTURE_USAGE_STORAGE_BINDING |
338
+ GPU_TEXTURE_USAGE_TEXTURE_BINDING,
339
+ domain: 'linear-hdr',
340
+ },
341
+ (frame) => {
342
+ const internal = frame as import('./render-context')._InternalRenderPipelineContext;
343
+ const owner = internal.frameState.ssrHistoryOwner;
344
+ const candidate = internal.frameState.ssrHistoryCandidate;
345
+ if (owner === undefined || candidate === undefined) {
346
+ throw new RhiError({
347
+ code: 'rhi-not-available',
348
+ expected: 'SSR history candidate to be staged before graph execution',
349
+ hint: 'begin the SSR history candidate before executing the admitted graph',
350
+ });
351
+ }
352
+ const slot =
353
+ role === 'read'
354
+ ? (candidate.readSlot ?? (candidate.writeSlot === 0 ? 1 : 0))
355
+ : candidate.writeSlot;
356
+ return surface
357
+ ? owner.resources.slots[slot].surfaceTexture
358
+ : owner.resources.slots[slot].texture;
359
+ },
360
+ );
361
+ if (!texture.ok) throw texture.error;
362
+ const view = graph.importView(
363
+ texture.value,
364
+ { label: `${label}.view`, dimension: '2d' },
365
+ (frame) => {
366
+ const internal = frame as import('./render-context')._InternalRenderPipelineContext;
367
+ const owner = internal.frameState.ssrHistoryOwner;
368
+ const candidate = internal.frameState.ssrHistoryCandidate;
369
+ if (owner === undefined || candidate === undefined) {
370
+ throw new RhiError({
371
+ code: 'rhi-not-available',
372
+ expected: 'SSR history candidate to be staged before graph execution',
373
+ hint: 'begin the SSR history candidate before executing the admitted graph',
374
+ });
375
+ }
376
+ const slot =
377
+ role === 'read'
378
+ ? (candidate.readSlot ?? (candidate.writeSlot === 0 ? 1 : 0))
379
+ : candidate.writeSlot;
380
+ return surface ? owner.resources.slots[slot].surfaceView : owner.resources.slots[slot].view;
381
+ },
382
+ );
383
+ if (!view.ok) throw view.error;
384
+ return {
385
+ texture: texture.value,
386
+ view: view.value,
387
+ format: surface ? 'rgba8unorm' : 'rgba16float',
388
+ sampleCount: 1,
389
+ domain: 'linear-hdr',
390
+ };
391
+ }
392
+
393
+ function importSsrHistoryTargets(
394
+ graph: RenderGraphBuilder<RenderPipelineFrame>,
395
+ ): NonNullable<
396
+ import('../render-pipeline').RenderPipelineBuildContext<RenderPipelineFrame>['ssrHistory']
397
+ > {
398
+ return {
399
+ previous: importSsrHistoryTarget(graph, 'ssr-history-previous', 'read'),
400
+ output: importSsrHistoryTarget(graph, 'ssr-history-output', 'write'),
401
+ previousSurface: importSsrHistoryTarget(graph, 'ssr-history-previous-surface', 'read', true),
402
+ outputSurface: importSsrHistoryTarget(graph, 'ssr-history-output-surface', 'write', true),
403
+ params: (() => {
404
+ const imported = graph.importBuffer(
405
+ 'ssr-history-params',
406
+ { size: 32, usage: GPU_BUFFER_USAGE_UNIFORM | GPU_BUFFER_USAGE_COPY_DST },
407
+ (frame) => {
408
+ const internal = frame as import('./render-context')._InternalRenderPipelineContext;
409
+ const owner = internal.frameState.ssrHistoryOwner;
410
+ if (owner === undefined) {
411
+ throw new RhiError({
412
+ code: 'rhi-not-available',
413
+ expected: 'SSR history owner to be staged before graph execution',
414
+ hint: 'create the renderer-owned SSR history before executing the admitted graph',
415
+ });
416
+ }
417
+ return owner.resources.paramsBuffer;
418
+ },
419
+ );
420
+ if (!imported.ok) throw imported.error;
421
+ return imported.value;
422
+ })(),
423
+ };
424
+ }
425
+
277
426
  export function shouldUseTemporalFrameTransaction(
278
427
  antialias: CameraSnapshot['antialias'],
279
428
  temporalDemand = false,
@@ -345,6 +494,7 @@ export interface ReflectionProbeFilterGraphState {
345
494
  }
346
495
 
347
496
  export interface ReflectionProbeGraphWork {
497
+ readonly background?: ProbeBackgroundResources;
348
498
  readonly probeIndex: number;
349
499
  readonly rawTexture: Texture;
350
500
  readonly rawCubeView: TextureView;
@@ -538,7 +688,6 @@ function addCubeCaptureGraphPasses(
538
688
  const captureResolveView = captureResolve?.ok ? captureResolve.value : null;
539
689
  const captureContext = {
540
690
  ...internal,
541
- gpuDrivenEntityKeys: new Set<number>(),
542
691
  camera: current().faceCamera,
543
692
  // Cube faces are raw scene captures, not display-camera HDR output.
544
693
  // Select the PSO against the actual target attachment so an LDR
@@ -571,6 +720,7 @@ function addCubeCaptureGraphPasses(
571
720
  export function addReflectionProbeGraphPasses(
572
721
  builder: RenderGraphBuilder<RenderPipelineFrame>,
573
722
  state: ReflectionProbeGraphState,
723
+ environmentCube?: import('../environment/ibl').GraphEnvironment,
574
724
  ): Result<readonly import('@forgeax/engine-render-graph').GraphAccess[], RenderGraphError> {
575
725
  const accesses: import('@forgeax/engine-render-graph').GraphAccess[] = [];
576
726
  for (const work of state.work) {
@@ -656,6 +806,11 @@ export function addReflectionProbeGraphPasses(
656
806
  if (!depth.ok) return depth;
657
807
  const added = builder.addRasterPass(`reflection-probe.${work.probeIndex}.capture.${face}`, {
658
808
  accesses: [
809
+ ...(environmentCube === undefined
810
+ ? []
811
+ : [environmentCube.sky, environmentCube.irradiance, environmentCube.prefilter].map(
812
+ (resource) => ({ resource, usage: 'sampled-read' as const }),
813
+ )),
659
814
  { resource: view.value, usage: 'color-attachment' },
660
815
  { resource: depth.value, usage: 'depth-stencil-write' },
661
816
  ],
@@ -683,9 +838,35 @@ export function addReflectionProbeGraphPasses(
683
838
  if (!captureColor.ok || !captureDepth.ok) return;
684
839
  if (work.faceCamera === undefined || work.viewBindGroupDynamicOffset === undefined)
685
840
  return;
841
+ recordProbeBackground(
842
+ work.background,
843
+ internal,
844
+ work.faceCamera,
845
+ pass,
846
+ environmentCube === undefined
847
+ ? undefined
848
+ : resources.textureView(environmentCube.sky).unwrap(),
849
+ );
850
+ const captureContext = {
851
+ ...internal,
852
+ ...(environmentCube === undefined
853
+ ? {}
854
+ : {
855
+ environmentIbl: {
856
+ irradiance: resources.textureView(environmentCube.irradiance).unwrap(),
857
+ prefilter: resources.textureView(environmentCube.prefilter).unwrap(),
858
+ },
859
+ }),
860
+ };
861
+ delete captureContext.reflectionProbes;
862
+ delete captureContext.hdrpSsaoBlurredView;
863
+ delete captureContext.gpuDrivenDrawKeys;
864
+ delete captureContext.gpuDrivenStandardPbrFrameResources;
686
865
  encodeMainPass(
687
866
  {
688
- ...internal,
867
+ ...captureContext,
868
+ dispatch: internal.captureDispatch ?? internal.dispatch,
869
+ foldDispatchPlan: null,
689
870
  camera: work.faceCamera,
690
871
  viewBindGroupDynamicOffset: work.viewBindGroupDynamicOffset,
691
872
  geometryColorView: captureColor.value,
@@ -787,6 +968,57 @@ export interface RenderFeatureGraphRuntimeState {
787
968
  >;
788
969
  }
789
970
 
971
+ /** The exact fields that define one validated feature-plan collection. */
972
+ export interface RenderFeaturePlanRevisionEntry {
973
+ readonly featureIdentity: string;
974
+ readonly generation: number;
975
+ readonly signature: string;
976
+ readonly order: number;
977
+ }
978
+
979
+ /** Compact graph-owner state for a completely validated feature-plan set. */
980
+ export interface RenderFeaturePlanRevisionState {
981
+ readonly revision: number;
982
+ readonly entries: readonly RenderFeaturePlanRevisionEntry[];
983
+ }
984
+
985
+ /**
986
+ * Advance the plan revision only when the complete canonical plan collection
987
+ * changes. Equality is an exact field comparison; the canonical signatures
988
+ * have already been recomputed by validation before this helper is called.
989
+ */
990
+ export function updateRenderFeaturePlanRevision(
991
+ previous: RenderFeaturePlanRevisionState,
992
+ plans: readonly RenderFeaturePlannedFrame[],
993
+ executions: readonly RenderFeaturePlanExecution[],
994
+ ): RenderFeaturePlanRevisionState {
995
+ if (
996
+ plans.length === previous.entries.length &&
997
+ plans.every((planned, index) => {
998
+ const prior = previous.entries[index];
999
+ return (
1000
+ prior !== undefined &&
1001
+ prior.featureIdentity === planned.featureIdentity &&
1002
+ prior.generation === planned.generation &&
1003
+ prior.signature === planned.signature &&
1004
+ prior.order === (executions[index]?.order ?? -1)
1005
+ );
1006
+ })
1007
+ ) {
1008
+ return previous;
1009
+ }
1010
+ const entries = plans.map((planned, index) => ({
1011
+ featureIdentity: planned.featureIdentity,
1012
+ generation: planned.generation,
1013
+ signature: planned.signature,
1014
+ order: executions[index]?.order ?? -1,
1015
+ }));
1016
+ return {
1017
+ revision: previous.revision + 1,
1018
+ entries: Object.freeze(entries),
1019
+ };
1020
+ }
1021
+
790
1022
  /** A frame-local graph candidate that is committed only after compilation. */
791
1023
  export interface RenderFeatureGraphCandidate {
792
1024
  readonly plans: readonly RenderFeaturePlannedFrame[];
@@ -795,16 +1027,22 @@ export interface RenderFeatureGraphCandidate {
795
1027
  import('../fullscreen-post-process-pass').PostProcessShaderEntry
796
1028
  >;
797
1029
  /**
798
- * Physical prepared resources are imported into the compiled graph. A new
799
- * prepared batch therefore needs a new graph even when the declarative plan
800
- * signature is unchanged; otherwise queue retirement can destroy the buffer
801
- * still referenced by the memoized graph.
1030
+ * Physical transient graphics resources are imported into the compiled
1031
+ * graph. Their lease therefore needs a new graph even when the declarative
1032
+ * plan signature is unchanged; otherwise queue retirement could destroy a
1033
+ * buffer still referenced by the memoized graph. Retired GPU-work leases are
1034
+ * kept in the completion batch but are not imported by this candidate and do
1035
+ * not require a graph revision on their own.
802
1036
  */
803
1037
  readonly preparedResourceKey?: string;
804
1038
  /** Release candidate-owned prepared resources when graph promotion fails. */
805
1039
  readonly onRejected?: () => void;
806
1040
  /** Publish candidate-owned runtime declarations only after graph promotion. */
807
1041
  readonly onAccepted?: () => void;
1042
+ /** Consume producer frame state only after the command buffer is submitted. */
1043
+ readonly onSubmitted?: () => void;
1044
+ /** Discard producer frame state after graph execution/submission aborts. */
1045
+ readonly onAborted?: () => void;
808
1046
  /** Discard candidate-only resources when a base graph is kept as fallback. */
809
1047
  readonly onAbandoned?: () => void;
810
1048
  }
@@ -812,6 +1050,139 @@ export interface RenderFeatureGraphCandidate {
812
1050
  const featureGraphStates = new WeakMap<RenderSystemInternals, RenderFeatureGraphRuntimeState>();
813
1051
  const graphDeviceGenerations = new WeakMap<object, number>();
814
1052
 
1053
+ interface MutableRenderFeatureGraphInspection {
1054
+ planRevisionState: RenderFeaturePlanRevisionState;
1055
+ signatureValidationCalls: number;
1056
+ signatureValidationBytes: number;
1057
+ signatureValidationChars: number;
1058
+ signatureValidationCpuMs: number;
1059
+ signatureValidationCacheHits: number;
1060
+ signatureValidationCacheMisses: number;
1061
+ ensureCalls: number;
1062
+ reuseHits: number;
1063
+ rebuildAttempts: number;
1064
+ compileAttempts: number;
1065
+ compileSuccesses: number;
1066
+ compileFailures: number;
1067
+ validationFailures: number;
1068
+ buildFailures: number;
1069
+ compileCpuMs: number;
1070
+ candidatesWithPreparedBatches: number;
1071
+ preparedKeyChanges: number;
1072
+ accepted: number;
1073
+ rejected: number;
1074
+ abandoned: number;
1075
+ lastPlanSignature: string;
1076
+ lastTopologyKey: string | undefined;
1077
+ lastPreparedResourceKey: string | undefined;
1078
+ preparedKeyObserved: boolean;
1079
+ }
1080
+
1081
+ const featureGraphInspections = new WeakMap<
1082
+ RenderSystemInternals,
1083
+ MutableRenderFeatureGraphInspection
1084
+ >();
1085
+
1086
+ function mutableFeatureGraphInspection(
1087
+ internals: RenderSystemInternals,
1088
+ ): MutableRenderFeatureGraphInspection {
1089
+ const existing = featureGraphInspections.get(internals);
1090
+ if (existing !== undefined) return existing;
1091
+ const created: MutableRenderFeatureGraphInspection = {
1092
+ planRevisionState: { revision: 0, entries: [] },
1093
+ signatureValidationCalls: 0,
1094
+ signatureValidationBytes: 0,
1095
+ signatureValidationChars: 0,
1096
+ signatureValidationCpuMs: 0,
1097
+ signatureValidationCacheHits: 0,
1098
+ signatureValidationCacheMisses: 0,
1099
+ ensureCalls: 0,
1100
+ reuseHits: 0,
1101
+ rebuildAttempts: 0,
1102
+ compileAttempts: 0,
1103
+ compileSuccesses: 0,
1104
+ compileFailures: 0,
1105
+ validationFailures: 0,
1106
+ buildFailures: 0,
1107
+ compileCpuMs: 0,
1108
+ candidatesWithPreparedBatches: 0,
1109
+ preparedKeyChanges: 0,
1110
+ accepted: 0,
1111
+ rejected: 0,
1112
+ abandoned: 0,
1113
+ lastPlanSignature: '',
1114
+ lastTopologyKey: undefined,
1115
+ lastPreparedResourceKey: undefined,
1116
+ preparedKeyObserved: false,
1117
+ };
1118
+ featureGraphInspections.set(internals, created);
1119
+ return created;
1120
+ }
1121
+
1122
+ export function getRenderFeatureGraphInspection(
1123
+ internals: RenderSystemInternals,
1124
+ ): RenderFeatureGraphInspection {
1125
+ const metrics = mutableFeatureGraphInspection(internals);
1126
+ return Object.freeze({
1127
+ planRevision: metrics.planRevisionState.revision,
1128
+ signatureValidationCalls: metrics.signatureValidationCalls,
1129
+ signatureValidationBytes: metrics.signatureValidationBytes,
1130
+ signatureValidationChars: metrics.signatureValidationChars,
1131
+ signatureValidationCpuMs: metrics.signatureValidationCpuMs,
1132
+ signatureValidationCacheHits: metrics.signatureValidationCacheHits,
1133
+ signatureValidationCacheMisses: metrics.signatureValidationCacheMisses,
1134
+ ensureCalls: metrics.ensureCalls,
1135
+ reuseHits: metrics.reuseHits,
1136
+ rebuildAttempts: metrics.rebuildAttempts,
1137
+ compileAttempts: metrics.compileAttempts,
1138
+ compileSuccesses: metrics.compileSuccesses,
1139
+ compileFailures: metrics.compileFailures,
1140
+ validationFailures: metrics.validationFailures,
1141
+ buildFailures: metrics.buildFailures,
1142
+ compileCpuMs: metrics.compileCpuMs,
1143
+ candidatesWithPreparedBatches: metrics.candidatesWithPreparedBatches,
1144
+ preparedKeyChanges: metrics.preparedKeyChanges,
1145
+ accepted: metrics.accepted,
1146
+ rejected: metrics.rejected,
1147
+ abandoned: metrics.abandoned,
1148
+ last: Object.freeze({
1149
+ planSignature: metrics.lastPlanSignature,
1150
+ topologyKey: metrics.lastTopologyKey,
1151
+ preparedResourceKey: metrics.lastPreparedResourceKey,
1152
+ }),
1153
+ });
1154
+ }
1155
+
1156
+ export function recordRenderFeatureCandidate(
1157
+ internals: RenderSystemInternals,
1158
+ candidate: RenderFeatureGraphCandidate,
1159
+ ): void {
1160
+ const metrics = mutableFeatureGraphInspection(internals);
1161
+ if (
1162
+ metrics.preparedKeyObserved &&
1163
+ metrics.lastPreparedResourceKey !== candidate.preparedResourceKey
1164
+ ) {
1165
+ metrics.preparedKeyChanges += 1;
1166
+ }
1167
+ metrics.preparedKeyObserved = true;
1168
+ metrics.lastPreparedResourceKey = candidate.preparedResourceKey;
1169
+ if (candidate.preparedResourceKey !== undefined) {
1170
+ metrics.candidatesWithPreparedBatches += 1;
1171
+ }
1172
+ }
1173
+
1174
+ function recordRenderFeatureCandidateEvent(
1175
+ internals: RenderSystemInternals,
1176
+ candidate: RenderFeatureGraphCandidate,
1177
+ event: 'accepted' | 'rejected' | 'abandoned',
1178
+ ): void {
1179
+ const metrics = mutableFeatureGraphInspection(internals);
1180
+ metrics[event] += 1;
1181
+ if (event === 'accepted') candidate.onAccepted?.();
1182
+ else if (event === 'rejected') candidate.onRejected?.();
1183
+ else candidate.onAbandoned?.();
1184
+ }
1185
+
815
1186
  interface TimingInstrumentationState {
816
1187
  readonly instrumentation: RenderGraphPassInstrumentation<RenderPipelineFrame>;
817
1188
  setCapture(capture: GpuPassTimingCapture | undefined): void;
@@ -830,6 +1201,11 @@ type CompiledGraphTargetAccess = CompiledRenderGraph<RenderPipelineFrame> & {
830
1201
  readonly getColorTargetTexture: (name: string) => Texture | undefined;
831
1202
  };
832
1203
 
1204
+ type ResolvedDepthPassExecution =
1205
+ import('@forgeax/engine-render-graph').RenderGraphPassExecution & {
1206
+ readonly resolvedDepthStencilAttachmentView?: TextureView;
1207
+ };
1208
+
833
1209
  export function getRenderFeatureGraphState(
834
1210
  internals: RenderSystemInternals,
835
1211
  ): RenderFeatureGraphRuntimeState {
@@ -899,15 +1275,46 @@ export function resolvePostProcessChainAdmission(
899
1275
 
900
1276
  function validateRenderFeaturePlans(
901
1277
  plans: readonly RenderFeaturePlannedFrame[],
1278
+ metrics?: MutableRenderFeatureGraphInspection,
902
1279
  ): Result<readonly RenderFeaturePlanExecution[], RenderError> {
903
1280
  const identities = new Set<string>();
904
1281
  const projected: RenderFeaturePlanExecution[] = [];
905
1282
  let previousOrder = -1;
906
1283
  for (const [order, planned] of plans.entries()) {
907
1284
  const execution = getRenderFeaturePlanExecutionProjection(planned);
1285
+ const signatureMetrics =
1286
+ metrics === undefined ? undefined : { calls: 0, typedArrayBytes: 0, outputChars: 0 };
1287
+ const started =
1288
+ metrics === undefined
1289
+ ? 0
1290
+ : typeof performance === 'undefined'
1291
+ ? Date.now()
1292
+ : performance.now();
1293
+ // The host records detached structural evidence, but graph admission must
1294
+ // check it again so a mutation between the two synchronous stages cannot
1295
+ // smuggle a stale plan into the compiled graph. Only candidates without
1296
+ // evidence fall back to the canonical serializer.
1297
+ const signatureCacheHit = renderFeaturePlanSignatureEvidenceMatches(
1298
+ planned.plan,
1299
+ planned.signature,
1300
+ );
1301
+ if (metrics !== undefined) {
1302
+ if (signatureCacheHit) metrics.signatureValidationCacheHits += 1;
1303
+ else metrics.signatureValidationCacheMisses += 1;
1304
+ }
1305
+ const recomputedSignature = signatureCacheHit
1306
+ ? planned.signature
1307
+ : renderFeaturePlanSignature(planned.plan, signatureMetrics);
1308
+ if (metrics !== undefined) {
1309
+ const now = typeof performance === 'undefined' ? Date.now() : performance.now();
1310
+ metrics.signatureValidationCalls += signatureMetrics?.calls ?? 0;
1311
+ metrics.signatureValidationBytes += signatureMetrics?.typedArrayBytes ?? 0;
1312
+ metrics.signatureValidationChars += signatureMetrics?.outputChars ?? 0;
1313
+ metrics.signatureValidationCpuMs += now - started;
1314
+ }
908
1315
  if (
909
1316
  identities.has(planned.featureIdentity) ||
910
- planned.signature !== renderFeaturePlanSignature(planned.plan) ||
1317
+ planned.signature !== recomputedSignature ||
911
1318
  execution === undefined ||
912
1319
  execution.featureIdentity !== planned.featureIdentity ||
913
1320
  execution.order <= previousOrder
@@ -930,7 +1337,7 @@ function commitFeatureCandidate(
930
1337
  // Publish renderer-owned declarations only after their device resources have
931
1338
  // been admitted. If the acceptance hook throws, the previously accepted
932
1339
  // graph/state pair remains visible to the caller.
933
- candidate.onAccepted?.();
1340
+ recordRenderFeatureCandidateEvent(internals, candidate, 'accepted');
934
1341
  const state = getRenderFeatureGraphState(internals);
935
1342
  state.plans = candidate.plans;
936
1343
  state.fullscreenEffects = candidate.fullscreenEffects;
@@ -948,10 +1355,13 @@ function topologyOf(
948
1355
  shadowMapSize: number | undefined,
949
1356
  gpuDriven: PreparedGpuDrivenFrame | undefined,
950
1357
  featureGraphCandidate: RenderFeatureGraphCandidate | undefined,
1358
+ featurePlanRevision: number,
951
1359
  cubeCaptureState: CubeCaptureGraphState | undefined,
952
1360
  transmissionDemand: TransmissionDemand | undefined,
953
1361
  volumetricFog: ExtractedVolumetricFog | undefined,
954
1362
  standardLighting: StandardTopologyInputValue | undefined,
1363
+ ssr: SsrSpatialAdmission | undefined,
1364
+ renderExtent: RenderExtent | undefined,
955
1365
  ): Result<RenderPipelineTopology, RhiError> {
956
1366
  const cascadeCount = Math.max(1, Math.min(4, Math.round(lights.cascadeCount ?? 1))) as
957
1367
  | 1
@@ -1007,12 +1417,16 @@ function topologyOf(
1007
1417
  : volumetricFog?.lightKind === undefined
1008
1418
  ? lights.directional
1009
1419
  : undefined;
1420
+ const preparedLut =
1421
+ frameState.pendingStandardLutGpuResources ?? frameState.standardLutGpuResources;
1010
1422
  return ok({
1011
1423
  pipelineId: STANDARD_PIPELINE_ID,
1012
1424
  standardProfile: internals.standardProfile,
1013
1425
  config,
1014
1426
  clearOnly,
1015
1427
  reflectionFallback: { enabled: frameState.reflectionFallbackDemand === true },
1428
+ ssr,
1429
+ ...(renderExtent === undefined ? {} : { extent: renderExtent }),
1016
1430
  surface: {
1017
1431
  width,
1018
1432
  height,
@@ -1025,6 +1439,27 @@ function topologyOf(
1025
1439
  antialias: camera.antialias,
1026
1440
  bloom: camera.bloom,
1027
1441
  },
1442
+ atmosphere: !clearOnly && frameState.environmentFrame?.source.kind === 'atmosphere',
1443
+ output: {
1444
+ autoExposure:
1445
+ !clearOnly &&
1446
+ camera.output?.exposure.kind === 'auto' &&
1447
+ (frameState.pendingAutoExposureGpuResources ?? frameState.autoExposureGpuResources) !==
1448
+ undefined,
1449
+ whiteBalance:
1450
+ !clearOnly &&
1451
+ camera.output !== undefined &&
1452
+ (camera.output.temperature !== 6504 || camera.output.tint !== 0),
1453
+ temperature: camera.output?.temperature ?? 6504,
1454
+ tint: camera.output?.tint ?? 0,
1455
+ colorLut:
1456
+ !clearOnly &&
1457
+ (camera.output?.colorLutStrength ?? 0) > 0 &&
1458
+ (frameState.pendingStandardLutGpuResources ?? frameState.standardLutGpuResources) !==
1459
+ undefined,
1460
+ colorLutStrength: camera.output?.colorLutStrength ?? 0,
1461
+ ...(preparedLut === undefined ? {} : { lutSourceKey: preparedLut.sourceKey }),
1462
+ },
1028
1463
  temporal: {
1029
1464
  taa: camera.antialias === 'taa',
1030
1465
  motionBlur: isMotionBlurTemporalDemand(camera.motionBlur),
@@ -1092,9 +1527,7 @@ function topologyOf(
1092
1527
  maxColorAttachments: internals.device.caps.maxColorAttachments,
1093
1528
  },
1094
1529
  featureTopologySignature: JSON.stringify({
1095
- plans: renderFeatureGraphPlanSignature(
1096
- featureGraphCandidate?.plans ?? getRenderFeatureGraphState(internals).plans,
1097
- ),
1530
+ planRevision: featurePlanRevision,
1098
1531
  fullscreenEffects: featurePostEffectDeclarations,
1099
1532
  preparedResourceKey: featureGraphCandidate?.preparedResourceKey ?? '',
1100
1533
  cubeCaptureSlots: cubeCaptureState?.work.length ?? 0,
@@ -1263,7 +1696,9 @@ function resolveTargetBindings(
1263
1696
  frame.runtime as RenderSystemInternals,
1264
1697
  frame.frameState,
1265
1698
  frame.pipelineState,
1266
- frame.validated.length > 0,
1699
+ // This callback is reached only for an actual feature draw. A scene
1700
+ // containing only particles still needs the pipeline's View/light ABI.
1701
+ true,
1267
1702
  frame.bindGroupCounts,
1268
1703
  {
1269
1704
  directionalShadow: frame.frameState.currentDirectionalShadowView ?? undefined,
@@ -1350,23 +1785,42 @@ export function ensureCompiledFrameGraph(
1350
1785
  volumeTopologyCandidate = false,
1351
1786
  standardLighting?: StandardTopologyInputValue,
1352
1787
  onRecoveryError?: (error: unknown) => void,
1788
+ ssr?: SsrSpatialAdmission,
1789
+ renderExtent?: RenderExtent,
1353
1790
  ): CompiledRenderGraph<RenderPipelineFrame> | null {
1791
+ const featureMetrics = mutableFeatureGraphInspection(internals);
1792
+ featureMetrics.ensureCalls += 1;
1354
1793
  const requestedStandardLightingSignature = standardLightingTopologySignature(standardLighting);
1355
1794
  const lastKnownGood = (): CompiledRenderGraph<RenderPipelineFrame> | null =>
1356
1795
  frameState.compiledFrameGraph !== null &&
1796
+ !hasSubmissionSensitiveFeatures(getRenderFeatureGraphState(internals).plans) &&
1357
1797
  frameState.standardLightingGraphSignature === requestedStandardLightingSignature
1358
1798
  ? frameState.compiledFrameGraph
1359
1799
  : null;
1360
1800
  const surfaceWidth = Math.max(1, width);
1361
1801
  const surfaceHeight = Math.max(1, height);
1362
1802
  const featurePlans = featureGraphCandidate?.plans ?? getRenderFeatureGraphState(internals).plans;
1363
- const projectedFeaturePlans = validateRenderFeaturePlans(featurePlans);
1803
+ const projectedFeaturePlans = validateRenderFeaturePlans(featurePlans, featureMetrics);
1364
1804
  if (!projectedFeaturePlans.ok) {
1805
+ featureMetrics.validationFailures += 1;
1365
1806
  onRecoveryError?.(projectedFeaturePlans.error);
1366
1807
  reportRenderFeatureGraphError(internals, projectedFeaturePlans.error);
1367
- featureGraphCandidate?.onRejected?.();
1808
+ if (featureGraphCandidate !== undefined) {
1809
+ recordRenderFeatureCandidateEvent(internals, featureGraphCandidate, 'rejected');
1810
+ }
1368
1811
  return volumeTopologyCandidate ? null : lastKnownGood();
1369
1812
  }
1813
+ const nextPlanRevision = updateRenderFeaturePlanRevision(
1814
+ featureMetrics.planRevisionState,
1815
+ featurePlans,
1816
+ projectedFeaturePlans.value,
1817
+ );
1818
+ if (nextPlanRevision !== featureMetrics.planRevisionState) {
1819
+ featureMetrics.lastPlanSignature = nextPlanRevision.entries
1820
+ .map((entry) => `${entry.featureIdentity}:${entry.signature}`)
1821
+ .join('|');
1822
+ featureMetrics.planRevisionState = nextPlanRevision;
1823
+ }
1370
1824
  const topologyResult = topologyOf(
1371
1825
  internals,
1372
1826
  frameState,
@@ -1379,15 +1833,21 @@ export function ensureCompiledFrameGraph(
1379
1833
  shadowMapSize,
1380
1834
  gpuDriven,
1381
1835
  featureGraphCandidate,
1836
+ featureMetrics.planRevisionState.revision,
1382
1837
  cubeCaptureState,
1383
1838
  transmissionDemand,
1384
1839
  volumetricFog,
1385
1840
  standardLighting,
1841
+ ssr,
1842
+ renderExtent,
1386
1843
  );
1387
1844
  if (!topologyResult.ok) {
1845
+ featureMetrics.buildFailures += 1;
1388
1846
  onRecoveryError?.(topologyResult.error);
1389
1847
  internals.errorRegistry.fire(topologyResult.error);
1390
- featureGraphCandidate?.onRejected?.();
1848
+ if (featureGraphCandidate !== undefined) {
1849
+ recordRenderFeatureCandidateEvent(internals, featureGraphCandidate, 'rejected');
1850
+ }
1391
1851
  return volumeTopologyCandidate ? null : lastKnownGood();
1392
1852
  }
1393
1853
  const requestedPostEffects = topologyResult.value.config?.postEffects ?? [];
@@ -1416,7 +1876,7 @@ export function ensureCompiledFrameGraph(
1416
1876
  getPipeline(
1417
1877
  identity,
1418
1878
  built.bindGroupLayout,
1419
- topologyResult.value.surface.storageFormat as GPUTextureFormat,
1879
+ [topologyResult.value.surface.storageFormat as GPUTextureFormat],
1420
1880
  entry,
1421
1881
  ) !== null
1422
1882
  );
@@ -1427,7 +1887,9 @@ export function ensureCompiledFrameGraph(
1427
1887
  // Do not publish a candidate whose fullscreen chain is only partially
1428
1888
  // ready. Keep the accepted graph (including its prior post-effect chain)
1429
1889
  // and retry the same feature candidate on the next frame.
1430
- featureGraphCandidate?.onRejected?.();
1890
+ if (featureGraphCandidate !== undefined) {
1891
+ recordRenderFeatureCandidateEvent(internals, featureGraphCandidate, 'rejected');
1892
+ }
1431
1893
  return acceptedLkg;
1432
1894
  }
1433
1895
  const topology = postProcessAdmission.pending
@@ -1441,6 +1903,12 @@ export function ensureCompiledFrameGraph(
1441
1903
  : topologyResult.value;
1442
1904
  const key = JSON.stringify({
1443
1905
  topology,
1906
+ // Observation domains are an explicit per-frame graph demand. They are
1907
+ // part of the cache identity so a request made after the ordinary graph
1908
+ // was compiled can admit the matching tone/output capture boundaries on
1909
+ // that receipt without forcing every unobserved frame onto the split
1910
+ // output path.
1911
+ observationCaptureDomains: [...(internals.observationCaptureDomains ?? [])].sort(),
1444
1912
  // GPU-driven residency can become available after the first record pass
1445
1913
  // (custom mesh handles are resolved into the per-frame projection). The
1446
1914
  // topology signature alone is intentionally stable across that lifecycle,
@@ -1461,11 +1929,13 @@ export function ensureCompiledFrameGraph(
1461
1929
  ]),
1462
1930
  });
1463
1931
  if (frameState.compiledFrameGraph !== null && frameState.compiledFrameGraphTopologyKey === key) {
1932
+ featureMetrics.reuseHits += 1;
1933
+ featureMetrics.lastTopologyKey = key;
1464
1934
  frameState.standardLightingGraphSignature = requestedStandardLightingSignature;
1465
1935
  if (featureGraphCandidate !== undefined && !postProcessAdmission.pending) {
1466
1936
  commitFeatureCandidate(internals, featureGraphCandidate);
1467
1937
  } else if (featureGraphCandidate !== undefined) {
1468
- featureGraphCandidate.onAbandoned?.();
1938
+ recordRenderFeatureCandidateEvent(internals, featureGraphCandidate, 'abandoned');
1469
1939
  }
1470
1940
  // A candidate flag only describes a possible topology replacement. When
1471
1941
  // the derived key is unchanged there is no replacement to stage: reuse the
@@ -1474,17 +1944,120 @@ export function ensureCompiledFrameGraph(
1474
1944
  return frameState.compiledFrameGraph;
1475
1945
  }
1476
1946
 
1947
+ featureMetrics.rebuildAttempts += 1;
1948
+ featureMetrics.lastTopologyKey = key;
1949
+ const discardPendingStandardOutput = (): void => {
1950
+ if (frameState.pendingAutoExposureGpuResources !== undefined) {
1951
+ retireAutoExposureGpuResources(frameState.pendingAutoExposureGpuResources);
1952
+ frameState.pendingAutoExposureGpuResources = undefined;
1953
+ }
1954
+ if (frameState.pendingStandardLutGpuResources !== undefined) {
1955
+ retireStandardLutGpuResources(frameState.pendingStandardLutGpuResources);
1956
+ frameState.pendingStandardLutGpuResources = undefined;
1957
+ }
1958
+ };
1477
1959
  const builder = new RenderGraphBuilder<RenderPipelineFrame>();
1960
+ const autoExposureResources =
1961
+ topology.output?.autoExposure === true ? importAutoExposureGraphResources(builder) : undefined;
1962
+ if (autoExposureResources !== undefined && !autoExposureResources.ok) {
1963
+ internals.errorRegistry.fire(autoExposureResources.error);
1964
+ featureGraphCandidate?.onRejected?.();
1965
+ discardPendingStandardOutput();
1966
+ return lastKnownGood();
1967
+ }
1968
+ const lutResources =
1969
+ topology.output?.colorLut === true
1970
+ ? (() => {
1971
+ const prepared =
1972
+ frameState.pendingStandardLutGpuResources ?? frameState.standardLutGpuResources;
1973
+ if (prepared === undefined) return undefined;
1974
+ const texture = builder.importTexture(
1975
+ 'standard-color-lut-source',
1976
+ {
1977
+ format: 'rgba16float',
1978
+ size: {
1979
+ width: prepared.size,
1980
+ height: prepared.size,
1981
+ depthOrArrayLayers: prepared.size,
1982
+ },
1983
+ dimension: '3d',
1984
+ usage: GPU_TEXTURE_USAGE_TEXTURE_BINDING,
1985
+ },
1986
+ (frame) =>
1987
+ (
1988
+ (frame as _InternalRenderPipelineContext).frameState
1989
+ .pendingStandardLutGpuResources ??
1990
+ (frame as _InternalRenderPipelineContext).frameState.standardLutGpuResources
1991
+ )?.texture ?? prepared.texture,
1992
+ );
1993
+ if (!texture.ok) return texture;
1994
+ const view = builder.importView(
1995
+ texture.value,
1996
+ { label: 'standard-color-lut-source.view', dimension: '3d' },
1997
+ (frame) =>
1998
+ (
1999
+ (frame as _InternalRenderPipelineContext).frameState
2000
+ .pendingStandardLutGpuResources ??
2001
+ (frame as _InternalRenderPipelineContext).frameState.standardLutGpuResources
2002
+ )?.view ?? prepared.view,
2003
+ );
2004
+ if (!view.ok) return view;
2005
+ return ok({ texture: texture.value, view: view.value, prepared });
2006
+ })()
2007
+ : undefined;
2008
+ if (lutResources !== undefined && !lutResources.ok) {
2009
+ internals.errorRegistry.fire(lutResources.error);
2010
+ featureGraphCandidate?.onRejected?.();
2011
+ discardPendingStandardOutput();
2012
+ return lastKnownGood();
2013
+ }
1478
2014
  const taaHistory = camera.antialias === 'taa' ? importTemporalHistoryTargets(builder) : undefined;
2015
+ const targetCoverage =
2016
+ camera.dynamicResolution === undefined || topology.extent === undefined
2017
+ ? undefined
2018
+ : createTargetCoverageAttachment(builder, topology.extent);
2019
+ if (targetCoverage !== undefined && !targetCoverage.ok) {
2020
+ internals.errorRegistry.fire(targetCoverage.error);
2021
+ featureGraphCandidate?.onRejected?.();
2022
+ discardPendingStandardOutput();
2023
+ return lastKnownGood();
2024
+ }
2025
+ const ssrHistory = ssr?.status === 'admitted' ? importSsrHistoryTargets(builder) : undefined;
1479
2026
  let projectedFeatures = false;
2027
+ const featureProjection = createRenderFeatureProjectionState();
2028
+ let featureShadows:
2029
+ | ReturnType<typeof projectRenderFeatureShadows<RenderPipelineFrame>>
2030
+ | undefined;
1480
2031
  let projectedGpuDriven = false;
1481
2032
  const built = frameState.activePipeline.build(
1482
2033
  {
1483
2034
  graph: builder,
2035
+ observationCaptureDomains: internals.observationCaptureDomains,
2036
+ ...(autoExposureResources?.ok === true
2037
+ ? { standardOutput: { autoExposure: autoExposureResources.value } }
2038
+ : {}),
2039
+ ...(lutResources?.ok === true
2040
+ ? {
2041
+ standardOutput: {
2042
+ ...(autoExposureResources?.ok === true
2043
+ ? { autoExposure: autoExposureResources.value }
2044
+ : {}),
2045
+ colorLut: {
2046
+ view: lutResources.value.view,
2047
+ sampler: lutResources.value.prepared.sampler,
2048
+ strength: lutResources.value.prepared.strength,
2049
+ bindGroupLayout: lutResources.value.prepared.bindGroupLayout,
2050
+ bindGroup: lutResources.value.prepared.bindGroup,
2051
+ },
2052
+ },
2053
+ }
2054
+ : {}),
1484
2055
  ...(standardLighting === undefined ? {} : { standardLighting }),
1485
2056
  capabilities: { rgba16floatRenderable: internals.device.caps.rgba16floatRenderable },
1486
2057
  ...(occlusion === undefined ? {} : { occlusion }),
1487
2058
  ...(taaHistory === undefined ? {} : { taaHistory }),
2059
+ ...(targetCoverage?.ok === true ? { targetCoverage: targetCoverage.value } : {}),
2060
+ ...(ssrHistory === undefined ? {} : { ssrHistory }),
1488
2061
  encodeTransmissionMip: ({ pass, resources, source }) => {
1489
2062
  const sourceView = resources.textureView(source);
1490
2063
  if (!sourceView.ok) throw sourceView.error;
@@ -1494,24 +2067,69 @@ export function ensureCompiledFrameGraph(
1494
2067
  projectGpuDriven: (target) => {
1495
2068
  if (projectedGpuDriven || gpuDriven === undefined) return ok(undefined);
1496
2069
  projectedGpuDriven = true;
1497
- return gpuDriven.project(builder, target.format, target.sampleCount);
2070
+ return gpuDriven.project(
2071
+ builder,
2072
+ target.format,
2073
+ target.sampleCount,
2074
+ target.additionalColorFormats,
2075
+ );
1498
2076
  },
1499
- contributeFeatures: (targets, semanticTargets = [], namedTargets = {}) => {
2077
+ ...(gpuDriven?.projectShadow === undefined
2078
+ ? {}
2079
+ : {
2080
+ projectGpuDrivenShadow: (identity) =>
2081
+ gpuDriven.projectShadow?.(builder, identity) ?? ok(undefined),
2082
+ }),
2083
+ contributeShadowFeatures: () =>
2084
+ (featureShadows ??= projectRenderFeatureShadows(
2085
+ builder,
2086
+ projectedFeaturePlans.value,
2087
+ featureProjection,
2088
+ )),
2089
+ contributeFeatures: (
2090
+ targets,
2091
+ semanticTargets = [],
2092
+ namedTargets = {},
2093
+ standardSurfaceAccesses = [],
2094
+ ) => {
1500
2095
  if (projectedFeatures) return ok(undefined);
1501
2096
  projectedFeatures = true;
1502
2097
  if (projectedFeaturePlans.value.length === 0) return ok(undefined);
1503
2098
  const resolveTarget = targetResolver(targets, semanticTargets, namedTargets);
1504
2099
  const projected = projectPlanExecutions(builder, projectedFeaturePlans.value, {
2100
+ state: featureProjection,
1505
2101
  resolveTarget,
2102
+ standardSurfaceAccesses,
1506
2103
  resolveBindings: (input) => resolveTargetBindings(input, featurePostProcessEntries),
2104
+ resolveStandardLighting: (frame, pipeline) => {
2105
+ const context = frame as import('./render-context')._InternalRenderPipelineContext;
2106
+ if (context.standardLighting?.kind !== 'clustered') return undefined;
2107
+ const layout = (
2108
+ pipeline as RenderPipeline & {
2109
+ getBindGroupLayout?: (index: number) => BindGroupLayout;
2110
+ }
2111
+ ).getBindGroupLayout?.(2);
2112
+ if (layout === undefined) return undefined;
2113
+ return (
2114
+ createStandardSurfaceLightingBindGroup(
2115
+ context.runtime,
2116
+ layout,
2117
+ context.standardLighting.prepared.layout.grid,
2118
+ context.hdrpSsaoBlurredView === undefined
2119
+ ? { enabled: false }
2120
+ : { enabled: true, ssaoBlurredView: context.hdrpSsaoBlurredView },
2121
+ ) ?? undefined
2122
+ );
2123
+ },
1507
2124
  reportError: (error) => reportRenderFeatureGraphError(internals, error),
1508
2125
  });
1509
2126
  return projected.ok ? ok(undefined) : projected;
1510
2127
  },
1511
- contributeCubeCaptures: () => {
2128
+ contributeCubeCaptures: (environmentCube) => {
1512
2129
  const reflectionProbes = addReflectionProbeGraphPasses(
1513
2130
  builder,
1514
2131
  cubeCaptureState?.reflectionProbes ?? { work: [] },
2132
+ environmentCube,
1515
2133
  );
1516
2134
  if (!reflectionProbes.ok) return reflectionProbes;
1517
2135
  return cubeCaptureState === undefined
@@ -1524,19 +2142,33 @@ export function ensureCompiledFrameGraph(
1524
2142
  topology,
1525
2143
  );
1526
2144
  if (!built.ok) {
2145
+ featureMetrics.buildFailures += 1;
1527
2146
  onRecoveryError?.(built.error);
1528
2147
  internals.errorRegistry.fire(built.error);
1529
2148
  featureGraphCandidate?.onRejected?.();
2149
+ discardPendingStandardOutput();
2150
+ if (featureGraphCandidate !== undefined) {
2151
+ recordRenderFeatureCandidateEvent(internals, featureGraphCandidate, 'rejected');
2152
+ }
1530
2153
  return volumeTopologyCandidate ? null : lastKnownGood();
1531
2154
  }
2155
+ featureMetrics.compileAttempts += 1;
2156
+ const compileStarted = typeof performance === 'undefined' ? Date.now() : performance.now();
1532
2157
  const compiled = builder.compile({
1533
2158
  device: internals.device,
1534
2159
  surfaceSize: { width: surfaceWidth, height: surfaceHeight },
1535
2160
  });
2161
+ featureMetrics.compileCpuMs +=
2162
+ (typeof performance === 'undefined' ? Date.now() : performance.now()) - compileStarted;
1536
2163
  if (!compiled.ok) {
2164
+ featureMetrics.compileFailures += 1;
1537
2165
  onRecoveryError?.(compiled.error);
1538
2166
  internals.errorRegistry.fire(compiled.error);
1539
2167
  featureGraphCandidate?.onRejected?.();
2168
+ discardPendingStandardOutput();
2169
+ if (featureGraphCandidate !== undefined) {
2170
+ recordRenderFeatureCandidateEvent(internals, featureGraphCandidate, 'rejected');
2171
+ }
1540
2172
  return lastKnownGood();
1541
2173
  }
1542
2174
  const previous = frameState.compiledFrameGraph;
@@ -1551,21 +2183,31 @@ export function ensureCompiledFrameGraph(
1551
2183
  frameState.compiledFrameGraphGeneration += 1;
1552
2184
  const compiledTargets = compiled.value as CompiledGraphTargetAccess;
1553
2185
  frameState.graphGeneration += 1;
2186
+ featureMetrics.compileSuccesses += 1;
1554
2187
  frameState.perFrameGraph = {
1555
2188
  getColorTargetDescriptor: (name) => compiledTargets.getColorTargetDescriptor(name),
1556
2189
  getColorTargetView: (name) => compiledTargets.getColorTargetView(name),
1557
2190
  getColorTargetTexture: (name) => compiledTargets.getColorTargetTexture(name),
1558
2191
  graphGeneration: frameState.graphGeneration,
1559
2192
  };
2193
+ // View buffer replacement is safe to retire once the compiled graph owns
2194
+ // the new imports. Shadow cache publication remains submit-transactional
2195
+ // and is committed only by executeCompiledFrameGraph's onSubmitted hook.
2196
+ if (gpuDriven?._commitGpuResourceReplacement !== undefined) {
2197
+ gpuDriven._commitGpuResourceReplacement();
2198
+ } else {
2199
+ // Synthetic/internal prepared projections predating the split own no
2200
+ // shadow cache; retain their original graph-promotion callback.
2201
+ gpuDriven?._commitResourceReplacement();
2202
+ }
1560
2203
  const deviceGeneration = internals.deviceScope?.generation;
1561
2204
  if (deviceGeneration !== undefined) {
1562
2205
  graphDeviceGenerations.set(compiled.value, deviceGeneration);
1563
2206
  }
1564
- gpuDriven?._commitResourceReplacement();
1565
2207
  if (featureGraphCandidate !== undefined && !postProcessAdmission.pending) {
1566
2208
  commitFeatureCandidate(internals, featureGraphCandidate);
1567
2209
  } else if (featureGraphCandidate !== undefined) {
1568
- featureGraphCandidate.onAbandoned?.();
2210
+ recordRenderFeatureCandidateEvent(internals, featureGraphCandidate, 'abandoned');
1569
2211
  }
1570
2212
  if (!volumeTopologyCandidate && previous !== null) retire(frameState, previous);
1571
2213
  return compiled.value;
@@ -1577,15 +2219,21 @@ export function executeCompiledFrameGraph(
1577
2219
  frame: RenderPipelineFrame,
1578
2220
  encoder: RhiCommandEncoder,
1579
2221
  runPass?: import('@forgeax/engine-render-graph').RenderGraphPassRunner,
1580
- frameHooks?: {
1581
- readonly afterGraphExecute?: () => Result<void, RhiError>;
1582
- readonly onSubmitted?: () => void;
1583
- readonly onAborted?: () => void;
1584
- },
2222
+ frameHooks?:
2223
+ | {
2224
+ readonly afterGraphExecute?: () => Result<void, RhiError>;
2225
+ readonly onSubmitted?: () => void;
2226
+ readonly onAborted?: () => void;
2227
+ }
2228
+ // Keep the pre-submit-hook shape accepted for internal callers that have
2229
+ // not yet migrated to the typed frame hooks object.
2230
+ | (() => void),
1585
2231
  readbackFaces?: readonly number[],
1586
2232
  onSubmitted?: (completed: Promise<unknown>) => void,
1587
2233
  timingCapture?: GpuTimingCapture,
1588
2234
  ): boolean {
2235
+ const legacySubmitCommit = typeof frameHooks === 'function' ? frameHooks : undefined;
2236
+ const resolvedFrameHooks = typeof frameHooks === 'function' ? undefined : frameHooks;
1589
2237
  const graph = frameState.compiledFrameGraph;
1590
2238
  const rejectTemporalFrame = (): void => {
1591
2239
  if (frameState.temporalFrameInput === undefined) return;
@@ -1594,6 +2242,8 @@ export function executeCompiledFrameGraph(
1594
2242
  };
1595
2243
  if (graph === null) {
1596
2244
  timingCapture?.discard();
2245
+ frameState.pendingAutoExposureState = undefined;
2246
+ frameState.pendingStandardLutState = undefined;
1597
2247
  settleVolumetricFogGraphCandidate(frameState, false);
1598
2248
  rejectTemporalFrame();
1599
2249
  return false;
@@ -1664,14 +2314,327 @@ export function executeCompiledFrameGraph(
1664
2314
  const transaction = executeRendererFrameTransaction<PreparedCommand>({
1665
2315
  build: () => ({ ok: true, value: { command: undefined as never } }),
1666
2316
  execute: () => {
1667
- const executed = graph.execute(frame, runPass, graphInstrumentation);
1668
- timingInstrumentationState?.setCapture(undefined);
1669
- if (!executed.ok) {
1670
- passTimingCapture?.abort({ code: executed.error.code });
1671
- internals.errorRegistry.fire(executed.error);
1672
- return { ok: false, stage: 'execute' };
2317
+ const graphCapture = frameState.graphTargetCapture;
2318
+ const replayPassNames = graphCapture?.replayPassNames;
2319
+ const unsupportedCaptureKind =
2320
+ graphCapture !== undefined &&
2321
+ graphCapture.kind !== undefined &&
2322
+ graphCapture.kind !== 'target-copy' &&
2323
+ graphCapture.kind !== 'pass-replay';
2324
+ if (unsupportedCaptureKind || replayPassNames !== undefined) {
2325
+ if (graphCapture === undefined) {
2326
+ return { ok: false, stage: 'execute' };
2327
+ }
2328
+ const passNames = graph.inspect().passes.map((pass) => pass.name);
2329
+ const passNameCounts = new Map<string, number>();
2330
+ for (const passName of passNames) {
2331
+ passNameCounts.set(passName, (passNameCounts.get(passName) ?? 0) + 1);
2332
+ }
2333
+ const passNameSet = new Set(passNames);
2334
+ const selectedReplayPassNames = replayPassNames ?? [];
2335
+ const requestedPassNames = new Set(selectedReplayPassNames);
2336
+ const passReplayCapture = graphCapture.kind === 'pass-replay' ? graphCapture : undefined;
2337
+ const onPassEncoded = passReplayCapture?.onPassEncoded;
2338
+ const onPrefixEncoded = passReplayCapture?.onPrefixEncoded;
2339
+ const depthAttachmentPassName = passReplayCapture?.depthAttachmentPassName;
2340
+ const observeAfterPassName = passReplayCapture?.observeAfterPassName;
2341
+ let replayValidationFailed = false;
2342
+ const duplicatePassName = selectedReplayPassNames.find(
2343
+ (passName, index) => selectedReplayPassNames.indexOf(passName) !== index,
2344
+ );
2345
+ const invalidPassName = selectedReplayPassNames.find(
2346
+ (passName) => !passNameSet.has(passName),
2347
+ );
2348
+ const nonUniquePassName = selectedReplayPassNames.find(
2349
+ (passName) => passNameCounts.get(passName) !== 1,
2350
+ );
2351
+ const replayFailure = (reason: string): void => {
2352
+ replayValidationFailed = true;
2353
+ internals.errorRegistry.fire(
2354
+ new RhiError({
2355
+ code: 'webgpu-runtime-error',
2356
+ expected:
2357
+ 'the requested graph target replay pass selection is valid and executes once',
2358
+ hint: 'inspect replayPassNames against the compiled graph pass roster',
2359
+ detail: {
2360
+ error: {
2361
+ code: 'graph-target-capture-failed',
2362
+ message: JSON.stringify({
2363
+ target: graphCapture.kind === 'pass-replay' ? undefined : graphCapture.name,
2364
+ replayPassNames,
2365
+ availablePassNames: passNames,
2366
+ reason,
2367
+ }),
2368
+ },
2369
+ },
2370
+ }),
2371
+ );
2372
+ };
2373
+ if (unsupportedCaptureKind) {
2374
+ replayFailure('capture-kind-unknown');
2375
+ return { ok: false, stage: 'execute' };
2376
+ }
2377
+ if (replayPassNames === undefined) {
2378
+ replayFailure('replay-pass-selection-missing');
2379
+ return { ok: false, stage: 'execute' };
2380
+ }
2381
+ if (replayPassNames.length === 0) {
2382
+ replayFailure('replay-pass-selection-empty');
2383
+ return { ok: false, stage: 'execute' };
2384
+ }
2385
+ if (duplicatePassName !== undefined) {
2386
+ replayFailure(`replay-pass-selection-duplicate:${duplicatePassName}`);
2387
+ return { ok: false, stage: 'execute' };
2388
+ }
2389
+ if (invalidPassName !== undefined) {
2390
+ replayFailure(`replay-pass-selection-unknown:${invalidPassName}`);
2391
+ return { ok: false, stage: 'execute' };
2392
+ }
2393
+ if (nonUniquePassName !== undefined) {
2394
+ replayFailure(`replay-pass-selection-non-unique:${nonUniquePassName}`);
2395
+ return { ok: false, stage: 'execute' };
2396
+ }
2397
+
2398
+ if (onPrefixEncoded !== undefined) {
2399
+ if (onPassEncoded !== undefined) {
2400
+ replayFailure('pass-replay-prefix-callback-conflict');
2401
+ return { ok: false, stage: 'execute' };
2402
+ }
2403
+ if (depthAttachmentPassName === undefined) {
2404
+ replayFailure('pass-replay-depth-attachment-name-missing');
2405
+ return { ok: false, stage: 'execute' };
2406
+ }
2407
+ if (observeAfterPassName === undefined) {
2408
+ replayFailure('pass-replay-observe-boundary-name-missing');
2409
+ return { ok: false, stage: 'execute' };
2410
+ }
2411
+ const firstNonPrefixPass = selectedReplayPassNames.find(
2412
+ (passName, index) => passName !== passNames[index],
2413
+ );
2414
+ if (
2415
+ firstNonPrefixPass !== undefined ||
2416
+ selectedReplayPassNames.length > passNames.length
2417
+ ) {
2418
+ replayFailure('pass-replay-selection-not-prefix');
2419
+ return { ok: false, stage: 'execute' };
2420
+ }
2421
+ if (selectedReplayPassNames.at(-1) !== observeAfterPassName) {
2422
+ replayFailure('pass-replay-observe-boundary-not-last');
2423
+ return { ok: false, stage: 'execute' };
2424
+ }
2425
+ const anchorIndex = selectedReplayPassNames.indexOf(depthAttachmentPassName);
2426
+ if (anchorIndex < 0 || anchorIndex > selectedReplayPassNames.length - 1) {
2427
+ replayFailure('pass-replay-depth-attachment-not-in-prefix');
2428
+ return { ok: false, stage: 'execute' };
2429
+ }
2430
+ }
2431
+
2432
+ let replayTarget:
2433
+ | {
2434
+ readonly name: string;
2435
+ readonly view: TextureView;
2436
+ readonly texture: Texture;
2437
+ readonly textureIdentity: number;
2438
+ readonly graphGeneration: number;
2439
+ }
2440
+ | undefined;
2441
+ if (onPassEncoded !== undefined || onPrefixEncoded !== undefined) {
2442
+ const targetName = passReplayCapture?.targetName;
2443
+ const graphAccess = frameState.perFrameGraph;
2444
+ const targetView =
2445
+ targetName === undefined ? undefined : graphAccess?.getColorTargetView(targetName);
2446
+ const targetTexture =
2447
+ targetName === undefined ? undefined : graphAccess?.getColorTargetTexture(targetName);
2448
+ const targetDescriptor =
2449
+ targetName === undefined
2450
+ ? undefined
2451
+ : graphAccess?.getColorTargetDescriptor(targetName);
2452
+ if (targetName === undefined) {
2453
+ replayFailure('pass-replay-target-name-missing');
2454
+ return { ok: false, stage: 'execute' };
2455
+ }
2456
+ if (graphAccess === undefined || graphAccess === null) {
2457
+ replayFailure(`pass-replay-target-missing:${targetName}`);
2458
+ return { ok: false, stage: 'execute' };
2459
+ }
2460
+ if (targetView === undefined || targetTexture === undefined) {
2461
+ replayFailure(`pass-replay-target-missing:${targetName}`);
2462
+ return { ok: false, stage: 'execute' };
2463
+ }
2464
+ if (targetDescriptor !== undefined && targetDescriptor.texture !== targetTexture) {
2465
+ replayFailure(`pass-replay-target-identity-mismatch:${targetName}`);
2466
+ return { ok: false, stage: 'execute' };
2467
+ }
2468
+ replayTarget = {
2469
+ name: targetName,
2470
+ view: targetView,
2471
+ texture: targetTexture,
2472
+ textureIdentity: getTextureIdentity(targetTexture),
2473
+ graphGeneration: graphAccess.graphGeneration,
2474
+ };
2475
+ }
2476
+
2477
+ const executed = graph.execute(frame, runPass, graphInstrumentation);
2478
+ if (!executed.ok) {
2479
+ passTimingCapture?.abort({ code: executed.error.code });
2480
+ internals.errorRegistry.fire(executed.error);
2481
+ return { ok: false, stage: 'execute' };
2482
+ }
2483
+ const replayedPassNames = new Set<string>();
2484
+ let prefixCallbackCount = 0;
2485
+ let depthAnchorReceipt:
2486
+ | {
2487
+ readonly pass: { name: string; executionIndex: number };
2488
+ readonly view: TextureView;
2489
+ }
2490
+ | undefined;
2491
+ const replayRunPass: import('@forgeax/engine-render-graph').RenderGraphPassRunner = (
2492
+ pass,
2493
+ encode,
2494
+ ) => {
2495
+ if (!requestedPassNames.has(pass.name)) return;
2496
+ if (replayedPassNames.has(pass.name)) {
2497
+ replayFailure(`replay-pass-selection-multiple-hit:${pass.name}`);
2498
+ return;
2499
+ }
2500
+ replayedPassNames.add(pass.name);
2501
+ const depthView = (pass as ResolvedDepthPassExecution).resolvedDepthStencilAttachmentView;
2502
+ if (onPrefixEncoded !== undefined) {
2503
+ if (pass.name === depthAttachmentPassName) {
2504
+ if (depthView === undefined) {
2505
+ replayFailure(`pass-replay-depth-attachment-missing:${pass.name}`);
2506
+ return;
2507
+ }
2508
+ const target = replayTarget;
2509
+ if (target === undefined || depthView !== target.view) {
2510
+ replayFailure(`pass-replay-attachment-target-mismatch:${pass.name}`);
2511
+ return;
2512
+ }
2513
+ if (depthAnchorReceipt !== undefined) {
2514
+ replayFailure(`pass-replay-depth-attachment-multiple-hit:${pass.name}`);
2515
+ return;
2516
+ }
2517
+ depthAnchorReceipt = {
2518
+ pass: { name: pass.name, executionIndex: pass.executionIndex },
2519
+ view: depthView,
2520
+ };
2521
+ }
2522
+ let encoded = false;
2523
+ const encodePrefix = () => {
2524
+ if (encoded) {
2525
+ replayFailure(`pass-replay-encode-multiple-hit:${pass.name}`);
2526
+ return;
2527
+ }
2528
+ encode();
2529
+ encoded = true;
2530
+ if (replayValidationFailed || pass.name !== observeAfterPassName) return;
2531
+ const target = replayTarget;
2532
+ const anchor = depthAnchorReceipt;
2533
+ if (target === undefined || anchor === undefined) {
2534
+ replayFailure('pass-replay-depth-attachment-anchor-missing-at-boundary');
2535
+ return;
2536
+ }
2537
+ const receipt: GraphTargetPassReplayPrefixReceipt = {
2538
+ passName: pass.name,
2539
+ executionIndex: pass.executionIndex,
2540
+ resolvedDepthStencilAttachmentView: anchor.view,
2541
+ graphGeneration: target.graphGeneration,
2542
+ targetName: target.name,
2543
+ targetView: target.view,
2544
+ targetTexture: target.texture,
2545
+ targetTextureIdentity: target.textureIdentity,
2546
+ replayPassNames: [...selectedReplayPassNames],
2547
+ depthAttachmentPassName: anchor.pass.name,
2548
+ observeAfterPassName: pass.name,
2549
+ depthAttachmentExecutionIndex: anchor.pass.executionIndex,
2550
+ };
2551
+ try {
2552
+ onPrefixEncoded(receipt);
2553
+ prefixCallbackCount += 1;
2554
+ } catch (cause) {
2555
+ replayFailure(
2556
+ `pass-replay-prefix-callback-threw:${pass.name}:${cause instanceof Error ? cause.message : String(cause)}`,
2557
+ );
2558
+ }
2559
+ };
2560
+ if (runPass === undefined) encodePrefix();
2561
+ else runPass(pass, encodePrefix);
2562
+ if (!encoded && !replayValidationFailed) {
2563
+ replayFailure(`pass-replay-encode-not-called:${pass.name}`);
2564
+ }
2565
+ return;
2566
+ }
2567
+ if (onPassEncoded === undefined) {
2568
+ if (runPass === undefined) encode();
2569
+ else runPass(pass, encode);
2570
+ return;
2571
+ }
2572
+ const target = replayTarget;
2573
+ if (target === undefined || depthView === undefined) {
2574
+ replayFailure(`pass-replay-depth-attachment-missing:${pass.name}`);
2575
+ return;
2576
+ }
2577
+ if (depthView !== target.view) {
2578
+ replayFailure(`pass-replay-attachment-target-mismatch:${pass.name}`);
2579
+ return;
2580
+ }
2581
+ let encoded = false;
2582
+ const encodeAndObserve = () => {
2583
+ if (encoded) {
2584
+ replayFailure(`pass-replay-encode-multiple-hit:${pass.name}`);
2585
+ return;
2586
+ }
2587
+ encode();
2588
+ encoded = true;
2589
+ if (replayValidationFailed) return;
2590
+ const receipt: GraphTargetPassReplayReceipt = {
2591
+ passName: pass.name,
2592
+ executionIndex: pass.executionIndex,
2593
+ resolvedDepthStencilAttachmentView: depthView,
2594
+ graphGeneration: target.graphGeneration,
2595
+ targetName: target.name,
2596
+ targetView: target.view,
2597
+ targetTexture: target.texture,
2598
+ targetTextureIdentity: target.textureIdentity,
2599
+ };
2600
+ try {
2601
+ onPassEncoded(receipt);
2602
+ } catch (cause) {
2603
+ replayFailure(
2604
+ `pass-replay-callback-threw:${pass.name}:${cause instanceof Error ? cause.message : String(cause)}`,
2605
+ );
2606
+ }
2607
+ };
2608
+ if (runPass === undefined) encodeAndObserve();
2609
+ else runPass(pass, encodeAndObserve);
2610
+ if (!encoded && !replayValidationFailed) {
2611
+ replayFailure(`pass-replay-encode-not-called:${pass.name}`);
2612
+ }
2613
+ };
2614
+ const replayed = graph.execute(frame, replayRunPass);
2615
+ if (!replayed.ok) {
2616
+ internals.errorRegistry.fire(replayed.error);
2617
+ return { ok: false, stage: 'execute' };
2618
+ }
2619
+ if (replayValidationFailed) return { ok: false, stage: 'execute' };
2620
+ if (replayedPassNames.size !== requestedPassNames.size) {
2621
+ replayFailure('replay-pass-selection-zero-hit');
2622
+ return { ok: false, stage: 'execute' };
2623
+ }
2624
+ if (onPrefixEncoded !== undefined && prefixCallbackCount !== 1) {
2625
+ replayFailure('pass-replay-prefix-callback-count-invalid');
2626
+ return { ok: false, stage: 'execute' };
2627
+ }
2628
+ } else {
2629
+ const executed = graph.execute(frame, runPass, graphInstrumentation);
2630
+ if (!executed.ok) {
2631
+ passTimingCapture?.abort({ code: executed.error.code });
2632
+ internals.errorRegistry.fire(executed.error);
2633
+ return { ok: false, stage: 'execute' };
2634
+ }
1673
2635
  }
1674
- const afterGraphExecute = frameHooks?.afterGraphExecute;
2636
+ timingInstrumentationState?.setCapture(undefined);
2637
+ const afterGraphExecute = resolvedFrameHooks?.afterGraphExecute;
1675
2638
  if (afterGraphExecute !== undefined) {
1676
2639
  const recorded = afterGraphExecute();
1677
2640
  if (!recorded.ok) {
@@ -1684,7 +2647,7 @@ export function executeCompiledFrameGraph(
1684
2647
  finish: () => {
1685
2648
  const graphCapture = frameState.graphTargetCapture;
1686
2649
  frameState.graphTargetCapture = undefined;
1687
- if (graphCapture !== undefined) {
2650
+ if (graphCapture !== undefined && graphCapture.kind !== 'pass-replay') {
1688
2651
  const graphAccess = frameState.perFrameGraph;
1689
2652
  const graphTexture = graphAccess?.getColorTargetTexture(graphCapture.name);
1690
2653
  const descriptor = graphAccess?.getColorTargetDescriptor(graphCapture.name);
@@ -1903,7 +2866,8 @@ export function executeCompiledFrameGraph(
1903
2866
  },
1904
2867
  }),
1905
2868
  commit: () => {
1906
- frameHooks?.onSubmitted?.();
2869
+ resolvedFrameHooks?.onSubmitted?.();
2870
+ legacySubmitCommit?.();
1907
2871
  if (frameState.temporalFrameInput !== undefined) {
1908
2872
  const temporal = frameState.temporalFrameTransaction.commit({ accepted: true });
1909
2873
  if (temporal.ok) {
@@ -1931,6 +2895,46 @@ export function executeCompiledFrameGraph(
1931
2895
  ?.perPassResources.commitBloomFrameReceipts?.(frameState.bloomFrameReceipts);
1932
2896
  frameState.bloomFrameReceipts = undefined;
1933
2897
  }
2898
+ const pendingAuto = frameState.pendingAutoExposureGpuResources;
2899
+ if (pendingAuto !== undefined) {
2900
+ const previousAuto = frameState.autoExposureGpuResources;
2901
+ frameState.autoExposureGpuResources = pendingAuto;
2902
+ frameState.pendingAutoExposureGpuResources = undefined;
2903
+ if (previousAuto !== undefined && previousAuto !== pendingAuto) {
2904
+ internals.device.queue
2905
+ .onSubmittedWorkDone()
2906
+ .then(() => retireAutoExposureGpuResources(previousAuto))
2907
+ .catch(() => undefined);
2908
+ }
2909
+ }
2910
+ const pendingAutoState = frameState.pendingAutoExposureState;
2911
+ if (pendingAutoState !== undefined) {
2912
+ frameState.autoExposureState = commitAutoExposureSubmission(
2913
+ pendingAutoState.state,
2914
+ pendingAutoState,
2915
+ );
2916
+ frameState.pendingAutoExposureState = undefined;
2917
+ }
2918
+ const pendingLut = frameState.pendingStandardLutGpuResources;
2919
+ if (pendingLut !== undefined) {
2920
+ const previousLut = frameState.standardLutGpuResources;
2921
+ frameState.standardLutGpuResources = pendingLut;
2922
+ frameState.pendingStandardLutGpuResources = undefined;
2923
+ if (previousLut !== undefined && previousLut !== pendingLut) {
2924
+ retireStandardLutGpuResources(previousLut);
2925
+ }
2926
+ }
2927
+ const pendingLutState = frameState.pendingStandardLutState;
2928
+ if (pendingLutState !== undefined) {
2929
+ frameState.standardLutState =
2930
+ pendingLutState.remove || pendingLutState.candidate === undefined
2931
+ ? resetStandardLutState(pendingLutState.state, 'resource-removed', {
2932
+ targetGeneration: pendingLutState.targetGeneration,
2933
+ deviceEpoch: pendingLutState.deviceEpoch,
2934
+ })
2935
+ : commitStandardLutCandidate(pendingLutState.state, pendingLutState.candidate);
2936
+ frameState.pendingStandardLutState = undefined;
2937
+ }
1934
2938
  const stagedGpuState = frameState.temporalGpuState;
1935
2939
  if (stagedGpuState !== undefined) {
1936
2940
  if (commitTemporalGpuSubmit(stagedGpuState)) {
@@ -1993,15 +2997,28 @@ export function executeCompiledFrameGraph(
1993
2997
  frameState.environmentLifecycle?.publish(frameState.environmentGeneration);
1994
2998
  frameState.environmentGeneration = undefined;
1995
2999
  }
3000
+ frameState.pendingAtmospherePublish?.();
3001
+ frameState.pendingAtmospherePublish = undefined;
1996
3002
  onSubmitted?.(internals.device.queue.onSubmittedWorkDone());
1997
3003
  },
1998
3004
  abort: (failure) => {
1999
- frameHooks?.onAborted?.();
3005
+ frameState.pendingAtmospherePublish = undefined;
3006
+ resolvedFrameHooks?.onAborted?.();
2000
3007
  passTimingCapture?.abort({ code: failure.stage });
2001
3008
  timingHost.gpuPassTimingCapture = undefined;
2002
3009
  timingHost.gpuPassTimingSubmittedWork = undefined;
2003
3010
  timingCapture?.discard();
2004
3011
  frameState.bloomFrameReceipts = undefined;
3012
+ frameState.pendingAutoExposureState = undefined;
3013
+ frameState.pendingStandardLutState = undefined;
3014
+ if (frameState.pendingAutoExposureGpuResources !== undefined) {
3015
+ retireAutoExposureGpuResources(frameState.pendingAutoExposureGpuResources);
3016
+ frameState.pendingAutoExposureGpuResources = undefined;
3017
+ }
3018
+ if (frameState.pendingStandardLutGpuResources !== undefined) {
3019
+ retireStandardLutGpuResources(frameState.pendingStandardLutGpuResources);
3020
+ frameState.pendingStandardLutGpuResources = undefined;
3021
+ }
2005
3022
  if (frameState.environmentGeneration !== undefined) {
2006
3023
  frameState.environmentLifecycle?.recordStageFailure(
2007
3024
  failure.stage,