@forgeax/engine-render 0.1.33 → 0.1.35

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 (624) hide show
  1. package/README.md +1062 -127
  2. package/dist/assembly/backend-contract.d.ts +2 -0
  3. package/dist/assembly/backend-contract.d.ts.map +1 -1
  4. package/dist/assembly/barrel-distortion-inspection.d.ts +3 -0
  5. package/dist/assembly/barrel-distortion-inspection.d.ts.map +1 -0
  6. package/dist/assembly/canvas-draw-guard.d.ts +3 -0
  7. package/dist/assembly/canvas-draw-guard.d.ts.map +1 -0
  8. package/dist/assembly/cloud-shadow-entry.d.ts +4 -0
  9. package/dist/assembly/cloud-shadow-entry.d.ts.map +1 -0
  10. package/dist/assembly/device-feature-admission.d.ts +2 -2
  11. package/dist/assembly/dynamic-geometry-host.d.ts +4 -1
  12. package/dist/assembly/dynamic-geometry-host.d.ts.map +1 -1
  13. package/dist/assembly/dynamic-geometry-runtime.d.ts +1 -1
  14. package/dist/assembly/dynamic-geometry-runtime.d.ts.map +1 -1
  15. package/dist/assembly/factory.d.ts +1 -1
  16. package/dist/assembly/factory.d.ts.map +1 -1
  17. package/dist/assembly/host-contract.d.ts +6 -5
  18. package/dist/assembly/host-contract.d.ts.map +1 -1
  19. package/dist/assembly/material/assembly.d.ts.map +1 -1
  20. package/dist/assembly/material/pipeline-helpers.d.ts +5 -0
  21. package/dist/assembly/material/pipeline-helpers.d.ts.map +1 -1
  22. package/dist/assembly/material-shader-policy.d.ts +16 -2
  23. package/dist/assembly/material-shader-policy.d.ts.map +1 -1
  24. package/dist/assembly/material-shader-prewarm.d.ts.map +1 -1
  25. package/dist/assembly/recovery/device-loss-fanout.d.ts.map +1 -1
  26. package/dist/assembly/recovery/renderer-recover.d.ts +2 -0
  27. package/dist/assembly/recovery/renderer-recover.d.ts.map +1 -1
  28. package/dist/assembly/render-feature-post-processes.d.ts +6 -0
  29. package/dist/assembly/render-feature-post-processes.d.ts.map +1 -0
  30. package/dist/assembly/render-target-host.d.ts +5 -0
  31. package/dist/assembly/render-target-host.d.ts.map +1 -1
  32. package/dist/assembly/renderer-facade.d.ts.map +1 -1
  33. package/dist/assembly/renderer-feature-inspection.d.ts +1 -1
  34. package/dist/assembly/renderer-feature-inspection.d.ts.map +1 -1
  35. package/dist/assembly/renderer-frame-transaction.d.ts +12 -0
  36. package/dist/assembly/renderer-frame-transaction.d.ts.map +1 -1
  37. package/dist/assembly/renderer-inspection.d.ts +11 -0
  38. package/dist/assembly/renderer-inspection.d.ts.map +1 -1
  39. package/dist/assembly/webgpu-pbr-ready.d.ts +1 -0
  40. package/dist/assembly/webgpu-pbr-ready.d.ts.map +1 -1
  41. package/dist/assembly/webgpu-ready-per-pass.d.ts +39 -0
  42. package/dist/assembly/webgpu-ready-per-pass.d.ts.map +1 -0
  43. package/dist/assembly/webgpu-ready.d.ts +1 -1
  44. package/dist/assembly/webgpu-ready.d.ts.map +1 -1
  45. package/dist/assembly/webgpu-renderer-bootstrap.d.ts.map +1 -1
  46. package/dist/assembly/webgpu-renderer-observation-owner.d.ts +35 -0
  47. package/dist/assembly/webgpu-renderer-observation-owner.d.ts.map +1 -0
  48. package/dist/assembly/webgpu-renderer.d.ts +2 -1
  49. package/dist/assembly/webgpu-renderer.d.ts.map +1 -1
  50. package/dist/authoring.mjs +2 -4
  51. package/dist/authoring.mjs.map +1 -1
  52. package/dist/barrel-distortion.d.ts +47 -0
  53. package/dist/barrel-distortion.d.ts.map +1 -0
  54. package/dist/chunk-3XUBWRY2.mjs +1842 -0
  55. package/dist/chunk-3XUBWRY2.mjs.map +1 -0
  56. package/dist/{chunk-OO3DRYK7.mjs → chunk-G6HDNGY7.mjs} +2400 -1767
  57. package/dist/chunk-G6HDNGY7.mjs.map +1 -0
  58. package/dist/{chunk-ZDQWGQW7.mjs → chunk-LM5IE7GF.mjs} +4 -4
  59. package/dist/{chunk-ZDQWGQW7.mjs.map → chunk-LM5IE7GF.mjs.map} +1 -1
  60. package/dist/{chunk-VOZWDM3L.mjs → chunk-LNIUIKQ7.mjs} +1514 -498
  61. package/dist/chunk-LNIUIKQ7.mjs.map +1 -0
  62. package/dist/chunk-MXTWKZO4.mjs +3268 -0
  63. package/dist/chunk-MXTWKZO4.mjs.map +1 -0
  64. package/dist/chunk-MZ4C7EHF.mjs +6942 -0
  65. package/dist/chunk-MZ4C7EHF.mjs.map +1 -0
  66. package/dist/chunk-RIPAEGI6.mjs +48 -0
  67. package/dist/chunk-RIPAEGI6.mjs.map +1 -0
  68. package/dist/{chunk-LEAXOMYJ.mjs → chunk-SGPUJW3F.mjs} +117 -5
  69. package/dist/chunk-SGPUJW3F.mjs.map +1 -0
  70. package/dist/{chunk-PA5DRJNI.mjs → chunk-X2KA6WHM.mjs} +29 -4
  71. package/dist/chunk-X2KA6WHM.mjs.map +1 -0
  72. package/dist/{chunk-BLXGONR2.mjs → chunk-XSFB7XXQ.mjs} +51 -4
  73. package/dist/chunk-XSFB7XXQ.mjs.map +1 -0
  74. package/dist/cloud/density.d.ts +55 -0
  75. package/dist/cloud/density.d.ts.map +1 -0
  76. package/dist/cloud/extract.d.ts +25 -0
  77. package/dist/cloud/extract.d.ts.map +1 -0
  78. package/dist/cloud/feature.d.ts +57 -0
  79. package/dist/cloud/feature.d.ts.map +1 -0
  80. package/dist/cloud/frame-context.d.ts +8 -0
  81. package/dist/cloud/frame-context.d.ts.map +1 -0
  82. package/dist/cloud/inspection.d.ts +59 -0
  83. package/dist/cloud/inspection.d.ts.map +1 -0
  84. package/dist/cloud/optics.d.ts +56 -0
  85. package/dist/cloud/optics.d.ts.map +1 -0
  86. package/dist/cloud/parameters.d.ts +73 -0
  87. package/dist/cloud/parameters.d.ts.map +1 -0
  88. package/dist/cloud/resources.d.ts +60 -0
  89. package/dist/cloud/resources.d.ts.map +1 -0
  90. package/dist/cloud/shadow.d.ts +42 -0
  91. package/dist/cloud/shadow.d.ts.map +1 -0
  92. package/dist/cloud/temporal.d.ts +74 -0
  93. package/dist/cloud/temporal.d.ts.map +1 -0
  94. package/dist/components/barrel-distortion.d.ts +13 -0
  95. package/dist/components/barrel-distortion.d.ts.map +1 -0
  96. package/dist/components/cloud-layer.d.ts +29 -0
  97. package/dist/components/cloud-layer.d.ts.map +1 -0
  98. package/dist/components/index.d.ts +2 -0
  99. package/dist/components/index.d.ts.map +1 -1
  100. package/dist/components/instances.d.ts +20 -6
  101. package/dist/components/instances.d.ts.map +1 -1
  102. package/dist/construct-renderer.d.ts +1 -1
  103. package/dist/construct-renderer.d.ts.map +1 -1
  104. package/dist/construct-renderer.mjs +8406 -5785
  105. package/dist/construct-renderer.mjs.map +1 -1
  106. package/dist/device/gpu-residency.d.ts +19 -19
  107. package/dist/device/gpu-residency.d.ts.map +1 -1
  108. package/dist/dynamic-geometry.d.ts +5 -1
  109. package/dist/dynamic-geometry.d.ts.map +1 -1
  110. package/dist/errors/cloud.d.ts +59 -0
  111. package/dist/errors/cloud.d.ts.map +1 -0
  112. package/dist/errors/render.d.ts +20 -5
  113. package/dist/errors/render.d.ts.map +1 -1
  114. package/dist/examples/single-layer-medium-surface.d.ts +47 -0
  115. package/dist/examples/single-layer-medium-surface.d.ts.map +1 -0
  116. package/dist/extract/camera.d.ts.map +1 -1
  117. package/dist/extract/contracts.d.ts +5 -1
  118. package/dist/extract/contracts.d.ts.map +1 -1
  119. package/dist/extract/material-context.d.ts +7 -0
  120. package/dist/extract/material-context.d.ts.map +1 -0
  121. package/dist/features/barrel-distortion.d.ts +29 -0
  122. package/dist/features/barrel-distortion.d.ts.map +1 -0
  123. package/dist/features/error-reporting.d.ts +6 -2
  124. package/dist/features/error-reporting.d.ts.map +1 -1
  125. package/dist/features/host.d.ts +15 -0
  126. package/dist/features/host.d.ts.map +1 -1
  127. package/dist/features/plan.d.ts +10 -0
  128. package/dist/features/plan.d.ts.map +1 -1
  129. package/dist/features/render-graph-contribution.d.ts +5 -0
  130. package/dist/features/render-graph-contribution.d.ts.map +1 -1
  131. package/dist/features/render-graph-raster.d.ts +1 -0
  132. package/dist/features/render-graph-raster.d.ts.map +1 -1
  133. package/dist/features/targets.d.ts +2 -0
  134. package/dist/features/targets.d.ts.map +1 -1
  135. package/dist/features/types.d.ts +48 -0
  136. package/dist/features/types.d.ts.map +1 -1
  137. package/dist/fullscreen-post-process-pass.d.ts +15 -7
  138. package/dist/fullscreen-post-process-pass.d.ts.map +1 -1
  139. package/dist/glyph-text-layout-system.d.ts +1 -1
  140. package/dist/glyph-text-layout-system.d.ts.map +1 -1
  141. package/dist/gpu-dirty-ranges.d.ts +11 -0
  142. package/dist/gpu-dirty-ranges.d.ts.map +1 -0
  143. package/dist/gpu-driven/batch-topology.d.ts +17 -0
  144. package/dist/gpu-driven/batch-topology.d.ts.map +1 -1
  145. package/dist/gpu-driven/material-artifacts.d.ts +6 -0
  146. package/dist/gpu-driven/material-artifacts.d.ts.map +1 -1
  147. package/dist/gpu-driven/prepared-draw.d.ts.map +1 -1
  148. package/dist/gpu-driven/production-raster-material.d.ts +178 -0
  149. package/dist/gpu-driven/production-raster-material.d.ts.map +1 -0
  150. package/dist/gpu-driven/production-raster.d.ts +47 -3
  151. package/dist/gpu-driven/production-raster.d.ts.map +1 -1
  152. package/dist/gpu-driven/resource-allocation.d.ts +31 -0
  153. package/dist/gpu-driven/resource-allocation.d.ts.map +1 -0
  154. package/dist/gpu-driven/shadow-ownership.d.ts +14 -0
  155. package/dist/gpu-driven/shadow-ownership.d.ts.map +1 -0
  156. package/dist/gpu-driven/view-gpu.d.ts +26 -2
  157. package/dist/gpu-driven/view-gpu.d.ts.map +1 -1
  158. package/dist/gpu-scene.d.ts +5 -0
  159. package/dist/gpu-scene.d.ts.map +1 -1
  160. package/dist/hdrp-buffers.d.ts +2 -2
  161. package/dist/hdrp-buffers.d.ts.map +1 -1
  162. package/dist/ibl/frame-resources.d.ts.map +1 -1
  163. package/dist/ibl/skylight-bind-group.d.ts +14 -5
  164. package/dist/ibl/skylight-bind-group.d.ts.map +1 -1
  165. package/dist/index.d.ts +30 -7
  166. package/dist/index.d.ts.map +1 -1
  167. package/dist/index.mjs +780 -9
  168. package/dist/index.mjs.map +1 -1
  169. package/dist/inspection-types.d.ts +135 -1
  170. package/dist/inspection-types.d.ts.map +1 -1
  171. package/dist/instance-buffer-cache.d.ts +4 -4
  172. package/dist/instance-buffer-cache.d.ts.map +1 -1
  173. package/dist/instances.d.ts +47 -100
  174. package/dist/instances.d.ts.map +1 -1
  175. package/dist/internal.mjs +7 -8
  176. package/dist/internal.mjs.map +1 -1
  177. package/dist/pbr-pipeline.d.ts +22 -4
  178. package/dist/pbr-pipeline.d.ts.map +1 -1
  179. package/dist/pipeline/single-layer-medium-passes.d.ts +73 -0
  180. package/dist/pipeline/single-layer-medium-passes.d.ts.map +1 -0
  181. package/dist/pipeline/standard-forward-lane.d.ts.map +1 -1
  182. package/dist/pipeline/standard-output/graph.d.ts.map +1 -1
  183. package/dist/pipeline/standard-output/lut-gpu.d.ts +2 -2
  184. package/dist/pipeline/standard-output/lut-gpu.d.ts.map +1 -1
  185. package/dist/pipeline/standard-output/resources.d.ts +2 -2
  186. package/dist/pipeline/standard-output/resources.d.ts.map +1 -1
  187. package/dist/pipeline/standard-output/types.d.ts +4 -2
  188. package/dist/pipeline/standard-output/types.d.ts.map +1 -1
  189. package/dist/pipeline/standard-pipeline.d.ts.map +1 -1
  190. package/dist/pipeline/standard-post.d.ts.map +1 -1
  191. package/dist/pipeline-builder.d.ts +1 -1
  192. package/dist/pipeline-builder.d.ts.map +1 -1
  193. package/dist/plugin.d.ts.map +1 -1
  194. package/dist/prepare/prepared-graphics-resolver.d.ts +2 -0
  195. package/dist/prepare/prepared-graphics-resolver.d.ts.map +1 -1
  196. package/dist/publication/contract.d.ts +77 -0
  197. package/dist/publication/contract.d.ts.map +1 -0
  198. package/dist/publication/dependencies.d.ts +7 -0
  199. package/dist/publication/dependencies.d.ts.map +1 -0
  200. package/dist/publication/prepare-geometry.d.ts +9 -0
  201. package/dist/publication/prepare-geometry.d.ts.map +1 -0
  202. package/dist/publication/programs.d.ts +5 -0
  203. package/dist/publication/programs.d.ts.map +1 -0
  204. package/dist/publication/publisher.d.ts +33 -0
  205. package/dist/publication/publisher.d.ts.map +1 -0
  206. package/dist/publication/receiver.d.ts +29 -0
  207. package/dist/publication/receiver.d.ts.map +1 -0
  208. package/dist/publication/resource-scope.d.ts +18 -0
  209. package/dist/publication/resource-scope.d.ts.map +1 -0
  210. package/dist/publication/targets.d.ts +33 -0
  211. package/dist/publication/targets.d.ts.map +1 -0
  212. package/dist/publication/video.d.ts +5 -0
  213. package/dist/publication/video.d.ts.map +1 -0
  214. package/dist/record/barrel-distortion-frame.d.ts +15 -0
  215. package/dist/record/barrel-distortion-frame.d.ts.map +1 -0
  216. package/dist/record/dynamic-geometry-consumption.d.ts +10 -2
  217. package/dist/record/dynamic-geometry-consumption.d.ts.map +1 -1
  218. package/dist/record/fold-buckets.d.ts +95 -0
  219. package/dist/record/fold-buckets.d.ts.map +1 -0
  220. package/dist/record/fold-instance-buffer.d.ts +6 -0
  221. package/dist/record/fold-instance-buffer.d.ts.map +1 -0
  222. package/dist/record/frame-lighting.d.ts +1 -0
  223. package/dist/record/frame-lighting.d.ts.map +1 -1
  224. package/dist/record/frame-snapshot.d.ts +43 -9
  225. package/dist/record/frame-snapshot.d.ts.map +1 -1
  226. package/dist/record/frame.d.ts +15 -65
  227. package/dist/record/frame.d.ts.map +1 -1
  228. package/dist/record/gpu-draw-receipts.d.ts +11 -0
  229. package/dist/record/gpu-draw-receipts.d.ts.map +1 -0
  230. package/dist/record/gpu-timing.d.ts +8 -0
  231. package/dist/record/gpu-timing.d.ts.map +1 -1
  232. package/dist/record/helpers.d.ts +2 -2
  233. package/dist/record/helpers.d.ts.map +1 -1
  234. package/dist/record/main-pass-geometry.d.ts +22 -6
  235. package/dist/record/main-pass-geometry.d.ts.map +1 -1
  236. package/dist/record/main-pass-material.d.ts +14 -10
  237. package/dist/record/main-pass-material.d.ts.map +1 -1
  238. package/dist/record/main-pass-sprite-draws.d.ts +3 -16
  239. package/dist/record/main-pass-sprite-draws.d.ts.map +1 -1
  240. package/dist/record/main-pass.d.ts +13 -2
  241. package/dist/record/main-pass.d.ts.map +1 -1
  242. package/dist/record/motion-blur-receipt.d.ts +11 -0
  243. package/dist/record/motion-blur-receipt.d.ts.map +1 -0
  244. package/dist/record/prepared-material-bindings.d.ts +3 -3
  245. package/dist/record/prepared-material-bindings.d.ts.map +1 -1
  246. package/dist/record/probe-blend-buffer.d.ts +16 -0
  247. package/dist/record/probe-blend-buffer.d.ts.map +1 -0
  248. package/dist/record/recovery-pipeline.d.ts.map +1 -1
  249. package/dist/record/render-context.d.ts +24 -5
  250. package/dist/record/render-context.d.ts.map +1 -1
  251. package/dist/record/shadow-pass.d.ts +2 -0
  252. package/dist/record/shadow-pass.d.ts.map +1 -1
  253. package/dist/record/skybox-post-pass.d.ts +1 -1
  254. package/dist/record/skybox-post-pass.d.ts.map +1 -1
  255. package/dist/record/sprite-instance-buffer.d.ts +31 -0
  256. package/dist/record/sprite-instance-buffer.d.ts.map +1 -0
  257. package/dist/record/target-capture-graph.d.ts +19 -0
  258. package/dist/record/target-capture-graph.d.ts.map +1 -0
  259. package/dist/record/typed-frame-graph.d.ts +24 -15
  260. package/dist/record/typed-frame-graph.d.ts.map +1 -1
  261. package/dist/record/view-ubo.d.ts +11 -3
  262. package/dist/record/view-ubo.d.ts.map +1 -1
  263. package/dist/record/volume-params.d.ts +9 -0
  264. package/dist/record/volume-params.d.ts.map +1 -0
  265. package/dist/recovery/render-system-candidate.d.ts +14 -4
  266. package/dist/recovery/render-system-candidate.d.ts.map +1 -1
  267. package/dist/reflection/record-owner.d.ts.map +1 -1
  268. package/dist/render-contract.d.ts +46 -5
  269. package/dist/render-contract.d.ts.map +1 -1
  270. package/dist/render-graph-primitives.d.ts.map +1 -1
  271. package/dist/render-pipeline.d.ts +103 -2
  272. package/dist/render-pipeline.d.ts.map +1 -1
  273. package/dist/render-system-extract-tail.d.ts +3 -2
  274. package/dist/render-system-extract-tail.d.ts.map +1 -1
  275. package/dist/render-system-extract.d.ts +18 -9
  276. package/dist/render-system-extract.d.ts.map +1 -1
  277. package/dist/render-system-presentation.d.ts +23 -0
  278. package/dist/render-system-presentation.d.ts.map +1 -0
  279. package/dist/render-system-producer-roots.d.ts +10 -0
  280. package/dist/render-system-producer-roots.d.ts.map +1 -0
  281. package/dist/render-system-projections.d.ts +3 -2
  282. package/dist/render-system-projections.d.ts.map +1 -1
  283. package/dist/render-system-residency.d.ts +12 -0
  284. package/dist/render-system-residency.d.ts.map +1 -0
  285. package/dist/render-system.d.ts +22 -21
  286. package/dist/render-system.d.ts.map +1 -1
  287. package/dist/scene/probe-blend.d.ts +27 -0
  288. package/dist/scene/probe-blend.d.ts.map +1 -1
  289. package/dist/scene/render-scene.d.ts +18 -7
  290. package/dist/scene/render-scene.d.ts.map +1 -1
  291. package/dist/scene/render-source.d.ts +42 -0
  292. package/dist/scene/render-source.d.ts.map +1 -0
  293. package/dist/scene/source-systems.d.ts +6 -0
  294. package/dist/scene/source-systems.d.ts.map +1 -0
  295. package/dist/ssao-buffers.d.ts +9 -0
  296. package/dist/ssao-buffers.d.ts.map +1 -1
  297. package/dist/surface/dynamic-input.d.ts +133 -0
  298. package/dist/surface/dynamic-input.d.ts.map +1 -0
  299. package/dist/surface/gpu-driven.d.ts +41 -0
  300. package/dist/surface/gpu-driven.d.ts.map +1 -0
  301. package/dist/surface/submission-observation.d.ts +136 -0
  302. package/dist/surface/submission-observation.d.ts.map +1 -0
  303. package/dist/systems/skin-palette-allocator.d.ts.map +1 -1
  304. package/dist/systems/skin-palette-types.d.ts +10 -0
  305. package/dist/systems/skin-palette-types.d.ts.map +1 -1
  306. package/dist/systems/transparent-dispatch.d.ts +2 -2
  307. package/dist/systems/transparent-dispatch.d.ts.map +1 -1
  308. package/dist/systems/transparent-sort-config.d.ts +2 -1
  309. package/dist/systems/transparent-sort-config.d.ts.map +1 -1
  310. package/dist/temporal/gpu.d.ts +13 -1
  311. package/dist/temporal/gpu.d.ts.map +1 -1
  312. package/dist/temporal/index.mjs +6 -7
  313. package/dist/temporal/inspection.d.ts.map +1 -1
  314. package/dist/temporal/standard-scene-data.d.ts.map +1 -1
  315. package/dist/temporal/target-coverage-attachment.d.ts.map +1 -1
  316. package/dist/transmission/single-layer-medium.d.ts +89 -0
  317. package/dist/transmission/single-layer-medium.d.ts.map +1 -0
  318. package/dist/typed-render-graph-primitives.d.ts +14 -2
  319. package/dist/typed-render-graph-primitives.d.ts.map +1 -1
  320. package/dist/volume/component.d.ts +9 -4
  321. package/dist/volume/component.d.ts.map +1 -1
  322. package/dist/volume/extract.d.ts +1 -1
  323. package/dist/volume/extract.d.ts.map +1 -1
  324. package/dist/volume/inspection.d.ts +2 -0
  325. package/dist/volume/inspection.d.ts.map +1 -1
  326. package/dist/volume/passes.d.ts +4 -1
  327. package/dist/volume/passes.d.ts.map +1 -1
  328. package/dist/volume/resources.d.ts.map +1 -1
  329. package/package.json +22 -21
  330. package/src/__tests__/atmosphere-daylight.dawn.test.ts +72 -0
  331. package/src/__tests__/auto-exposure-transaction.integration.test.ts +4 -9
  332. package/src/__tests__/barrel-distortion-lkg.integration.test.ts +353 -0
  333. package/src/__tests__/barrel-distortion.dawn.test.ts +41 -0
  334. package/src/__tests__/barrel-distortion.unit.test.ts +364 -0
  335. package/src/__tests__/construct-renderer-identity.unit.test.ts +49 -0
  336. package/src/__tests__/detached-recovery-graph.unit.test.ts +277 -0
  337. package/src/__tests__/device-feature-admission.unit.test.ts +3 -2
  338. package/src/__tests__/device-loss-fanout.unit.test.ts +36 -1
  339. package/src/__tests__/docs-gate-green.unit.test.ts +112 -1
  340. package/src/__tests__/factory-contract.integration.test.ts +295 -45
  341. package/src/__tests__/feature-depth-input.dawn.test.ts +129 -2
  342. package/src/__tests__/fullscreen-feature-plan.unit.test.ts +14 -3
  343. package/src/__tests__/gpu-dirty-ranges.unit.test.ts +22 -0
  344. package/src/__tests__/gpu-driven-baseline.characterization.test.ts +16 -3
  345. package/src/__tests__/gpu-driven-batch-topology-pbr.unit.test.ts +12 -0
  346. package/src/__tests__/gpu-driven-material-artifacts.unit.test.ts +143 -0
  347. package/src/__tests__/gpu-driven-pbr.dawn.test.ts +5 -6
  348. package/src/__tests__/gpu-driven-production.integration.test.ts +482 -3
  349. package/src/__tests__/gpu-driven-shadow-views.dawn.test.ts +6 -5
  350. package/src/__tests__/gpu-driven-view-gpu-evidence.ts +94 -6
  351. package/src/__tests__/gpu-driven-view-graph.integration.test.ts +18 -2
  352. package/src/__tests__/gpu-driven-view.browser.test.ts +5 -8
  353. package/src/__tests__/gpu-driven-view.dawn.test.ts +6 -2
  354. package/src/__tests__/gpu-driven-view.unit.test.ts +1 -1
  355. package/src/__tests__/gpu-pass-timing-lifecycle.integration.test.ts +1 -0
  356. package/src/__tests__/gpu-pass-timing.browser.test.ts +6 -4
  357. package/src/__tests__/gpu-pass-timing.rhi-null.unit.test.ts +1 -0
  358. package/src/__tests__/gpu-scene.unit.test.ts +119 -9
  359. package/src/__tests__/instance-allocation-failure.unit.test.ts +57 -0
  360. package/src/__tests__/instances-culling.integration.test.ts +10 -36
  361. package/src/__tests__/instances-store.unit.test.ts +97 -305
  362. package/src/__tests__/instances-world-ownership.integration.test.ts +62 -0
  363. package/src/__tests__/ktx2-basis-gpu-consumer.dawn.test.ts +4 -1
  364. package/src/__tests__/main-pass-material-medium-selection.unit.test.ts +145 -0
  365. package/src/__tests__/material-shader-prewarm.unit.test.ts +59 -0
  366. package/src/__tests__/material-snapshot-mutation.integration.test.ts +39 -1
  367. package/src/__tests__/materials-standard-contract.unit.test.ts +0 -1
  368. package/src/__tests__/morph-culling-reentry.dawn.test.ts +5 -5
  369. package/src/__tests__/morph-visual-evidence.integration.test.ts +8 -7
  370. package/src/__tests__/motion-blur-compute.dawn.test.ts +13 -7
  371. package/src/__tests__/motion-blur.pixel.integration.test.ts +2 -2
  372. package/src/__tests__/nineslice-handle-surface.unit.test.ts +4 -4
  373. package/src/__tests__/pbr-view-layout.unit.test.ts +9 -0
  374. package/src/__tests__/physical-clearcoat.integration.test.ts +66 -8
  375. package/src/__tests__/physical-material-budget.unit.test.ts +40 -0
  376. package/src/__tests__/prepared-graphics-capability.unit.test.ts +66 -2
  377. package/src/__tests__/probe-bindings.unit.test.ts +582 -1
  378. package/src/__tests__/probe-scene-dirty.integration.test.ts +28 -1
  379. package/src/__tests__/receipt-observation-retirement.unit.test.ts +65 -0
  380. package/src/__tests__/recovery-candidate-prepare.contract.test.ts +69 -0
  381. package/src/__tests__/render-error-code-owner.test-d.ts +8 -0
  382. package/src/__tests__/render-feature-diagnostics.unit.test.ts +15 -2
  383. package/src/__tests__/render-feature-error-reporting.unit.test.ts +21 -1
  384. package/src/__tests__/render-feature-prepared-diagnostics.unit.test.ts +10 -1
  385. package/src/__tests__/render-feature-retry.unit.test.ts +12 -1
  386. package/src/__tests__/render-scene-mixed-updates.integration.test.ts +145 -19
  387. package/src/__tests__/render-scene-projection.unit.test.ts +36 -11
  388. package/src/__tests__/render-scene-temporal-retry.unit.test.ts +20 -20
  389. package/src/__tests__/render-target-probe-soak.perf.test.ts +2 -2
  390. package/src/__tests__/render-temporal-environment-consumer.browser.test.ts +3 -3
  391. package/src/__tests__/render-temporal-environment-consumer.dawn.test.ts +5 -2
  392. package/src/__tests__/renderer-factory-material-contract.unit.test.ts +42 -8
  393. package/src/__tests__/renderer-frame-generation-fence.integration.test.ts +16 -0
  394. package/src/__tests__/renderer-frame-transaction.integration.test.ts +26 -10
  395. package/src/__tests__/resource-allocation.unit.test.ts +123 -0
  396. package/src/__tests__/single-layer-medium-passes.unit.test.ts +275 -0
  397. package/src/__tests__/skin-motion-regression.unit.test.ts +70 -1
  398. package/src/__tests__/skin-palette-recycling.dawn.test.ts +97 -0
  399. package/src/__tests__/skinned-shadow-caster.test.ts +15 -0
  400. package/src/__tests__/ssr-carrier-public-contract.unit.test.ts +21 -0
  401. package/src/__tests__/ssr-gpu-dispatch.browser.test.ts +4 -4
  402. package/src/__tests__/ssr-gpu-dispatch.dawn.test.ts +2 -2
  403. package/src/__tests__/ssr-gpu-dispatch.ts +1 -1
  404. package/src/__tests__/ssr-receiver-coverage.dawn.test.ts +6 -2
  405. package/src/__tests__/standard-output-chain-contract.unit.test.ts +28 -0
  406. package/src/__tests__/standard-pbr-artifact-assembly.unit.test.ts +46 -1
  407. package/src/__tests__/standard-pipeline.integration.test.ts +182 -1
  408. package/src/__tests__/surface-dynamic-buffer-lifecycle.unit.test.ts +506 -0
  409. package/src/__tests__/surface-submission-observation.unit.test.ts +812 -0
  410. package/src/__tests__/temporal-history-lifecycle.unit.test.ts +32 -0
  411. package/src/__tests__/temporal-performance.integration.test.ts +3 -3
  412. package/src/__tests__/visibility-instances.integration.test.ts +7 -19
  413. package/src/__tests__/visibility-producer-matrix.integration.test.ts +9 -20
  414. package/src/__tests__/volume-optics-oracle.unit.test.ts +4 -2
  415. package/src/__tests__/volumetric-fog-budget-recovery.integration.test.ts +30 -20
  416. package/src/__tests__/volumetric-fog-errors.unit.test.ts +4 -3
  417. package/src/__tests__/volumetric-fog-multiple.unit.test.ts +55 -0
  418. package/src/__tests__/volumetric-fog-spot-frame-optics.integration.test.ts +1 -1
  419. package/src/__tests__/volumetric-fog-stage-readback.dawn.test.ts +113 -9
  420. package/src/__tests__/volumetric-fog-topology.unit.test.ts +5 -3
  421. package/src/assembly/backend-contract.ts +30 -0
  422. package/src/assembly/barrel-distortion-inspection.ts +22 -0
  423. package/src/assembly/canvas-draw-guard.ts +11 -0
  424. package/src/assembly/cloud-shadow-entry.ts +22 -0
  425. package/src/assembly/device-feature-admission.ts +2 -2
  426. package/src/assembly/dynamic-geometry-host.ts +65 -37
  427. package/src/assembly/dynamic-geometry-runtime.ts +7 -1
  428. package/src/assembly/factory.ts +2 -30
  429. package/src/assembly/host-contract.ts +8 -5
  430. package/src/assembly/material/assembly.ts +25 -13
  431. package/src/assembly/material/pipeline-helpers.ts +53 -12
  432. package/src/assembly/material-shader-policy.ts +55 -0
  433. package/src/assembly/material-shader-prewarm.ts +21 -10
  434. package/src/assembly/recovery/device-loss-fanout.ts +13 -0
  435. package/src/assembly/recovery/renderer-recover.ts +50 -18
  436. package/src/assembly/render-feature-post-processes.ts +54 -0
  437. package/src/assembly/render-target-host.ts +57 -47
  438. package/src/assembly/renderer-facade.ts +7 -2
  439. package/src/assembly/renderer-feature-inspection.ts +8 -2
  440. package/src/assembly/renderer-frame-transaction.ts +23 -0
  441. package/src/assembly/renderer-inspection.ts +28 -0
  442. package/src/assembly/skin-palette-owner.ts +1 -1
  443. package/src/assembly/temporal-post-process-prewarm.ts +3 -3
  444. package/src/assembly/webgpu-pbr-ready.ts +9 -1
  445. package/src/assembly/webgpu-ready-per-pass.ts +104 -0
  446. package/src/assembly/webgpu-ready.ts +116 -62
  447. package/src/assembly/webgpu-renderer-bootstrap.ts +0 -12
  448. package/src/assembly/webgpu-renderer-observation-owner.ts +222 -0
  449. package/src/assembly/webgpu-renderer.ts +303 -313
  450. package/src/assembly/webgpu-vertex-layouts.ts +1 -1
  451. package/src/barrel-distortion.ts +247 -0
  452. package/src/cloud/__tests__/cloud-density-parity.dawn.test.ts +173 -0
  453. package/src/cloud/__tests__/cloud-layer-framebuffer-y.dawn.test.ts +265 -0
  454. package/src/cloud/__tests__/cloud-layer.browser.test.ts +432 -0
  455. package/src/cloud/__tests__/cloud-layer.unit.test.ts +634 -0
  456. package/src/cloud/density.ts +600 -0
  457. package/src/cloud/extract.ts +110 -0
  458. package/src/cloud/feature.ts +1810 -0
  459. package/src/cloud/frame-context.ts +42 -0
  460. package/src/cloud/inspection.ts +130 -0
  461. package/src/cloud/optics.ts +285 -0
  462. package/src/cloud/parameters.ts +255 -0
  463. package/src/cloud/resources.ts +122 -0
  464. package/src/cloud/shadow.ts +167 -0
  465. package/src/cloud/temporal.ts +226 -0
  466. package/src/components/barrel-distortion.ts +46 -0
  467. package/src/components/cloud-layer.ts +47 -0
  468. package/src/components/index.ts +2 -0
  469. package/src/components/instances.ts +18 -45
  470. package/src/components/sprite-instances.ts +1 -1
  471. package/src/construct-renderer.ts +1 -1
  472. package/src/device/gpu-residency.ts +26 -25
  473. package/src/dynamic-geometry.ts +12 -1
  474. package/src/errors/cloud.ts +103 -0
  475. package/src/errors/render.ts +47 -8
  476. package/src/examples/single-layer-medium-surface.ts +59 -0
  477. package/src/extract/camera.ts +15 -1
  478. package/src/extract/contracts.ts +5 -0
  479. package/src/extract/material-context.ts +21 -0
  480. package/src/features/barrel-distortion.ts +172 -0
  481. package/src/features/error-reporting.ts +26 -6
  482. package/src/features/host.ts +128 -19
  483. package/src/features/plan.ts +10 -0
  484. package/src/features/render-graph-contribution.ts +9 -0
  485. package/src/features/render-graph-raster.ts +45 -3
  486. package/src/features/targets.ts +66 -0
  487. package/src/features/types.ts +51 -0
  488. package/src/fullscreen-post-process-pass.ts +41 -9
  489. package/src/glyph-text-layout-system.ts +2 -2
  490. package/src/gpu-dirty-ranges.ts +48 -0
  491. package/src/gpu-driven/batch-topology.ts +53 -0
  492. package/src/gpu-driven/material-artifacts.ts +33 -25
  493. package/src/gpu-driven/prepared-draw.ts +12 -4
  494. package/src/gpu-driven/production-raster-material.ts +1894 -0
  495. package/src/gpu-driven/production-raster.ts +825 -784
  496. package/src/gpu-driven/resource-allocation.ts +142 -0
  497. package/src/gpu-driven/shadow-ownership.ts +71 -0
  498. package/src/gpu-driven/view-gpu.ts +164 -10
  499. package/src/gpu-scene.ts +75 -84
  500. package/src/hdrp-buffers.ts +4 -3
  501. package/src/ibl/frame-resources.ts +0 -1
  502. package/src/ibl/skylight-bind-group.ts +62 -32
  503. package/src/index.ts +205 -9
  504. package/src/inspection-types.ts +162 -0
  505. package/src/instance-buffer-cache.ts +4 -4
  506. package/src/instances.ts +152 -569
  507. package/src/pbr-pipeline.ts +230 -30
  508. package/src/pipeline/single-layer-medium-passes.ts +267 -0
  509. package/src/pipeline/standard-forward-lane.ts +313 -57
  510. package/src/pipeline/standard-output/graph.ts +8 -2
  511. package/src/pipeline/standard-output/lut-gpu.ts +3 -3
  512. package/src/pipeline/standard-output/resources.ts +2 -2
  513. package/src/pipeline/standard-output/types.ts +12 -1
  514. package/src/pipeline/standard-pipeline.ts +291 -18
  515. package/src/pipeline/standard-post.ts +90 -24
  516. package/src/pipeline-builder.ts +1 -1
  517. package/src/plugin.ts +4 -0
  518. package/src/points-lines/__tests__/points-lines.bench.ts +17 -8
  519. package/src/prepare/prepared-graphics-resolver.ts +2 -0
  520. package/src/publication/__tests__/derived-geometry.integration.test.ts +177 -0
  521. package/src/publication/__tests__/features.integration.test.ts +122 -0
  522. package/src/publication/__tests__/programs.unit.test.ts +25 -0
  523. package/src/publication/__tests__/publication.integration.test.ts +370 -0
  524. package/src/publication/__tests__/targets.integration.test.ts +120 -0
  525. package/src/publication/__tests__/video.browser.test.ts +50 -0
  526. package/src/publication/contract.ts +104 -0
  527. package/src/publication/dependencies.ts +54 -0
  528. package/src/publication/prepare-geometry.ts +94 -0
  529. package/src/publication/programs.ts +45 -0
  530. package/src/publication/publisher.ts +618 -0
  531. package/src/publication/receiver.ts +297 -0
  532. package/src/publication/resource-scope.ts +31 -0
  533. package/src/publication/targets.ts +182 -0
  534. package/src/publication/video.ts +33 -0
  535. package/src/record/__tests__/main-pass-geometry.unit.test.ts +30 -0
  536. package/src/record/__tests__/material-bg-cache.unit.test.ts +15 -1
  537. package/src/record/__tests__/sprite-material-abi.unit.test.ts +9 -11
  538. package/src/record/__tests__/temporal-payload.unit.test.ts +1 -1
  539. package/src/record/__tests__/transparent-group2-selection.unit.test.ts +11 -0
  540. package/src/record/__tests__/typed-frame-graph-plan.unit.test.ts +1 -0
  541. package/src/record/__tests__/video-texture-view.unit.test.ts +9 -9
  542. package/src/record/__tests__/view-ubo-layout.unit.test.ts +4 -3
  543. package/src/record/barrel-distortion-frame.ts +110 -0
  544. package/src/record/dynamic-geometry-consumption.ts +39 -9
  545. package/src/record/fold-buckets.ts +855 -0
  546. package/src/record/fold-instance-buffer.ts +51 -0
  547. package/src/record/frame-lighting.ts +36 -2
  548. package/src/record/frame-snapshot.ts +45 -9
  549. package/src/record/frame.ts +258 -1105
  550. package/src/record/gpu-draw-receipts.ts +38 -0
  551. package/src/record/gpu-timing.ts +48 -5
  552. package/src/record/helpers.ts +2 -2
  553. package/src/record/main-pass-geometry.ts +272 -84
  554. package/src/record/main-pass-material.ts +102 -36
  555. package/src/record/main-pass-sprite-draws.ts +13 -217
  556. package/src/record/main-pass.ts +164 -27
  557. package/src/record/motion-blur-receipt.ts +91 -0
  558. package/src/record/prepared-material-bindings.ts +11 -6
  559. package/src/record/probe-blend-buffer.ts +180 -0
  560. package/src/record/recovery-pipeline.ts +35 -3
  561. package/src/record/render-context.ts +41 -5
  562. package/src/record/shadow-pass.ts +30 -4
  563. package/src/record/skybox-post-pass.ts +28 -4
  564. package/src/record/sprite-instance-buffer.ts +155 -0
  565. package/src/record/target-capture-graph.ts +258 -0
  566. package/src/record/typed-frame-graph.ts +776 -340
  567. package/src/record/view-ubo.ts +27 -4
  568. package/src/record/volume-params.ts +225 -0
  569. package/src/recovery/render-system-candidate.ts +243 -50
  570. package/src/reflection/record-owner.ts +7 -3
  571. package/src/render-contract.ts +54 -5
  572. package/src/render-graph-primitives.ts +7 -1
  573. package/src/render-pipeline.ts +130 -0
  574. package/src/render-system-extract-tail.ts +90 -78
  575. package/src/render-system-extract.ts +76 -76
  576. package/src/render-system-presentation.ts +56 -0
  577. package/src/render-system-producer-roots.ts +96 -0
  578. package/src/render-system-projections.ts +3 -2
  579. package/src/render-system-residency.ts +159 -0
  580. package/src/render-system.ts +421 -408
  581. package/src/scene/probe-blend.ts +96 -4
  582. package/src/scene/render-scene.ts +416 -337
  583. package/src/scene/render-source.ts +90 -0
  584. package/src/scene/source-systems.ts +33 -0
  585. package/src/ssao-buffers.ts +95 -2
  586. package/src/surface/__tests__/dynamic-input.unit.test.ts +374 -0
  587. package/src/surface/__tests__/gpu-driven.unit.test.ts +87 -0
  588. package/src/surface/dynamic-input.ts +658 -0
  589. package/src/surface/gpu-driven.ts +147 -0
  590. package/src/surface/submission-observation.ts +517 -0
  591. package/src/systems/skin-palette-allocator.ts +5 -1
  592. package/src/systems/skin-palette-types.ts +11 -0
  593. package/src/systems/transparent-dispatch.ts +2 -2
  594. package/src/systems/transparent-sort-config.ts +3 -1
  595. package/src/temporal/gpu.ts +101 -17
  596. package/src/temporal/inspection.ts +7 -1
  597. package/src/temporal/standard-scene-data.ts +5 -0
  598. package/src/temporal/target-coverage-attachment.ts +4 -0
  599. package/src/transmission/__tests__/single-layer-medium.unit.test.ts +149 -0
  600. package/src/transmission/__tests__/standard-transmission.dawn.test.ts +12 -11
  601. package/src/transmission/single-layer-medium.ts +322 -0
  602. package/src/typed-render-graph-primitives.ts +70 -2
  603. package/src/volume/component.ts +10 -9
  604. package/src/volume/extract.ts +11 -5
  605. package/src/volume/inspection.ts +3 -0
  606. package/src/volume/passes.ts +87 -4
  607. package/src/volume/resources.ts +2 -1
  608. package/dist/chunk-3RTCJTH4.mjs +0 -1610
  609. package/dist/chunk-3RTCJTH4.mjs.map +0 -1
  610. package/dist/chunk-BLXGONR2.mjs.map +0 -1
  611. package/dist/chunk-ILQ5MEZF.mjs +0 -32
  612. package/dist/chunk-ILQ5MEZF.mjs.map +0 -1
  613. package/dist/chunk-LEAXOMYJ.mjs.map +0 -1
  614. package/dist/chunk-NB2S7ZRX.mjs +0 -1783
  615. package/dist/chunk-NB2S7ZRX.mjs.map +0 -1
  616. package/dist/chunk-NNQL7CB3.mjs +0 -1713
  617. package/dist/chunk-NNQL7CB3.mjs.map +0 -1
  618. package/dist/chunk-OO3DRYK7.mjs.map +0 -1
  619. package/dist/chunk-PA5DRJNI.mjs.map +0 -1
  620. package/dist/chunk-PLAXOOX5.mjs +0 -1907
  621. package/dist/chunk-PLAXOOX5.mjs.map +0 -1
  622. package/dist/chunk-RXZ3RGOU.mjs +0 -53
  623. package/dist/chunk-RXZ3RGOU.mjs.map +0 -1
  624. package/dist/chunk-VOZWDM3L.mjs.map +0 -1
@@ -1,38 +1,23 @@
1
1
  import { projectCaptureScene } from './capture/scene-projection';
2
+ import { renderMaterialContext } from './extract/material-context';
3
+ import { RenderPublicationError } from './publication/contract';
4
+ import { preparePublicationGeometry } from './publication/prepare-geometry';
5
+ import type { PreparedRenderPublication } from './publication/receiver';
6
+ import { type RenderResourceScope, renderTime } from './publication/resource-scope';
2
7
  import type { RenderSceneBounds } from './scene/render-scene-types';
3
- // @forgeax/engine-runtime - RenderSystem main entry (D-S2 three-stage Extract ->
4
- // Prepare -> Record + 4-tier error fan-out).
5
- //
6
- // Engine-internal phase: NOT registered to World schedule (AC-09);
7
- // `Renderer.draw([world], { cameraOwner: 0, resourceOwner: 0 })` invokes once per frame. See `Renderer` JSDoc in
8
- // `./render-contract.ts` for the public error/frame contract and AGENTS.md
9
- // "ECS render bridge" section for the AI-user-facing contract.
10
- //
11
- // Stage carve-out (review round 1 finding #3 - 505 line cap fallback):
12
- // - render-system.ts (this file) types + orchestration
13
- // - render-system-extract.ts Extract ECS query phase + snapshot helpers
14
- // - render-system-record.ts Prepare + Record GPU phase + matrix helpers
15
- //
16
8
  // @forgeax/engine-math is referenced through render-system-record.ts which builds
17
9
  // view/proj matrices and worldFromLocal via `mat4.compose / .multiply /
18
10
  // .invert` (charter proposition 5: no math reinvention; render-system.test.ts
19
11
  // asserts `/@forgeax\/engine-math/` shows up in render-system.ts source).
20
12
 
21
- import { numMipLevels, resolveAssetHandle } from '@forgeax/engine-assets-runtime';
22
- import { Time, type World } from '@forgeax/engine-ecs';
13
+ import { numMipLevels } from '@forgeax/engine-assets-runtime';
14
+ import type { World } from '@forgeax/engine-ecs';
23
15
  import type { RenderReadLease } from '@forgeax/engine-ecs/projection';
24
16
  import type { RecorderSession } from '@forgeax/engine-profiler';
25
17
  import type { CompiledRenderGraphInfo } from '@forgeax/engine-render-graph';
26
18
  import type { BindGroupLayout, Buffer, RenderPipeline, RhiDevice } from '@forgeax/engine-rhi';
27
19
  import { err, ok, type Result, RhiError } from '@forgeax/engine-rhi';
28
- import {
29
- deriveTextureLayout,
30
- type MaterialAsset,
31
- type RenderPipelineAsset,
32
- type SamplerAsset,
33
- type TextureAsset,
34
- toShared,
35
- } from '@forgeax/engine-types';
20
+ import { type Handle, type RenderPipelineAsset, toShared } from '@forgeax/engine-types';
36
21
  import {
37
22
  type DirectionalShadowInspectionSource,
38
23
  directionalShadowProfileFromQuality,
@@ -40,7 +25,9 @@ import {
40
25
  } from './assembly/directional-shadow-inspection';
41
26
  import { createGpuDrivenOwner } from './assembly/gpu-driven-owner';
42
27
  import { standardBloomAdmitted } from './bloom-admission';
28
+ import { createCloudFeatureFrameContext, createCloudFeatureView } from './cloud/frame-context';
43
29
  import { createClusterBinScratch } from './cluster-binner';
30
+ import type { DynamicGeometryRecordStageLane } from './dynamic-geometry';
44
31
  import { EnvironmentLifecycle } from './environment/lifecycle';
45
32
  import {
46
33
  type ObservationUnavailableError,
@@ -49,6 +36,7 @@ import {
49
36
  } from './errors/render';
50
37
  import { projectDepthOfFieldInspection } from './features/depth-of-field/depth-of-field-inspection';
51
38
  import { resolveDepthOfFieldFrameParams } from './features/depth-of-field/depth-of-field-params';
39
+ import type { PendingRenderFeatureErrorReport } from './features/error-reporting';
52
40
  import { reportPendingRenderFeatureErrors } from './features/error-reporting';
53
41
  import {
54
42
  type RenderFeaturePreparedGraphicsResolverInput,
@@ -83,6 +71,7 @@ import {
83
71
  postProcessShaderPipelineLabel,
84
72
  } from './fullscreen-post-process-pass';
85
73
  import type {
74
+ BarrelDistortionInspection,
86
75
  BloomInspection,
87
76
  DepthOfFieldInspection,
88
77
  DirectionalShadowInspection,
@@ -125,11 +114,7 @@ import {
125
114
  } from './pipeline/standard-output/resources';
126
115
  import type { PointsLinesRetainedSnapshot } from './points-lines/snapshot';
127
116
  import { StandardPointsLinesOwner } from './points-lines/standard-owner';
128
- import {
129
- createRenderSystemRecovery,
130
- materialSamplerHandles,
131
- materialTextureHandles,
132
- } from './recovery/render-system-candidate';
117
+ import { createRenderSystemRecovery } from './recovery/render-system-candidate';
133
118
 
134
119
  export { materialTextureHandlesForResidency } from './recovery/render-system-candidate';
135
120
 
@@ -169,9 +154,10 @@ import { inspectVolumetricFog } from './volume/inspection';
169
154
 
170
155
  export type { RenderSceneInspection } from './inspection-types';
171
156
 
157
+ import type { BarrelDistortionMapping } from './barrel-distortion';
172
158
  import { createCubeCaptureScheduler } from './capture/scheduler';
173
159
  import type { EnvironmentInspection } from './environment/inspection';
174
- import { gpuDrivenShadowDrawKey } from './extract/gpu-driven';
160
+ import { rebaseShadowCasterOwnership } from './gpu-driven/shadow-ownership';
175
161
  import { GPU_BUFFER_USAGE_COPY_DST, GPU_BUFFER_USAGE_UNIFORM } from './gpu-usage';
176
162
  import { resetHdrpBuffers } from './hdrp-buffers';
177
163
  import type { SkylightBindGroupResources } from './ibl/skylight-bind-group';
@@ -181,11 +167,9 @@ import {
181
167
  disposeTransientInstanceBuffers,
182
168
  } from './instance-buffer-cache';
183
169
  import type { InstanceCollectionInspection } from './instances';
184
- import { InstanceCollectionStore } from './instances';
170
+ import { InstanceProjectionStore } from './instances';
185
171
  import {
186
172
  type MeshMaterialBindingObservation,
187
- type MeshMaterialBindingPreparationFailure,
188
- type MeshMaterialBindingResidency,
189
173
  projectMeshMaterialBindingObservation,
190
174
  } from './mesh-material-bindings';
191
175
  import type { StandardLightingInspection } from './pipeline/standard-lighting/inspection';
@@ -198,6 +182,10 @@ import {
198
182
  createPreparedGraphicsResolver,
199
183
  type PreparedGraphicsResolver,
200
184
  } from './prepare/prepared-graphics-resolver';
185
+ import {
186
+ inspectBarrelDistortionState,
187
+ resetBarrelDistortionGraphState,
188
+ } from './record/barrel-distortion-frame';
201
189
  import {
202
190
  type CubeCaptureFrameInput,
203
191
  type FrameObservation,
@@ -213,6 +201,7 @@ import type {
213
201
  RenderFrameState,
214
202
  } from './record/frame-snapshot';
215
203
  import { getTextureIdentity, worldEntityKey } from './record/frame-snapshot';
204
+ import type { RenderableDrawReceipt } from './record/gpu-draw-receipts';
216
205
  import type { GpuPassTimingReason } from './record/gpu-pass-timing/errors';
217
206
  import type {
218
207
  GpuPassTimingCapture,
@@ -230,34 +219,39 @@ import type { PipelineState, RenderSystemInternals } from './record/render-conte
230
219
  import type { CubeCaptureGraphState } from './record/typed-frame-graph';
231
220
  import {
232
221
  getRenderFeatureGraphInspection,
222
+ inspectRenderGraphGenerationAllocation,
233
223
  type RenderFeatureGraphCandidate,
234
224
  recordRenderFeatureCandidate,
235
225
  resetRenderFeatureGraphState,
226
+ retire as retireCompiledGraph,
227
+ settleBarrelDistortionGraphCandidate,
236
228
  settleDepthOfFieldGraphCandidate,
237
229
  settleVolumetricFogGraphCandidate,
238
230
  } from './record/typed-frame-graph';
239
231
  import {
240
232
  type CameraSnapshot,
241
233
  type DrawOwnerOptions,
234
+ type FramePresentation,
242
235
  RENDER_PHASE_CATALOG,
243
236
  type RenderPhase,
244
237
  type RenderPhaseSkipReason,
245
238
  type RenderRecordPhase,
246
239
  } from './render-contract';
247
- import type {
248
- DispatchEntry,
249
- ExtractedLights,
250
- MaterialSnapshot,
251
- RenderableSnapshot,
252
- ShadowCasterMembership,
253
- } from './render-system-extract';
240
+ import type { DispatchEntry, ExtractedLights, RenderableSnapshot } from './render-system-extract';
254
241
  import { extractFrames } from './render-system-extract';
242
+ import { projectFramePresentation } from './render-system-presentation';
243
+ import {
244
+ createRendererProducerRootMatrix,
245
+ type RendererProducerRoot,
246
+ } from './render-system-producer-roots';
255
247
  import {
256
248
  canonicalizeWorldComposition,
257
249
  createLodWorldInspections,
258
250
  } from './render-system-projections';
251
+ import { observeMaterialResidency } from './render-system-residency';
259
252
  import { PersistentRenderScene } from './scene/render-scene';
260
253
  import { inspectLodOcclusion } from './scene/visibility/inspection';
254
+ import { resetSsaoResources } from './ssao-buffers';
261
255
  import { resolveSsaoParameters } from './ssao-config';
262
256
  import {
263
257
  projectSsrDependencies,
@@ -266,6 +260,8 @@ import {
266
260
  zeroSsrAdmissionWork,
267
261
  } from './ssr/admission';
268
262
  import { projectSsrSpatialInspection } from './ssr/inspection';
263
+ import type { SurfaceDynamicInputFrame } from './surface/dynamic-input';
264
+ import { SurfaceSubmissionObservationOwner } from './surface/submission-observation';
269
265
  import { sortTransparentDispatch } from './systems/transparent-dispatch';
270
266
  import type { RenderTarget } from './targets/contracts';
271
267
  import { createTemporalFrameTransaction, type TemporalFrame } from './temporal/frame';
@@ -283,73 +279,6 @@ import {
283
279
  inspectTransmissionFromAdmission,
284
280
  } from './transmission/inspection';
285
281
 
286
- const WORLD_ENTITY_KEY_STRIDE = 4294967296;
287
-
288
- /**
289
- * Extract emits world/entity keys in the transient `worlds[]` index domain,
290
- * while PersistentRenderScene owns stable renderer-local World keys for the
291
- * retained GPU scene. Rebase ShadowCaster ownership at this orchestration
292
- * boundary before both GPU projection and CPU residual recording consume it.
293
- */
294
- function rebaseShadowCasterOwnership(
295
- worlds: readonly World[],
296
- stableWorldKeys: readonly number[],
297
- entityKeys: ReadonlySet<number>,
298
- drawKeys: ReadonlySet<string>,
299
- membership: readonly ShadowCasterMembership[] | undefined,
300
- ): {
301
- readonly entityKeys: ReadonlySet<number>;
302
- readonly drawKeys: ReadonlySet<string>;
303
- readonly membership: readonly ShadowCasterMembership[] | undefined;
304
- } {
305
- const rebaseWorldEntity = (composite: number): number => {
306
- const transientWorldId = Math.floor(composite / WORLD_ENTITY_KEY_STRIDE);
307
- if (
308
- !Number.isInteger(transientWorldId) ||
309
- transientWorldId < 0 ||
310
- transientWorldId >= worlds.length
311
- ) {
312
- return composite;
313
- }
314
- const entityKey = composite - transientWorldId * WORLD_ENTITY_KEY_STRIDE;
315
- return worldEntityKey(stableWorldKeys[transientWorldId] ?? transientWorldId, entityKey);
316
- };
317
-
318
- const stableMembership =
319
- membership === undefined
320
- ? undefined
321
- : membership.map((entry) => ({
322
- ...entry,
323
- worldEntity: rebaseWorldEntity(entry.worldEntity),
324
- }));
325
- const stableDrawKeys =
326
- stableMembership === undefined
327
- ? new Set(
328
- [...drawKeys].map((key) => {
329
- const parts = key.split(':');
330
- if (parts.length !== 4) return key;
331
- const transientWorldEntity = Number(parts[0]);
332
- if (!Number.isFinite(transientWorldEntity)) return key;
333
- return `${rebaseWorldEntity(transientWorldEntity)}:${parts[1]}:${parts[2]}:${parts[3]}`;
334
- }),
335
- )
336
- : new Set(
337
- stableMembership.map((entry) =>
338
- gpuDrivenShadowDrawKey(
339
- entry.worldEntity,
340
- entry.materialHandle,
341
- entry.drawItemIndex,
342
- entry.passIndex,
343
- ),
344
- ),
345
- );
346
- return {
347
- entityKeys: new Set([...entityKeys].map(rebaseWorldEntity)),
348
- drawKeys: stableDrawKeys,
349
- membership: stableMembership,
350
- };
351
- }
352
-
353
282
  type TimingSessionHost = RenderSystemInternals & {
354
283
  gpuPassTimingSession?: GpuPassTimingSession | undefined;
355
284
  gpuPassTimingCapture?: GpuPassTimingCapture | undefined;
@@ -386,102 +315,11 @@ export {
386
315
  selectSwapChainFormat,
387
316
  } from './record/render-context';
388
317
 
389
- export type RendererProducerRootKind =
390
- | 'backend-surface'
391
- | 'shader-material-pipeline'
392
- | 'mesh-texture-sampler'
393
- | 'render-scene'
394
- | 'gpu-driven'
395
- | 'feature'
396
- | 'external-source'
397
- | 'render-graph'
398
- | 'target-history'
399
- | 'observation-lease';
400
-
401
- export interface RendererProducerRoot {
402
- readonly kind: RendererProducerRootKind;
403
- readonly owner: string;
404
- readonly candidateScope: 'device-scope';
405
- readonly visibility: 'visible-workset' | 'non-visible-lazy';
406
- readonly disabledWork: 'zero' | 'lazy';
407
- }
408
-
409
- const PRODUCER_ROOT_MATRIX: readonly RendererProducerRoot[] = Object.freeze([
410
- {
411
- kind: 'backend-surface',
412
- owner: 'backend-surface-owner',
413
- candidateScope: 'device-scope',
414
- visibility: 'visible-workset',
415
- disabledWork: 'zero',
416
- },
417
- {
418
- kind: 'shader-material-pipeline',
419
- owner: 'shader-material-pipeline-owner',
420
- candidateScope: 'device-scope',
421
- visibility: 'visible-workset',
422
- disabledWork: 'zero',
423
- },
424
- {
425
- kind: 'mesh-texture-sampler',
426
- owner: 'gpu-residency',
427
- candidateScope: 'device-scope',
428
- visibility: 'visible-workset',
429
- disabledWork: 'lazy',
430
- },
431
- {
432
- kind: 'render-scene',
433
- owner: 'persistent-render-scene',
434
- candidateScope: 'device-scope',
435
- visibility: 'visible-workset',
436
- disabledWork: 'zero',
437
- },
438
- {
439
- kind: 'gpu-driven',
440
- owner: 'gpu-driven-production',
441
- candidateScope: 'device-scope',
442
- visibility: 'visible-workset',
443
- disabledWork: 'zero',
444
- },
445
- {
446
- kind: 'feature',
447
- owner: 'render-feature-host',
448
- candidateScope: 'device-scope',
449
- visibility: 'visible-workset',
450
- disabledWork: 'lazy',
451
- },
452
- {
453
- kind: 'external-source',
454
- owner: 'external-source-owner',
455
- candidateScope: 'device-scope',
456
- visibility: 'non-visible-lazy',
457
- disabledWork: 'zero',
458
- },
459
- {
460
- kind: 'render-graph',
461
- owner: 'typed-frame-graph',
462
- candidateScope: 'device-scope',
463
- visibility: 'visible-workset',
464
- disabledWork: 'zero',
465
- },
466
- {
467
- kind: 'target-history',
468
- owner: 'temporal-target-owner',
469
- candidateScope: 'device-scope',
470
- visibility: 'visible-workset',
471
- disabledWork: 'zero',
472
- },
473
- {
474
- kind: 'observation-lease',
475
- owner: 'render-observation-owner',
476
- candidateScope: 'device-scope',
477
- visibility: 'non-visible-lazy',
478
- disabledWork: 'zero',
479
- },
480
- ]);
481
-
482
- export function createRendererProducerRootMatrix(): readonly RendererProducerRoot[] {
483
- return PRODUCER_ROOT_MATRIX;
484
- }
318
+ export type {
319
+ RendererProducerRoot,
320
+ RendererProducerRootKind,
321
+ } from './render-system-producer-roots';
322
+ export { createRendererProducerRootMatrix } from './render-system-producer-roots';
485
323
 
486
324
  /**
487
325
  * Production-owned recovery facts. These values are projections of the live
@@ -520,6 +358,8 @@ export interface RecoveryProductionEvidence {
520
358
  */
521
359
  export interface RenderSystem {
522
360
  bounds(world: World, entity: number): RenderSceneBounds | undefined;
361
+ /** Publish one renderer-owned read-only Surface dynamic page for the next frame. */
362
+ setSurfaceDynamicInput(frame: SurfaceDynamicInputFrame | undefined): void;
523
363
  /** Complete explicit SSR capability preparation before drawing a device generation. */
524
364
  initializeSsr(device?: RhiDevice): Promise<void>;
525
365
  /** Returns true only when this invocation reached queue submission. */
@@ -528,6 +368,7 @@ export interface RenderSystem {
528
368
  opts: DrawOwnerOptions,
529
369
  renderReadLeases?: readonly RenderReadLease[],
530
370
  timingCapture?: GpuTimingCapture,
371
+ publication?: PreparedRenderPublication,
531
372
  ): boolean;
532
373
  /**
533
374
  * Return the asset binding consumed by the last successful record pass.
@@ -535,6 +376,11 @@ export interface RenderSystem {
535
376
  * barrier; ECS component presence alone is not a draw receipt.
536
377
  */
537
378
  isDynamicGeometryConsumed(world: World, entity: number, meshHandle: number | undefined): boolean;
379
+ dynamicGeometryRecordStageLane(
380
+ world: World,
381
+ entity: number,
382
+ meshHandle: number | undefined,
383
+ ): DynamicGeometryRecordStageLane | undefined;
538
384
  invalidateGeometryHistory(): void;
539
385
  /** Prepare a detached graph candidate without entering the frame record path. */
540
386
  prepareRecoveryGraphCandidate(
@@ -568,8 +414,6 @@ export interface RenderSystem {
568
414
  readonly pipelineDispatchCounts: {
569
415
  readonly unlit: number;
570
416
  };
571
- /** Renderer-owned source for explicit large instance collections. */
572
- readonly instances: InstanceCollectionStore;
573
417
  /** Detached residency and upload facts for explicit instance collections. */
574
418
  readonly instanceCollectionsInspection: readonly InstanceCollectionInspection[];
575
419
  /**
@@ -588,6 +432,8 @@ export interface RenderSystem {
588
432
  readonly ssr: SsrSpatialInspection;
589
433
  /** Producer completion fence included in the public FrameReceipt. */
590
434
  readonly reflectionFallbackCompletion: Promise<void> | undefined;
435
+ /** Presentation readiness derived from the producer facts used by draw(). */
436
+ readonly presentation: FramePresentation;
591
437
  /** True while a progressive CubeCamera candidate still owns unfinished faces. */
592
438
  isCubeCapturePending(target: RenderTarget): boolean;
593
439
  readonly environment: EnvironmentInspection;
@@ -630,8 +476,14 @@ export interface RenderSystem {
630
476
  readonly perFramePassNames: readonly string[];
631
477
  /** Camera antialias mode for the last successfully submitted frame. */
632
478
  readonly lastSuccessfulCameraAntialias: CameraSnapshot['antialias'] | undefined;
479
+ /** Effective output mapping for the last successfully submitted camera. */
480
+ readonly lastSuccessfulBarrelDistortion: BarrelDistortionMapping | undefined;
481
+ /** Detached accepted/LKG projection for Renderer.inspect(). */
482
+ readonly barrelDistortionInspection: BarrelDistortionInspection;
633
483
  /** Detached compiled-graph facts used by the renderer inspection owner. */
634
484
  readonly perFrameGraphInfo: CompiledRenderGraphInfo | undefined;
485
+ /** Detached allocation facts across active, candidate, and retiring graphs. */
486
+ readonly renderGraphGenerationAllocation: import('@forgeax/engine-render-graph').RenderGraphGenerationAllocationInspection;
635
487
  /** Detached feature signature/compile/lifetime counters. */
636
488
  readonly featureGraphInspection: import('./inspection-types').RenderFeatureGraphInspection;
637
489
  /** Detached material texture-source probe counters from the last extract. */
@@ -751,149 +603,6 @@ function makePreparedPipelinePendingError(): RhiError {
751
603
  });
752
604
  }
753
605
 
754
- function preparationFailureFrom(error: unknown): MeshMaterialBindingPreparationFailure | undefined {
755
- if (typeof error !== 'object' || error === null) return undefined;
756
- const value = error as {
757
- readonly code?: unknown;
758
- readonly expected?: unknown;
759
- readonly hint?: unknown;
760
- readonly detail?: unknown;
761
- };
762
- if (
763
- typeof value.code !== 'string' ||
764
- typeof value.expected !== 'string' ||
765
- typeof value.hint !== 'string'
766
- ) {
767
- return undefined;
768
- }
769
- const detail =
770
- typeof value.detail === 'object' && value.detail !== null
771
- ? { ...(value.detail as Record<string, unknown>) }
772
- : undefined;
773
- return {
774
- code: value.code,
775
- expected: value.expected,
776
- hint: value.hint,
777
- ...(detail === undefined ? {} : { detail }),
778
- };
779
- }
780
-
781
- /**
782
- * Project the producer-owned material and GPU store state into the one
783
- * renderer observation surface. This is intentionally recomputed from the
784
- * current frame's detached material snapshots; no readiness map is retained
785
- * by RenderSystem. A producer failure with an already resident resource is
786
- * reported as last-known-good, preserving recovery context without copying
787
- * the producer's lifecycle state.
788
- */
789
- function observeMaterialResidency(
790
- world: World | undefined,
791
- material: MaterialSnapshot,
792
- internals: RenderSystemInternals,
793
- ): MeshMaterialBindingResidency {
794
- const textures: Array<{ readonly handle: number; readonly mipLevelCount: number }> = [];
795
- const samplers: Array<{ readonly handle: number; readonly resident: boolean }> = [];
796
- let pending = false;
797
- let resident = false;
798
- let failure: MeshMaterialBindingPreparationFailure | undefined;
799
- const keepFailure = (error: unknown): void => {
800
- if (failure === undefined) failure = preparationFailureFrom(error);
801
- };
802
-
803
- if (world === undefined) {
804
- pending = true;
805
- } else {
806
- const materialHandle = material.materialHandle;
807
- if (materialHandle !== undefined && materialHandle !== 0) {
808
- const materialResult = resolveAssetHandle<MaterialAsset>(
809
- world,
810
- toShared<'MaterialAsset'>(materialHandle),
811
- );
812
- if (!materialResult.ok) {
813
- keepFailure(materialResult.error);
814
- } else {
815
- const guid = internals.assets.guidOf(materialResult.value);
816
- if (guid !== undefined) {
817
- const readiness = internals.assets.getMaterialReadiness(guid);
818
- if (readiness?.status === 'Error') keepFailure(readiness.error);
819
- const load = internals.assets.loadState.get(guid);
820
- if (load?.status === 'provisional') pending = true;
821
- }
822
- }
823
- }
824
-
825
- for (const handle of materialTextureHandles(material)) {
826
- const existing = internals.gpuStore.getTextureGpuView(handle, world);
827
- const pod = resolveAssetHandle<TextureAsset>(world, handle);
828
- if (!pod.ok) {
829
- keepFailure(pod.error);
830
- continue;
831
- }
832
- let view = existing;
833
- if (view === undefined) {
834
- const prepared = internals.gpuStore.ensureResident(handle, pod.value, world);
835
- if (!prepared.ok) keepFailure(prepared.error);
836
- view = internals.gpuStore.getTextureGpuView(handle, world);
837
- }
838
- if (view === undefined) {
839
- pending = failure === undefined;
840
- continue;
841
- }
842
- const textureLayout = deriveTextureLayout({
843
- shape: pod.value.shape,
844
- format: pod.value.format,
845
- mips: pod.value.mips,
846
- });
847
- if (!textureLayout.ok) {
848
- keepFailure(textureLayout.error);
849
- continue;
850
- }
851
- resident = true;
852
- textures.push({
853
- handle: Number(handle),
854
- mipLevelCount: Math.max(1, textureLayout.value.levels.length),
855
- });
856
- }
857
-
858
- for (const handle of materialSamplerHandles(material)) {
859
- const pod = resolveAssetHandle<SamplerAsset>(world, handle);
860
- if (!pod.ok) {
861
- keepFailure(pod.error);
862
- samplers.push({ handle: Number(handle), resident: false });
863
- continue;
864
- }
865
- const prepared = internals.gpuStore.ensureSamplerResident(handle, pod.value, world);
866
- if (!prepared.ok) {
867
- keepFailure(prepared.error);
868
- samplers.push({ handle: Number(handle), resident: false });
869
- } else {
870
- resident = true;
871
- samplers.push({ handle: Number(handle), resident: true });
872
- }
873
- }
874
- // Video views are supplied by the dynamic host store at record time. They
875
- // are not static TextureAsset residents, so this bounded projection stays
876
- // pending until a dynamic observation contract exists rather than guessing
877
- // from the VideoAsset GUID.
878
- if ((material.videoTextureFields?.size ?? 0) > 0) pending = true;
879
- }
880
-
881
- const readiness =
882
- failure === undefined
883
- ? pending
884
- ? 'pending'
885
- : 'ready'
886
- : resident
887
- ? 'last-known-good'
888
- : 'failed';
889
- return {
890
- readiness,
891
- samplers,
892
- textures,
893
- ...(failure === undefined ? {} : { preparationFailure: failure }),
894
- };
895
- }
896
-
897
606
  export function createRenderSystem(internals: RenderSystemInternals): RenderSystem {
898
607
  const phaseCatalogRegistration = internals.profiler?.registerPhaseCatalog(
899
608
  'render',
@@ -901,7 +610,7 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
901
610
  );
902
611
  let releaseProfilerCatalog =
903
612
  phaseCatalogRegistration?.ok === true ? phaseCatalogRegistration.value : undefined;
904
- let preparedWorlds: readonly World[] = [];
613
+ let preparedWorlds: readonly RenderResourceScope[] = [];
905
614
  const resolveFeatureNoise = createFeatureNoiseResolver({
906
615
  scope: internals.deviceScope,
907
616
  getDevice: () => internals.device,
@@ -909,6 +618,7 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
909
618
  });
910
619
  let preparedFeatureSkylightResources: SkylightBindGroupResources | undefined;
911
620
  const dynamicGeometryFrames = createDynamicGeometryFrameBindings();
621
+ let surfaceDynamicInputFrame: SurfaceDynamicInputFrame | undefined;
912
622
  let latestCamera: CameraSnapshot | undefined;
913
623
  // Last public parameter failure; cleared only after a valid extraction.
914
624
  let lastMotionBlurInvalidParams: MotionBlurValidationError | undefined;
@@ -929,7 +639,7 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
929
639
  if (!installed.ok) internals.errorRegistry.fire(installed.error);
930
640
  };
931
641
  const pointsLinesOwner = new StandardPointsLinesOwner(internals);
932
- const instanceCollections = new InstanceCollectionStore();
642
+ const instanceCollections = new InstanceProjectionStore();
933
643
  const reflectionProbeOwner = new ReflectionProbeRecordOwner(internals);
934
644
  const ssrFormatReceipts = new WeakMap<
935
645
  RhiDevice,
@@ -957,7 +667,7 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
957
667
  const persistentRenderScene = new PersistentRenderScene({
958
668
  getDevice: () => internals.device,
959
669
  onGpuError: (error) => internals.errorRegistry.fire(error),
960
- onSharedRefMutation: (worldId, handle) => {
670
+ onRuntimeAssetChange: (worldId, handle) => {
961
671
  internals.gpuStore.invalidateMesh(handle, preparedWorlds[worldId] ?? worldId);
962
672
  },
963
673
  instanceCollections,
@@ -1105,6 +815,9 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
1105
815
  ),
1106
816
  } satisfies import('./pipeline-builder').PipelineBuilderShaderModuleFactory);
1107
817
  let gpuDrivenRecoveryCount = 0;
818
+ const surfaceSubmissionObservation = new SurfaceSubmissionObservationOwner(
819
+ () => internals.deviceScope.generation,
820
+ );
1108
821
  let gpuDrivenProduction = createGpuDrivenOwner(
1109
822
  internals.device,
1110
823
  gpuDrivenShaderFactory,
@@ -1176,6 +889,7 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
1176
889
  // raw (material-handle-based, cross-world collision semantically correct).
1177
890
  const frameState: RenderFrameState = {
1178
891
  frameNumber: 0,
892
+ surfaceSubmissionObservation: undefined,
1179
893
  reflectionFallbackDemand: false,
1180
894
  ssrRequested: false,
1181
895
  ssrSpatialAdmission: undefined,
@@ -1203,6 +917,13 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
1203
917
  depthOfFieldCandidateGraph: null,
1204
918
  depthOfFieldAccepted: undefined,
1205
919
  depthOfFieldLastSubmitFailed: false,
920
+ barrelDistortionPreviousGraph: null,
921
+ barrelDistortionPreviousGraphKey: null,
922
+ barrelDistortionPreviousPerFrameGraph: undefined,
923
+ barrelDistortionPreviousGraphGeneration: 0,
924
+ barrelDistortionPreviousCompiledGraphGeneration: 0,
925
+ barrelDistortionPreviousStandardLightingGraphSignature: '',
926
+ barrelDistortionCandidateGraph: null,
1206
927
  volumetricFogPreviousGraph: null,
1207
928
  volumetricFogPreviousGraphKey: null,
1208
929
  volumetricFogCandidateGraph: null,
@@ -1221,6 +942,8 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
1221
942
  currentFrameObservationSource: undefined,
1222
943
  reflectionFallbackObservationSource: undefined,
1223
944
  lastSuccessfulCameraAntialias: undefined,
945
+ lastSuccessfulBarrelDistortion: undefined,
946
+ barrelDistortionGraphResolution: 'accepted',
1224
947
  temporalGpuState: undefined,
1225
948
  autoExposureGpuResources: undefined,
1226
949
  pendingAutoExposureGpuResources: undefined,
@@ -1326,7 +1049,7 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
1326
1049
  // publish the same transient failure on every render tick. Keep one
1327
1050
  // renderer-owned cooldown per structured feature failure while retaining
1328
1051
  // the original error for the first and periodic reports.
1329
- const pendingFeatureErrorLastReportedFrame = new Map<string, number>();
1052
+ const pendingFeatureErrorLastReportedFrame = new Map<string, PendingRenderFeatureErrorReport>();
1330
1053
  const resolveSsrDependencies = (requested: boolean): SsrDependenciesInspection => {
1331
1054
  // Explicit SSR capability preparation belongs to initialization. Inspection
1332
1055
  // only projects receipts and never starts work or creates image history.
@@ -1532,7 +1255,7 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
1532
1255
  const invalidatePostProcessModule = (id: string): void => {
1533
1256
  const entry = lookupPostProcess(id);
1534
1257
  if (entry !== undefined) {
1535
- internals.invalidateShaderModule?.(postProcessShaderModuleLabel(id, entry.source));
1258
+ internals.invalidateShaderModule?.(postProcessShaderModuleLabel(entry.source));
1536
1259
  }
1537
1260
  };
1538
1261
  // feat-20260621 M-A2 / w8: expose the eager-created per-id params UBO through
@@ -1622,6 +1345,11 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
1622
1345
  if (!destroyed.ok) internals.errorRegistry.fire(destroyed.error);
1623
1346
  }
1624
1347
  };
1348
+ const disposeActivePostProcessResources = (): void => {
1349
+ const resources = { device: postProcessParamsDevice, paramsBuffers: postProcessParamsBuffers };
1350
+ postProcessParamsBuffers = new Map();
1351
+ disposePostProcessResources(resources);
1352
+ };
1625
1353
  const preparePostProcessParamsResources = (
1626
1354
  featureEntries: ReadonlyMap<string, PostProcessShaderEntry>,
1627
1355
  ): Result<PostProcessParamsCandidate, RhiError> => {
@@ -1775,7 +1503,7 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
1775
1503
  let orderedDispatchCache:
1776
1504
  | {
1777
1505
  readonly source: readonly DispatchEntry[];
1778
- readonly world: World;
1506
+ readonly world: RenderResourceScope;
1779
1507
  readonly camera: readonly CameraSnapshot[];
1780
1508
  readonly renderables: readonly RenderableSnapshot[];
1781
1509
  readonly value: readonly DispatchEntry[];
@@ -1901,11 +1629,12 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
1901
1629
  };
1902
1630
  let lastMeshMaterialBindings: readonly MeshMaterialBindingObservation[] = [];
1903
1631
  let lastMeshMaterialBindingRenderables: readonly RenderableSnapshot[] | undefined;
1632
+ let lastPresentation: FramePresentation = 'pending';
1904
1633
  const createPreparedResolverFactory =
1905
1634
  (
1906
1635
  runtime: RenderSystemInternals,
1907
1636
  gpuWork: RenderFeatureGpuWorkOwner,
1908
- worlds: readonly World[],
1637
+ worlds: readonly RenderResourceScope[],
1909
1638
  caches: PreparedResolverCaches,
1910
1639
  ) =>
1911
1640
  (input: RenderFeaturePreparedGraphicsResolverInput): PreparedGraphicsResolver => {
@@ -2064,6 +1793,17 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
2064
1793
  ) {
2065
1794
  return err(new Error('prepared scene-depth pipeline requires a scene target'));
2066
1795
  }
1796
+ // The typed graph composes fullscreen feature bindings from its
1797
+ // current graph views and post-process parameter snapshot at encode
1798
+ // time. Do not manufacture a fallback bind group here: during
1799
+ // registration/recovery its params buffer can still be absent, and
1800
+ // a two-entry fallback cannot satisfy a params-aware layout.
1801
+ if (
1802
+ preparedPipelineIds.has(pipeline as object) &&
1803
+ descriptor.values.fullscreen === true
1804
+ ) {
1805
+ return ok(undefined);
1806
+ }
2067
1807
  if (preparedGroup0Pipelines.has(pipeline as object)) {
2068
1808
  const layout =
2069
1809
  (materialShaderId === undefined
@@ -2201,10 +1941,12 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
2201
1941
  createPreparedResolverCaches,
2202
1942
  });
2203
1943
  return {
2204
- instances: instanceCollections,
1944
+ setSurfaceDynamicInput(frame: SurfaceDynamicInputFrame | undefined): void {
1945
+ surfaceDynamicInputFrame = frame;
1946
+ },
2205
1947
  initializeSsr: ensureSsrFormatProbe,
2206
1948
  get instanceCollectionsInspection(): readonly InstanceCollectionInspection[] {
2207
- return instanceCollections._inspections();
1949
+ return instanceCollections._inspections(frameState.frameNumber - 1);
2208
1950
  },
2209
1951
  releaseProfilerCatalog(): void {
2210
1952
  releaseProfilerCatalog?.();
@@ -2217,9 +1959,11 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
2217
1959
  return persistentRenderScene.bounds(world, entity);
2218
1960
  },
2219
1961
  get renderScene(): RenderSceneInspection {
1962
+ const submission = surfaceSubmissionObservation.inspect();
2220
1963
  return {
2221
1964
  ...persistentRenderScene.inspect(),
2222
1965
  gpuDriven: gpuDrivenProduction.inspect(),
1966
+ ...(submission === undefined ? {} : { submission }),
2223
1967
  };
2224
1968
  },
2225
1969
  get gpuDrivenInspection(): GpuDrivenProductionInspection {
@@ -2274,6 +2018,9 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
2274
2018
  get reflectionFallbackCompletion(): Promise<void> | undefined {
2275
2019
  return frameState.reflectionFallbackCompletion;
2276
2020
  },
2021
+ get presentation(): FramePresentation {
2022
+ return lastPresentation;
2023
+ },
2277
2024
  isCubeCapturePending(target: RenderTarget): boolean {
2278
2025
  return cubeCaptureScheduler.inspect(target).candidateGeneration !== undefined;
2279
2026
  },
@@ -2457,14 +2204,21 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
2457
2204
  opts: DrawOwnerOptions,
2458
2205
  renderReadLeases?: readonly RenderReadLease[],
2459
2206
  timingCapture?: GpuTimingCapture,
2207
+ publication?: PreparedRenderPublication,
2460
2208
  ): boolean {
2461
2209
  const composition = canonicalizeWorldComposition(worlds, opts, renderReadLeases);
2462
- const compositionWorlds = composition.worlds;
2210
+ const sourceWorlds = composition.worlds;
2211
+ const compositionWorlds: readonly RenderResourceScope[] =
2212
+ publication === undefined ? sourceWorlds : [publication.resources];
2463
2213
  const compositionLeases = composition.leases;
2464
2214
  preparedWorlds = compositionWorlds;
2465
2215
  const profileSession = internals.profiler?.activeSession();
2466
2216
  let ownsProfileFrame = false;
2467
2217
  let submitted = false;
2218
+ // A failed draw cannot publish a startup completion fact. Reset the
2219
+ // projection before extraction so a later receipt never reuses an old
2220
+ // scene's readiness.
2221
+ lastPresentation = 'pending';
2468
2222
  // A prior failed record/submit may have staged a temporal capture. A
2469
2223
  // capture belongs only to the draw call that created it; discard it
2470
2224
  // before this call can prepare or commit a new candidate.
@@ -2495,21 +2249,45 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
2495
2249
  // so a hot-swap cannot reuse passes compiled for the retired pipeline.
2496
2250
  resetRenderFeatureGraphState(internals);
2497
2251
  lastBuiltPipelineHandle = frameState.installedPipelineHandle;
2498
- persistentRenderScene.invalidate();
2252
+ if (publication === undefined) persistentRenderScene.invalidate();
2499
2253
  }
2500
2254
  dispatchCounts.unlit = 0;
2501
2255
 
2502
- const resourceWorld = compositionWorlds[resourceOwner] as World;
2256
+ const resourceWorld = compositionWorlds[resourceOwner] as RenderResourceScope;
2503
2257
  let frame: ReturnType<PersistentRenderScene['extractComposition']>;
2504
2258
  try {
2505
2259
  frame = runProfiledRenderPhase(profileSession, 'extract', () => {
2260
+ if (publication !== undefined) {
2261
+ for (const handle of [
2262
+ ...publication.packet.invalidatedAssets,
2263
+ ...publication.packet.retiredAssets,
2264
+ ]) {
2265
+ internals.gpuStore.invalidateMesh(handle, publication.resources);
2266
+ internals.gpuStore.evictTexture(
2267
+ handle as Handle<'TextureAsset', 'shared'>,
2268
+ publication.resources,
2269
+ );
2270
+ }
2271
+ return persistentRenderScene.consumePublication(
2272
+ preparePublicationGeometry(
2273
+ publication,
2274
+ persistentRenderScene,
2275
+ internals.getPipelineState()?.skinPaletteAllocator,
2276
+ internals.assets,
2277
+ instanceCollections,
2278
+ internals.device.caps.storageBuffer
2279
+ ? internals.getMaterialShaderArtifact
2280
+ : undefined,
2281
+ ),
2282
+ );
2283
+ }
2506
2284
  return persistentRenderScene.extractComposition(
2507
- compositionWorlds,
2285
+ sourceWorlds,
2508
2286
  { cameraOwner, resourceOwner },
2509
2287
  internals.assets.catalogEpoch,
2510
2288
  (renderables) =>
2511
2289
  extractFrames(
2512
- compositionWorlds,
2290
+ sourceWorlds,
2513
2291
  {
2514
2292
  cameraOwner,
2515
2293
  resourceOwner,
@@ -2519,25 +2297,7 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
2519
2297
  internals.getPipelineState(),
2520
2298
  persistentRenderScene.materialSnapshotCacheStore(),
2521
2299
  {
2522
- ...(internals.device.caps.backendKind === 'null'
2523
- ? {}
2524
- : {
2525
- materialContext: {
2526
- backend:
2527
- internals.device.caps.backendKind === 'wgpu-webgl2'
2528
- ? ('webgl2' as const)
2529
- : internals.device.caps.backendKind,
2530
- capability: internals.device.caps.storageBuffer
2531
- ? ('storage-buffer' as const)
2532
- : ('uniform-fallback' as const),
2533
- pipeline: 'forward' as const,
2534
- geometry: 'mesh' as const,
2535
- pass: 'forward' as const,
2536
- profile: 'forgeax-material-wgsl-v1' as const,
2537
- toolchain: 'naga-oil' as const,
2538
- instrumentation: 'none' as const,
2539
- },
2540
- }),
2300
+ ...renderMaterialContext(internals.device.caps),
2541
2301
  cull: 'none',
2542
2302
  retainHidden: true,
2543
2303
  renderables,
@@ -2563,11 +2323,13 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
2563
2323
  lastMotionBlurInvalidParams = undefined;
2564
2324
  const {
2565
2325
  cameras: extractedCameras,
2326
+ auxiliaryCameras,
2566
2327
  cubeCameras,
2567
2328
  lights,
2568
2329
  environment,
2569
2330
  environmentReady,
2570
2331
  volumetricFog,
2332
+ cloudLayer,
2571
2333
  renderables,
2572
2334
  dispatch,
2573
2335
  shadowCasterEntityKeys: extractedShadowCasterEntityKeys,
@@ -2587,7 +2349,7 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
2587
2349
  frameState,
2588
2350
  internals,
2589
2351
  cameras[0],
2590
- compositionWorlds[cameraOwner] as World,
2352
+ compositionWorlds[cameraOwner] as RenderResourceScope,
2591
2353
  );
2592
2354
  if (!preparedOutput.ok) {
2593
2355
  internals.errorRegistry.fire(preparedOutput.error);
@@ -2796,6 +2558,17 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
2796
2558
  );
2797
2559
  const submissionRenderables = visibilityProjection.renderables;
2798
2560
  const submissionDispatch = visibilityProjection.dispatch;
2561
+ const presentationProjection = projectFramePresentation({
2562
+ hasCamera: cameras.length > 0,
2563
+ environmentReady,
2564
+ hasEnvironment: environment !== undefined,
2565
+ submissionRenderables,
2566
+ submissionDispatch,
2567
+ preparedWorlds,
2568
+ internals,
2569
+ });
2570
+ const presentationRenderables = presentationProjection.renderables;
2571
+ let framePresentation = presentationProjection.presentation;
2799
2572
  const inspectionCamera = latestCamera;
2800
2573
  // The public frame receipt is allocated by WebGPURenderer immediately
2801
2574
  // before this draw (`observationFrameId`). RenderSystem's private
@@ -2991,6 +2764,17 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
2991
2764
  bindGroupCounts.createBindGroup = 0;
2992
2765
  bindGroupCounts.keys = [];
2993
2766
  const preparedPipelineState = internals.getPipelineState();
2767
+ const featureView = createCloudFeatureView(
2768
+ cameras[0],
2769
+ compositionWorlds,
2770
+ cameraOwner,
2771
+ internals.canvas.width,
2772
+ internals.canvas.height,
2773
+ internals.deviceScope.generation,
2774
+ frameState.lastSuccessfulTemporalView === undefined,
2775
+ lastSubmittedGeneration !== undefined &&
2776
+ lastSubmittedGeneration !== internals.deviceScope.generation,
2777
+ );
2994
2778
  const bindGroupSkipReason: RenderPhaseSkipReason | undefined =
2995
2779
  internals.featureHost === undefined
2996
2780
  ? 'feature-host-unavailable'
@@ -3041,11 +2825,12 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
3041
2825
  colorAttachmentFormat: preparedPipelineState.colorAttachmentFormat,
3042
2826
  storageBuffer: internals.device.caps.storageBuffer,
3043
2827
  multisample: internals.device.caps.backendKind !== 'wgpu-webgl2',
2828
+ cloudHistory: cloudLayer !== undefined,
3044
2829
  });
3045
2830
  const motionBlurParams = cameras[0]?.motionBlur;
3046
2831
  let motionBlurDelta = 0;
3047
2832
  try {
3048
- const delta = (compositionWorlds[cameraOwner] as World).getResource(Time).delta;
2833
+ const delta = renderTime(compositionWorlds[cameraOwner] as RenderResourceScope).delta;
3049
2834
  motionBlurDelta = Number.isFinite(delta) ? Math.max(0, delta) : 0;
3050
2835
  } catch {
3051
2836
  motionBlurDelta = 0;
@@ -3087,17 +2872,39 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
3087
2872
  .skylightResources;
3088
2873
  let featureGraphCandidate: RenderFeatureGraphCandidate | undefined;
3089
2874
  const preparedResourceBatches = runProfiledRenderPhase(profileSession, 'features', () => {
2875
+ if (
2876
+ publication?.packet.features.some(
2877
+ (row) =>
2878
+ !internals.featureHost?.features.some(
2879
+ (feature) => feature.identity === row.identity,
2880
+ ),
2881
+ )
2882
+ )
2883
+ throw new RenderPublicationError({
2884
+ reason: 'shape',
2885
+ subject: 'published feature has no receiver implementation',
2886
+ });
3090
2887
  if (internals.featureHost === undefined) return [];
3091
2888
  const featureFrame = runRenderFeatureFrame(internals.featureHost, {
3092
- worlds: compositionWorlds,
2889
+ worlds: sourceWorlds,
2890
+ ...(publication === undefined
2891
+ ? {}
2892
+ : {
2893
+ publishedFeatures: publication.packet.features,
2894
+ ...(publication.onFeatureSourceSubmitted === undefined
2895
+ ? {}
2896
+ : { onFeatureSourceSubmitted: publication.onFeatureSourceSubmitted }),
2897
+ }),
3093
2898
  owner: resourceOwner,
3094
2899
  frameNumber: frameState.frameNumber,
2900
+ ...(cameras[0] === undefined ? {} : { selectedCamera: cameras[0] }),
3095
2901
  frameSize: { width: internals.canvas.width, height: internals.canvas.height },
3096
2902
  visibilitySnapshots: frame.featureVisibilitySnapshots,
3097
2903
  hiddenEntityReports: frame.hiddenEntityReports,
3098
2904
  targets: featureTargets,
3099
2905
  generation: internals.featureHost?.preparedGeneration ?? 0,
3100
2906
  caps: internals.device.caps,
2907
+ frame: createCloudFeatureFrameContext(cloudLayer, featureView),
3101
2908
  ...(internals.getMaterialShaderBindingContract === undefined
3102
2909
  ? {}
3103
2910
  : { materialShaderBindingContract: internals.getMaterialShaderBindingContract }),
@@ -3147,6 +2954,7 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
3147
2954
  featureGraphCandidate = {
3148
2955
  plans: featureFrame.plans,
3149
2956
  fullscreenEffects: featureFrame.fullscreenEffects,
2957
+ postProcessIdentities: featureFrame.postProcessIdentities,
3150
2958
  ...(featureFrame.requiresPreparedResourceKey
3151
2959
  ? { preparedResourceKey: `frame-${frameState.frameNumber}` }
3152
2960
  : {}),
@@ -3281,18 +3089,50 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
3281
3089
  frameState.standardLutState.resident !== null ||
3282
3090
  frameState.pendingStandardLutState !== undefined;
3283
3091
  if (hasLiveFeatureState) {
3284
- const cameraWorld = compositionWorlds[cameraOwner] as World;
3285
- const deltaTime = cameraWorld.getResource(Time).delta;
3092
+ const cameraWorld = compositionWorlds[cameraOwner] as RenderResourceScope;
3093
+ const deltaTime = renderTime(cameraWorld).delta;
3286
3094
  stageLiveFeatureState(
3287
3095
  cameras[0],
3288
3096
  Number.isFinite(deltaTime) ? Math.max(0, deltaTime) : 0,
3289
3097
  );
3290
3098
  }
3099
+ const surfaceSubmissionCandidate = surfaceSubmissionObservation.begin({
3100
+ frameId:
3101
+ (internals as RenderSystemInternals & { readonly observationFrameId?: number })
3102
+ .observationFrameId ?? frameState.frameNumber,
3103
+ requestedLane: opts.geometryLane === 'direct' ? 'direct' : 'gpu-driven',
3104
+ deviceGeneration: internals.deviceScope.generation,
3105
+ resourceGeneration: gpuDrivenProduction.inspect().resourceGeneration,
3106
+ });
3107
+ frameState.surfaceSubmissionObservation = surfaceSubmissionCandidate;
3291
3108
  const probeCaptureScene =
3292
3109
  shadowCasterProjection !== undefined &&
3293
- reflectionProbeRecord.graph.work.some((work) => work.rawCaptureFace !== undefined)
3110
+ (auxiliaryCameras.length > 0 ||
3111
+ cubeCameras.length > 0 ||
3112
+ reflectionProbeRecord.graph.work.some((work) => work.rawCaptureFace !== undefined))
3294
3113
  ? projectCaptureScene(shadowCasterProjection, submissionRenderables, orderedDispatch)
3295
3114
  : undefined;
3115
+ // Track actual draws so a clear/submit cannot claim visible geometry was presented.
3116
+ const presentedRenderableKeys = new Set<number>();
3117
+ const presentedSubmeshKeys = new Set<string>();
3118
+ const consumeDynamicGeometry = dynamicGeometryFrames.onRenderableDraw(sourceWorlds);
3119
+ const markPresentedRenderable = (
3120
+ entry: Parameters<typeof consumeDynamicGeometry>[0],
3121
+ submeshIndex?: number,
3122
+ receipt?: RenderableDrawReceipt,
3123
+ ): void => {
3124
+ const entityKey = worldEntityKey(
3125
+ worldKeys[entry.source.worldId] ?? entry.source.worldId,
3126
+ entry.source.entityKey,
3127
+ );
3128
+ if (receipt?.ready !== false) {
3129
+ presentedRenderableKeys.add(entityKey);
3130
+ }
3131
+ if (submeshIndex !== undefined && receipt?.ready !== false) {
3132
+ presentedSubmeshKeys.add(`${entityKey}:${submeshIndex}`);
3133
+ }
3134
+ consumeDynamicGeometry(entry, receipt?.lane ?? 'cpu');
3135
+ };
3296
3136
  submitted = runProfiledRenderPhase(profileSession, 'record', () =>
3297
3137
  recordFrame(
3298
3138
  internals,
@@ -3325,12 +3165,24 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
3325
3165
  deviceGeneration: internals.deviceScope.generation,
3326
3166
  },
3327
3167
  ...(occlusionProjection === undefined ? {} : { occlusion: occlusionProjection }),
3168
+ frameTime: (() => {
3169
+ const elapsed = renderTime(
3170
+ compositionWorlds[cameraOwner] as RenderResourceScope,
3171
+ ).elapsed;
3172
+ return Number.isFinite(elapsed) ? elapsed : 0;
3173
+ })(),
3174
+ deviceGeneration: internals.deviceScope.generation,
3175
+ ...(surfaceDynamicInputFrame === undefined
3176
+ ? {}
3177
+ : { surfaceDynamicInput: surfaceDynamicInputFrame }),
3178
+ ...(opts.geometryLane === undefined ? {} : { geometryLane: opts.geometryLane }),
3328
3179
  },
3329
3180
  compositionLeases,
3330
3181
  featureGraphCandidate,
3331
3182
  pointsLinesOwner,
3332
3183
  {
3333
3184
  snapshots: cubeCameras,
3185
+ auxiliaryCameras,
3334
3186
  scheduler: cubeCaptureScheduler,
3335
3187
  state: cubeCaptureState,
3336
3188
  reflectionProbes: reflectionProbeRecord,
@@ -3351,13 +3203,16 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
3351
3203
  worldKeys,
3352
3204
  undefined,
3353
3205
  ssrDependencies,
3354
- dynamicGeometryFrames.onRenderableDraw(compositionWorlds),
3206
+ markPresentedRenderable,
3355
3207
  environment?.fog,
3356
3208
  opts.sampleTimeSeconds,
3357
3209
  opts.temporalReset === true,
3210
+ frame.cloudLayer,
3358
3211
  ),
3359
3212
  );
3360
3213
  dynamicGeometryFrames.commit(submitted);
3214
+ if (!submitted) surfaceSubmissionCandidate.abort();
3215
+ frameState.surfaceSubmissionObservation = undefined;
3361
3216
  if (!submitted) discardLiveFeatureState();
3362
3217
  if (submitted && lastLodOcclusionInspection !== undefined) {
3363
3218
  const query = ensureOcclusionRuntime().inspect();
@@ -3381,6 +3236,111 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
3381
3236
  (frameState.currentDirectionalShadowView !== null &&
3382
3237
  (lights.lightViewProj?.length ?? 0) > 0 &&
3383
3238
  (internals.getPipelineState()?.perPassResources.shadowMapSize ?? 0) > 0);
3239
+
3240
+ // A successful queue submit is necessary but not sufficient for the
3241
+ // startup presentation fact. Reuse the same visible snapshots and
3242
+ // producer-owned GPU stores consumed by record so missing geometry,
3243
+ // material bindings, dynamic video frames, or requested shadow work
3244
+ // cannot dismiss the loading screen behind a clear/fallback pass.
3245
+ if (submitted && framePresentation === 'ready' && cameras.length > 0) {
3246
+ const pipelineState = internals.getPipelineState();
3247
+ const visibleRenderableKeys = new Set(
3248
+ presentationRenderables.map((renderable) =>
3249
+ worldEntityKey(
3250
+ worldKeys[renderable.worldId] ?? renderable.worldId,
3251
+ renderable.entityKey,
3252
+ ),
3253
+ ),
3254
+ );
3255
+ if (
3256
+ pipelineState === null ||
3257
+ frameState.compiledFrameGraph === null ||
3258
+ [...visibleRenderableKeys].some((key) => !presentedRenderableKeys.has(key))
3259
+ ) {
3260
+ framePresentation = 'pending';
3261
+ }
3262
+ for (const renderable of presentationRenderables) {
3263
+ if (framePresentation === 'pending') break;
3264
+ const renderableWorld = preparedWorlds[renderable.worldId];
3265
+ const meshHandles =
3266
+ renderableWorld === undefined
3267
+ ? undefined
3268
+ : (internals.gpuStore.getMeshGpuHandles(
3269
+ toShared<'MeshAsset'>(renderable.assetHandle),
3270
+ renderableWorld,
3271
+ ) ?? pipelineState?.meshes.get(renderable.assetHandle));
3272
+ if (meshHandles === undefined) {
3273
+ framePresentation = 'pending';
3274
+ break;
3275
+ }
3276
+ const entityKey = worldEntityKey(
3277
+ worldKeys[renderable.worldId] ?? renderable.worldId,
3278
+ renderable.entityKey,
3279
+ );
3280
+ const gpuClaimedSubmeshes = new Set<number>();
3281
+ for (const [compactIndex, draw] of (renderable.gpuDrivenDraws ?? []).entries()) {
3282
+ const submeshIndex = draw.drawItemIndex ?? compactIndex;
3283
+ if (presentedSubmeshKeys.has(`${entityKey}:${submeshIndex}`)) {
3284
+ gpuClaimedSubmeshes.add(submeshIndex);
3285
+ }
3286
+ }
3287
+ if (renderable.pointsLines === undefined) {
3288
+ for (const [submeshIndex] of meshHandles.submeshes.entries()) {
3289
+ if (gpuClaimedSubmeshes.has(submeshIndex)) continue;
3290
+ if (!presentedSubmeshKeys.has(`${entityKey}:${submeshIndex}`)) {
3291
+ framePresentation = 'pending';
3292
+ break;
3293
+ }
3294
+ }
3295
+ }
3296
+ if (framePresentation === 'pending') break;
3297
+ for (const material of renderable.materials) {
3298
+ const residency = observeMaterialResidency(renderableWorld, material, internals);
3299
+ if (residency.readiness === 'pending' || residency.readiness === 'failed') {
3300
+ framePresentation = 'pending';
3301
+ break;
3302
+ }
3303
+ for (const clip of material.videoTextureFields?.values() ?? []) {
3304
+ if (internals.dynamicTextureStore?.getView(clip) === undefined) {
3305
+ framePresentation = 'pending';
3306
+ break;
3307
+ }
3308
+ }
3309
+ if (framePresentation === 'pending') break;
3310
+ }
3311
+ if (framePresentation === 'pending') break;
3312
+ }
3313
+ if (
3314
+ framePresentation === 'ready' &&
3315
+ directionalQuality !== undefined &&
3316
+ (!directionalShadowReady ||
3317
+ (shadowCasterDrawKeys.size > 0 &&
3318
+ !frameState.directionalShadowCacheRecorded &&
3319
+ frameState.directionalShadowCache === null))
3320
+ ) {
3321
+ framePresentation = 'pending';
3322
+ }
3323
+ if (
3324
+ framePresentation === 'ready' &&
3325
+ lights.pointShadow.some(
3326
+ (shadow) =>
3327
+ shadow.shadowAtlasLayer >= 0 &&
3328
+ (shadow.shadowMatrices.length < 96 ||
3329
+ [...shadow.shadowMatrices].some((value) => !Number.isFinite(value))),
3330
+ )
3331
+ ) {
3332
+ framePresentation = 'pending';
3333
+ }
3334
+ if (
3335
+ framePresentation === 'ready' &&
3336
+ lights.spot.some(
3337
+ (spot) =>
3338
+ spot.castShadow && (spot.lightViewProj === undefined || spot.shadowAtlasTile < 0),
3339
+ )
3340
+ ) {
3341
+ framePresentation = 'pending';
3342
+ }
3343
+ }
3384
3344
  if (submitted && directionalShadowReady) {
3385
3345
  lastDirectionalShadowCandidate = 'accepted';
3386
3346
  } else if (directionalQuality !== undefined) {
@@ -3398,6 +3358,7 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
3398
3358
  };
3399
3359
  }
3400
3360
  if (submitted) {
3361
+ lastPresentation = framePresentation;
3401
3362
  recoveryOwner.setLastSuccessfulFrameSeed({
3402
3363
  frame,
3403
3364
  worlds: compositionWorlds,
@@ -3405,6 +3366,21 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
3405
3366
  resourceOwner: composition.owners.resourceOwner,
3406
3367
  width: Math.max(1, internals.canvas.width),
3407
3368
  height: Math.max(1, internals.canvas.height),
3369
+ frameTime: (() => {
3370
+ const elapsed = renderTime(
3371
+ compositionWorlds[cameraOwner] as RenderResourceScope,
3372
+ ).elapsed;
3373
+ return Number.isFinite(elapsed) ? elapsed : 0;
3374
+ })(),
3375
+ ...(surfaceDynamicInputFrame === undefined
3376
+ ? {}
3377
+ : { surfaceDynamicInput: surfaceDynamicInputFrame }),
3378
+ ...(frameState.recoveryMaterialArtifacts === undefined
3379
+ ? {}
3380
+ : { materialArtifacts: frameState.recoveryMaterialArtifacts }),
3381
+ ...(frameState.recoveryShadowMaterialArtifacts === undefined
3382
+ ? {}
3383
+ : { shadowMaterialArtifacts: frameState.recoveryShadowMaterialArtifacts }),
3408
3384
  });
3409
3385
  submittedFrameCount += 1;
3410
3386
  lastSubmittedGeneration = internals.deviceScope?.generation;
@@ -3418,13 +3394,12 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
3418
3394
  internals.errorRegistry.fire(temporalCommit.error);
3419
3395
  }
3420
3396
  frameState.lastSuccessfulCameraAntialias = cameras[0]?.antialias;
3421
- const submittedCamera = cameras[0];
3422
3397
  const submittedDepthOfField =
3423
- submittedCamera === undefined
3398
+ cameras[0] === undefined
3424
3399
  ? undefined
3425
3400
  : resolveDepthOfFieldFrameParams(
3426
- submittedCamera.depthOfField,
3427
- submittedCamera.depthOfFieldError,
3401
+ cameras[0].depthOfField,
3402
+ cameras[0].depthOfFieldError,
3428
3403
  frameState.depthOfFieldAccepted?.params,
3429
3404
  );
3430
3405
  const submittedDepthOfFieldGraph = frameState.compiledFrameGraph?.inspect();
@@ -3521,6 +3496,8 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
3521
3496
  },
3522
3497
  isDynamicGeometryConsumed: (world, entity, meshHandle) =>
3523
3498
  dynamicGeometryFrames.isConsumed(world, entity, meshHandle),
3499
+ dynamicGeometryRecordStageLane: (world, entity, meshHandle) =>
3500
+ dynamicGeometryFrames.recordStageLane(world, entity, meshHandle),
3524
3501
  pipelineDispatchCounts: dispatchCounts,
3525
3502
  observeCurrentFrame(options: FrameObservationOptions) {
3526
3503
  const currentFrameId = frameState.frameNumber - 1;
@@ -3557,6 +3534,20 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
3557
3534
  )
3558
3535
  return;
3559
3536
  applyLodSelectionTelemetry(selection, capturedInspection, capturedWorldAttachments);
3537
+ if (
3538
+ selection.surfaceReadback !== undefined &&
3539
+ selection.surfaceActualMemberIds !== undefined &&
3540
+ selection.surfaceIndirectParameters !== undefined
3541
+ ) {
3542
+ surfaceSubmissionObservation.publishGpuMembers(
3543
+ {
3544
+ recording: selection.surfaceReadback,
3545
+ memberIds: selection.surfaceActualMemberIds,
3546
+ indirectParameters: selection.surfaceIndirectParameters,
3547
+ },
3548
+ receipt ?? capturedInspection.submit,
3549
+ );
3550
+ }
3560
3551
  const published = lastLodOcclusionInspection;
3561
3552
  if (
3562
3553
  published !== undefined &&
@@ -3621,9 +3612,18 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
3621
3612
  get lastSuccessfulCameraAntialias(): CameraSnapshot['antialias'] | undefined {
3622
3613
  return frameState.lastSuccessfulCameraAntialias;
3623
3614
  },
3615
+ get lastSuccessfulBarrelDistortion(): BarrelDistortionMapping | undefined {
3616
+ return frameState.lastSuccessfulBarrelDistortion;
3617
+ },
3618
+ get barrelDistortionInspection(): BarrelDistortionInspection {
3619
+ return inspectBarrelDistortionState(frameState, internals.deviceScope?.generation ?? 0);
3620
+ },
3624
3621
  get perFrameGraphInfo(): CompiledRenderGraphInfo | undefined {
3625
3622
  return frameState.compiledFrameGraph?.inspect();
3626
3623
  },
3624
+ get renderGraphGenerationAllocation() {
3625
+ return inspectRenderGraphGenerationAllocation(frameState);
3626
+ },
3627
3627
  get featureGraphInspection(): import('./inspection-types').RenderFeatureGraphInspection {
3628
3628
  return getRenderFeatureGraphInspection(internals);
3629
3629
  },
@@ -3650,7 +3650,11 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
3650
3650
  });
3651
3651
  },
3652
3652
  get volumetricFog(): import('./volume/inspection').VolumetricFogInspection {
3653
- return frameState.volumetricFogInspection;
3653
+ const accepted = frameState.volumetricFogAccepted;
3654
+ return {
3655
+ ...frameState.volumetricFogInspection,
3656
+ ownerCount: accepted === undefined ? 0 : 1 + (accepted.additional?.length ?? 0),
3657
+ };
3654
3658
  },
3655
3659
  configureStandard(config: RenderPipelineAsset['config']): void {
3656
3660
  const profileConfig = internals.standardProfile;
@@ -3729,7 +3733,7 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
3729
3733
  }
3730
3734
  builtinPostProcessEntries.set(id, entry);
3731
3735
  if (paramsBuffer !== undefined) postProcessParamsBuffers.set(id, paramsBuffer);
3732
- const moduleLabel = postProcessShaderModuleLabel(id, entry.source);
3736
+ const moduleLabel = postProcessShaderModuleLabel(entry.source);
3733
3737
  return () => {
3734
3738
  if (builtinPostProcessEntries.get(id) === entry) {
3735
3739
  builtinPostProcessEntries.delete(id);
@@ -3778,6 +3782,11 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
3778
3782
  internals.getPipelineState()?.perPassResources.drainBloomResources?.();
3779
3783
  internals.clearPostProcessPipelineCache?.('forgeax.taa-resolve');
3780
3784
  invalidatePostProcessModule('forgeax.taa-resolve');
3785
+ // Post-process parameter UBOs are renderer-owned persistent resources,
3786
+ // rather than graph-owned transient state. Clear the active table before
3787
+ // the feature host is retired so the renderer remains the sole owner.
3788
+ disposeActivePostProcessResources();
3789
+ resetSsaoResources(internals);
3781
3790
  resetHdrpBuffers(internals);
3782
3791
  // Retire graph-owned resources and dispose instance-buffer caches.
3783
3792
  // Both calls are idempotent + tolerate per-handle errors silently;
@@ -3789,6 +3798,9 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
3789
3798
  frameState.directionalShadowCacheRecorded = false;
3790
3799
  frameState.currentFrameObservationSource = undefined;
3791
3800
  frameState.lastSuccessfulCameraAntialias = undefined;
3801
+ frameState.lastSuccessfulBarrelDistortion = undefined;
3802
+ frameState.cloudHistoryActive = false;
3803
+ delete frameState.pendingCloudHistoryActive;
3792
3804
  frameState.currentDirectionalShadowView = null;
3793
3805
  frameState.currentSpotShadowView = null;
3794
3806
  if (frameState.pendingAutoExposureGpuResources !== undefined) {
@@ -3816,6 +3828,7 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
3816
3828
  retireTemporalGpuState(retiring);
3817
3829
  }
3818
3830
  frameState.retiringTemporalGpuStates.clear();
3831
+ settleBarrelDistortionGraphCandidate(frameState, false);
3819
3832
  settleVolumetricFogGraphCandidate(frameState, false);
3820
3833
  for (const buffer of frameState.volumetricFogParamsBuffers) {
3821
3834
  if (buffer === null) continue;
@@ -3849,9 +3862,10 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
3849
3862
  frameState.depthOfFieldCandidateGraph = null;
3850
3863
  frameState.depthOfFieldAccepted = undefined;
3851
3864
  frameState.depthOfFieldLastSubmitFailed = false;
3852
- if (compiled !== null) compiled.retire().catch(() => undefined);
3865
+ resetBarrelDistortionGraphState(frameState);
3866
+ if (compiled !== null) retireCompiledGraph(frameState, compiled);
3853
3867
  for (const retired of frameState.retiredCompiledFrameGraphs) {
3854
- retired.retire().catch(() => undefined);
3868
+ retireCompiledGraph(frameState, retired);
3855
3869
  }
3856
3870
  frameState.retiredCompiledFrameGraphs.clear();
3857
3871
  // feat-20260619 M4 (D-6): pass errorRegistry to disposeInstanceBuffers
@@ -3871,6 +3885,7 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
3871
3885
  }
3872
3886
  frameState.probeBlendRecordBufferCapacity = 0;
3873
3887
  frameState.probeBlendBuffers.clear();
3888
+ delete frameState.probeBlendRecordProjection;
3874
3889
  if (frameState.morphBuffers !== undefined) {
3875
3890
  for (const entry of frameState.morphBuffers.values()) {
3876
3891
  if (!entry.buffer.isDestroyed) {
@@ -3909,6 +3924,7 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
3909
3924
  // device. Drop the shared Standard Cluster bundle before the next
3910
3925
  // frame asks for a new generation; resetHdrpBuffers fences the bundle
3911
3926
  // using its own device/queue instead of the replacement runtime device.
3927
+ resetSsaoResources(internals);
3912
3928
  resetHdrpBuffers(internals);
3913
3929
  // Keep the persistent material demand observable across device loss.
3914
3930
  // The physical resource has already been fenced by markDeviceLost(); the
@@ -3949,9 +3965,12 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
3949
3965
  // must be discarded, not merely marked for destruction: their opaque
3950
3966
  // handles cannot be used on the fresh device and the next draw must
3951
3967
  // lazily build a new graph from the preserved ECS / asset POD caches.
3968
+ settleBarrelDistortionGraphCandidate(frameState, false);
3952
3969
  settleVolumetricFogGraphCandidate(frameState, false);
3953
3970
  settleDepthOfFieldGraphCandidate(frameState, false);
3954
- frameState.compiledFrameGraph?.retire().catch(() => undefined);
3971
+ if (frameState.compiledFrameGraph !== null) {
3972
+ retireCompiledGraph(frameState, frameState.compiledFrameGraph);
3973
+ }
3955
3974
  frameState.compiledFrameGraph = null;
3956
3975
  frameState.compiledFrameGraphTopologyKey = null;
3957
3976
  frameState.volumetricFogPreviousGraph = null;
@@ -3963,6 +3982,7 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
3963
3982
  frameState.depthOfFieldPreviousGraphGeneration = 0;
3964
3983
  frameState.depthOfFieldPreviousStandardLightingGraphSignature = '';
3965
3984
  frameState.depthOfFieldCandidateGraph = null;
3985
+ resetBarrelDistortionGraphState(frameState);
3966
3986
  frameState.volumetricFogAccepted = undefined;
3967
3987
  frameState.volumetricFogAcceptedContext = undefined;
3968
3988
  frameState.volumetricFogHistoryGraph = null;
@@ -3989,6 +4009,9 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
3989
4009
  frameState.directionalShadowCacheRecorded = false;
3990
4010
  frameState.currentFrameObservationSource = undefined;
3991
4011
  frameState.lastSuccessfulCameraAntialias = undefined;
4012
+ frameState.lastSuccessfulBarrelDistortion = undefined;
4013
+ frameState.cloudHistoryActive = false;
4014
+ delete frameState.pendingCloudHistoryActive;
3992
4015
  frameState.temporalFrameTransaction.reset('device-recovery');
3993
4016
  frameState.temporalFrame = undefined;
3994
4017
  frameState.temporalFrameInput = undefined;
@@ -4011,7 +4034,7 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
4011
4034
  frameState.retiringTemporalGpuStates.clear();
4012
4035
  frameState.hdrpClusterMembership = null;
4013
4036
  for (const retired of frameState.retiredCompiledFrameGraphs) {
4014
- retired.retire().catch(() => undefined);
4037
+ retireCompiledGraph(frameState, retired);
4015
4038
  }
4016
4039
  frameState.retiredCompiledFrameGraphs.clear();
4017
4040
  frameState.instanceBuffers.clear();
@@ -4020,6 +4043,7 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
4020
4043
  delete frameState.probeBlendRecordBuffer;
4021
4044
  frameState.probeBlendRecordBufferCapacity = 0;
4022
4045
  frameState.probeBlendBuffers.clear();
4046
+ delete frameState.probeBlendRecordProjection;
4023
4047
  frameState.morphBuffers?.clear();
4024
4048
  frameState.transientInstanceBuffers = [];
4025
4049
  frameState.pointShadowAtlas = null;
@@ -4070,14 +4094,3 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
4070
4094
  export function resolveInspectionBuild(internals: Pick<RenderSystemInternals, 'build'>): string {
4071
4095
  return internals.build ?? 'render-system';
4072
4096
  }
4073
-
4074
- // @forgeax/engine-render - built-in record context extension.
4075
- //
4076
- // The public RenderPipelineContext is canonical in render-contract.ts. This
4077
- // owner adds only concrete assembly state for built-in record closures.
4078
-
4079
- /**
4080
- * Package-private extension consumed by the built-in record closures only.
4081
- * Custom pipeline authors see the leaf RenderPipelineContext contract and
4082
- * never this surface.
4083
- */