@forgeax/engine-render 0.1.32 → 0.1.34

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 +1374 -142
  2. package/dist/assembly/analytic-fog-registration.d.ts +3 -0
  3. package/dist/assembly/analytic-fog-registration.d.ts.map +1 -0
  4. package/dist/assembly/backend-contract.d.ts +2 -0
  5. package/dist/assembly/backend-contract.d.ts.map +1 -1
  6. package/dist/assembly/barrel-distortion-inspection.d.ts +3 -0
  7. package/dist/assembly/barrel-distortion-inspection.d.ts.map +1 -0
  8. package/dist/assembly/canvas-draw-guard.d.ts +3 -0
  9. package/dist/assembly/canvas-draw-guard.d.ts.map +1 -0
  10. package/dist/assembly/cloud-shadow-entry.d.ts +4 -0
  11. package/dist/assembly/cloud-shadow-entry.d.ts.map +1 -0
  12. package/dist/assembly/dynamic-geometry-host.d.ts +4 -1
  13. package/dist/assembly/dynamic-geometry-host.d.ts.map +1 -1
  14. package/dist/assembly/dynamic-geometry-runtime.d.ts +1 -1
  15. package/dist/assembly/dynamic-geometry-runtime.d.ts.map +1 -1
  16. package/dist/assembly/factory.d.ts +1 -1
  17. package/dist/assembly/factory.d.ts.map +1 -1
  18. package/dist/assembly/fxaa-registration.d.ts +4 -0
  19. package/dist/assembly/fxaa-registration.d.ts.map +1 -0
  20. package/dist/assembly/host-contract.d.ts +3 -3
  21. package/dist/assembly/host-contract.d.ts.map +1 -1
  22. package/dist/assembly/lod-observation.d.ts +4 -0
  23. package/dist/assembly/lod-observation.d.ts.map +1 -0
  24. package/dist/assembly/material/assembly.d.ts.map +1 -1
  25. package/dist/assembly/material/pipeline-helpers.d.ts +5 -0
  26. package/dist/assembly/material/pipeline-helpers.d.ts.map +1 -1
  27. package/dist/assembly/material-shader-policy.d.ts +16 -2
  28. package/dist/assembly/material-shader-policy.d.ts.map +1 -1
  29. package/dist/assembly/material-shader-prewarm.d.ts.map +1 -1
  30. package/dist/assembly/motion-blur-registration.d.ts +3 -0
  31. package/dist/assembly/motion-blur-registration.d.ts.map +1 -0
  32. package/dist/assembly/recovery/device-loss-fanout.d.ts.map +1 -1
  33. package/dist/assembly/recovery/renderer-recover.d.ts +2 -0
  34. package/dist/assembly/recovery/renderer-recover.d.ts.map +1 -1
  35. package/dist/assembly/render-feature-post-processes.d.ts +6 -0
  36. package/dist/assembly/render-feature-post-processes.d.ts.map +1 -0
  37. package/dist/assembly/renderer-facade.d.ts.map +1 -1
  38. package/dist/assembly/renderer-feature-inspection.d.ts +1 -1
  39. package/dist/assembly/renderer-feature-inspection.d.ts.map +1 -1
  40. package/dist/assembly/renderer-frame-transaction.d.ts +12 -0
  41. package/dist/assembly/renderer-frame-transaction.d.ts.map +1 -1
  42. package/dist/assembly/renderer-inspection.d.ts +11 -0
  43. package/dist/assembly/renderer-inspection.d.ts.map +1 -1
  44. package/dist/assembly/temporal-post-process-prewarm.d.ts +13 -0
  45. package/dist/assembly/temporal-post-process-prewarm.d.ts.map +1 -0
  46. package/dist/assembly/webgpu-pbr-ready.d.ts +1 -0
  47. package/dist/assembly/webgpu-pbr-ready.d.ts.map +1 -1
  48. package/dist/assembly/webgpu-ready-contract.d.ts +4 -3
  49. package/dist/assembly/webgpu-ready-contract.d.ts.map +1 -1
  50. package/dist/assembly/webgpu-ready-per-pass.d.ts +39 -0
  51. package/dist/assembly/webgpu-ready-per-pass.d.ts.map +1 -0
  52. package/dist/assembly/webgpu-ready.d.ts +2 -2
  53. package/dist/assembly/webgpu-ready.d.ts.map +1 -1
  54. package/dist/assembly/webgpu-renderer-bootstrap.d.ts.map +1 -1
  55. package/dist/assembly/webgpu-renderer-observation-owner.d.ts +35 -0
  56. package/dist/assembly/webgpu-renderer-observation-owner.d.ts.map +1 -0
  57. package/dist/assembly/webgpu-renderer.d.ts +1 -1
  58. package/dist/assembly/webgpu-renderer.d.ts.map +1 -1
  59. package/dist/authoring.mjs +1 -1
  60. package/dist/barrel-distortion.d.ts +47 -0
  61. package/dist/barrel-distortion.d.ts.map +1 -0
  62. package/dist/bloom-admission.d.ts +13 -0
  63. package/dist/bloom-admission.d.ts.map +1 -0
  64. package/dist/{chunk-PA5DRJNI.mjs → chunk-ELJFJ2BU.mjs} +2 -2
  65. package/dist/chunk-ELJFJ2BU.mjs.map +1 -0
  66. package/dist/{chunk-JCIRYQ4V.mjs → chunk-HEB564WF.mjs} +10 -4
  67. package/dist/chunk-HEB564WF.mjs.map +1 -0
  68. package/dist/{chunk-JRIPCMYC.mjs → chunk-MKDIT2EM.mjs} +1584 -375
  69. package/dist/chunk-MKDIT2EM.mjs.map +1 -0
  70. package/dist/{chunk-S665NJNF.mjs → chunk-OCDLEI6I.mjs} +3 -3
  71. package/dist/{chunk-S665NJNF.mjs.map → chunk-OCDLEI6I.mjs.map} +1 -1
  72. package/dist/chunk-ODZWR6JQ.mjs +4927 -0
  73. package/dist/chunk-ODZWR6JQ.mjs.map +1 -0
  74. package/dist/{chunk-DRR7D3KX.mjs → chunk-SHFUFJ5N.mjs} +192 -18
  75. package/dist/chunk-SHFUFJ5N.mjs.map +1 -0
  76. package/dist/{chunk-4NNZQCL3.mjs → chunk-UI5SFODX.mjs} +223 -277
  77. package/dist/chunk-UI5SFODX.mjs.map +1 -0
  78. package/dist/{chunk-GWCEMDVR.mjs → chunk-UINHLCZA.mjs} +787 -80
  79. package/dist/chunk-UINHLCZA.mjs.map +1 -0
  80. package/dist/{chunk-6TFBXLRJ.mjs → chunk-WEX45HKH.mjs} +222 -337
  81. package/dist/chunk-WEX45HKH.mjs.map +1 -0
  82. package/dist/cloud/density.d.ts +55 -0
  83. package/dist/cloud/density.d.ts.map +1 -0
  84. package/dist/cloud/extract.d.ts +25 -0
  85. package/dist/cloud/extract.d.ts.map +1 -0
  86. package/dist/cloud/feature.d.ts +57 -0
  87. package/dist/cloud/feature.d.ts.map +1 -0
  88. package/dist/cloud/frame-context.d.ts +8 -0
  89. package/dist/cloud/frame-context.d.ts.map +1 -0
  90. package/dist/cloud/inspection.d.ts +59 -0
  91. package/dist/cloud/inspection.d.ts.map +1 -0
  92. package/dist/cloud/optics.d.ts +56 -0
  93. package/dist/cloud/optics.d.ts.map +1 -0
  94. package/dist/cloud/parameters.d.ts +73 -0
  95. package/dist/cloud/parameters.d.ts.map +1 -0
  96. package/dist/cloud/resources.d.ts +60 -0
  97. package/dist/cloud/resources.d.ts.map +1 -0
  98. package/dist/cloud/shadow.d.ts +42 -0
  99. package/dist/cloud/shadow.d.ts.map +1 -0
  100. package/dist/cloud/temporal.d.ts +74 -0
  101. package/dist/cloud/temporal.d.ts.map +1 -0
  102. package/dist/components/atmosphere.d.ts +2 -0
  103. package/dist/components/atmosphere.d.ts.map +1 -1
  104. package/dist/components/barrel-distortion.d.ts +13 -0
  105. package/dist/components/barrel-distortion.d.ts.map +1 -0
  106. package/dist/components/camera.d.ts +20 -4
  107. package/dist/components/camera.d.ts.map +1 -1
  108. package/dist/components/cloud-layer.d.ts +29 -0
  109. package/dist/components/cloud-layer.d.ts.map +1 -0
  110. package/dist/components/index.d.ts +2 -0
  111. package/dist/components/index.d.ts.map +1 -1
  112. package/dist/components/instances.d.ts +20 -6
  113. package/dist/components/instances.d.ts.map +1 -1
  114. package/dist/components/mesh-filter.d.ts +6 -5
  115. package/dist/components/mesh-filter.d.ts.map +1 -1
  116. package/dist/components/motion-blur.d.ts +1 -0
  117. package/dist/components/motion-blur.d.ts.map +1 -1
  118. package/dist/construct-renderer.d.ts +1 -1
  119. package/dist/construct-renderer.d.ts.map +1 -1
  120. package/dist/construct-renderer.mjs +9751 -3528
  121. package/dist/construct-renderer.mjs.map +1 -1
  122. package/dist/device/gpu-residency.d.ts +6 -0
  123. package/dist/device/gpu-residency.d.ts.map +1 -1
  124. package/dist/dynamic-geometry.d.ts +5 -1
  125. package/dist/dynamic-geometry.d.ts.map +1 -1
  126. package/dist/environment/analytic-fog.d.ts +6 -0
  127. package/dist/environment/analytic-fog.d.ts.map +1 -0
  128. package/dist/errors/cloud.d.ts +59 -0
  129. package/dist/errors/cloud.d.ts.map +1 -0
  130. package/dist/errors/render.d.ts +23 -5
  131. package/dist/errors/render.d.ts.map +1 -1
  132. package/dist/examples/single-layer-medium-surface.d.ts +47 -0
  133. package/dist/examples/single-layer-medium-surface.d.ts.map +1 -0
  134. package/dist/extract/camera.d.ts.map +1 -1
  135. package/dist/extract/contracts.d.ts +12 -1
  136. package/dist/extract/contracts.d.ts.map +1 -1
  137. package/dist/extract/environment.d.ts +2 -0
  138. package/dist/extract/environment.d.ts.map +1 -1
  139. package/dist/features/barrel-distortion.d.ts +29 -0
  140. package/dist/features/barrel-distortion.d.ts.map +1 -0
  141. package/dist/features/error-reporting.d.ts +17 -0
  142. package/dist/features/error-reporting.d.ts.map +1 -0
  143. package/dist/features/host.d.ts +15 -0
  144. package/dist/features/host.d.ts.map +1 -1
  145. package/dist/features/motion-blur/motion-blur-feature.d.ts +20 -2
  146. package/dist/features/motion-blur/motion-blur-feature.d.ts.map +1 -1
  147. package/dist/features/motion-blur/motion-blur-params.d.ts +21 -0
  148. package/dist/features/motion-blur/motion-blur-params.d.ts.map +1 -1
  149. package/dist/features/motion-blur/motion-blur-runtime.d.ts +54 -0
  150. package/dist/features/motion-blur/motion-blur-runtime.d.ts.map +1 -0
  151. package/dist/features/plan.d.ts +15 -4
  152. package/dist/features/plan.d.ts.map +1 -1
  153. package/dist/features/prepared-gpu-work.d.ts +9 -5
  154. package/dist/features/prepared-gpu-work.d.ts.map +1 -1
  155. package/dist/features/render-graph-compute.d.ts.map +1 -1
  156. package/dist/features/render-graph-contribution.d.ts +5 -0
  157. package/dist/features/render-graph-contribution.d.ts.map +1 -1
  158. package/dist/features/render-graph-raster.d.ts +1 -0
  159. package/dist/features/render-graph-raster.d.ts.map +1 -1
  160. package/dist/features/targets.d.ts +2 -0
  161. package/dist/features/targets.d.ts.map +1 -1
  162. package/dist/features/types.d.ts +44 -0
  163. package/dist/features/types.d.ts.map +1 -1
  164. package/dist/fullscreen-post-process-pass.d.ts +15 -7
  165. package/dist/fullscreen-post-process-pass.d.ts.map +1 -1
  166. package/dist/gpu-dirty-ranges.d.ts +11 -0
  167. package/dist/gpu-dirty-ranges.d.ts.map +1 -0
  168. package/dist/gpu-driven/batch-topology.d.ts +17 -0
  169. package/dist/gpu-driven/batch-topology.d.ts.map +1 -1
  170. package/dist/gpu-driven/material-artifacts.d.ts +6 -0
  171. package/dist/gpu-driven/material-artifacts.d.ts.map +1 -1
  172. package/dist/gpu-driven/prepared-draw.d.ts +7 -0
  173. package/dist/gpu-driven/prepared-draw.d.ts.map +1 -1
  174. package/dist/gpu-driven/production-raster-material.d.ts +178 -0
  175. package/dist/gpu-driven/production-raster-material.d.ts.map +1 -0
  176. package/dist/gpu-driven/production-raster.d.ts +50 -4
  177. package/dist/gpu-driven/production-raster.d.ts.map +1 -1
  178. package/dist/gpu-driven/resource-allocation.d.ts +31 -0
  179. package/dist/gpu-driven/resource-allocation.d.ts.map +1 -0
  180. package/dist/gpu-driven/shadow-ownership.d.ts +14 -0
  181. package/dist/gpu-driven/shadow-ownership.d.ts.map +1 -0
  182. package/dist/gpu-driven/view-gpu.d.ts +35 -2
  183. package/dist/gpu-driven/view-gpu.d.ts.map +1 -1
  184. package/dist/gpu-scene.d.ts +11 -1
  185. package/dist/gpu-scene.d.ts.map +1 -1
  186. package/dist/hdrp-buffers.d.ts +2 -2
  187. package/dist/hdrp-buffers.d.ts.map +1 -1
  188. package/dist/ibl/skylight-bind-group.d.ts +10 -1
  189. package/dist/ibl/skylight-bind-group.d.ts.map +1 -1
  190. package/dist/index.d.ts +31 -8
  191. package/dist/index.d.ts.map +1 -1
  192. package/dist/index.mjs +258 -8
  193. package/dist/index.mjs.map +1 -1
  194. package/dist/inspection-types.d.ts +178 -3
  195. package/dist/inspection-types.d.ts.map +1 -1
  196. package/dist/instance-buffer-cache.d.ts +4 -4
  197. package/dist/instance-buffer-cache.d.ts.map +1 -1
  198. package/dist/instances.d.ts +49 -94
  199. package/dist/instances.d.ts.map +1 -1
  200. package/dist/internal.mjs +7 -7
  201. package/dist/pbr-pipeline.d.ts +19 -1
  202. package/dist/pbr-pipeline.d.ts.map +1 -1
  203. package/dist/pipeline/single-layer-medium-passes.d.ts +73 -0
  204. package/dist/pipeline/single-layer-medium-passes.d.ts.map +1 -0
  205. package/dist/pipeline/standard-forward-lane.d.ts.map +1 -1
  206. package/dist/pipeline/standard-output/graph.d.ts.map +1 -1
  207. package/dist/pipeline/standard-output/types.d.ts +4 -2
  208. package/dist/pipeline/standard-output/types.d.ts.map +1 -1
  209. package/dist/pipeline/standard-pipeline.d.ts.map +1 -1
  210. package/dist/pipeline/standard-post.d.ts +28 -19
  211. package/dist/pipeline/standard-post.d.ts.map +1 -1
  212. package/dist/pipeline-builder.d.ts +1 -1
  213. package/dist/pipeline-builder.d.ts.map +1 -1
  214. package/dist/pipeline-spec.d.ts +2 -2
  215. package/dist/plugin.d.ts.map +1 -1
  216. package/dist/prepare/prepared-graphics-resolver.d.ts +2 -0
  217. package/dist/prepare/prepared-graphics-resolver.d.ts.map +1 -1
  218. package/dist/record/barrel-distortion-frame.d.ts +15 -0
  219. package/dist/record/barrel-distortion-frame.d.ts.map +1 -0
  220. package/dist/record/dynamic-geometry-consumption.d.ts +10 -2
  221. package/dist/record/dynamic-geometry-consumption.d.ts.map +1 -1
  222. package/dist/record/fold-buckets.d.ts +95 -0
  223. package/dist/record/fold-buckets.d.ts.map +1 -0
  224. package/dist/record/fold-instance-buffer.d.ts +6 -0
  225. package/dist/record/fold-instance-buffer.d.ts.map +1 -0
  226. package/dist/record/frame-lighting.d.ts +1 -0
  227. package/dist/record/frame-lighting.d.ts.map +1 -1
  228. package/dist/record/frame-snapshot.d.ts +40 -3
  229. package/dist/record/frame-snapshot.d.ts.map +1 -1
  230. package/dist/record/frame-targets.d.ts.map +1 -1
  231. package/dist/record/frame.d.ts +14 -62
  232. package/dist/record/frame.d.ts.map +1 -1
  233. package/dist/record/gpu-draw-receipts.d.ts +11 -0
  234. package/dist/record/gpu-draw-receipts.d.ts.map +1 -0
  235. package/dist/record/gpu-timing.d.ts +8 -0
  236. package/dist/record/gpu-timing.d.ts.map +1 -1
  237. package/dist/record/main-pass-geometry.d.ts +21 -5
  238. package/dist/record/main-pass-geometry.d.ts.map +1 -1
  239. package/dist/record/main-pass-material.d.ts +7 -1
  240. package/dist/record/main-pass-material.d.ts.map +1 -1
  241. package/dist/record/main-pass-sprite-draws.d.ts.map +1 -1
  242. package/dist/record/main-pass.d.ts +13 -2
  243. package/dist/record/main-pass.d.ts.map +1 -1
  244. package/dist/record/mesh-ssbo.d.ts +6 -5
  245. package/dist/record/mesh-ssbo.d.ts.map +1 -1
  246. package/dist/record/motion-blur-receipt.d.ts +11 -0
  247. package/dist/record/motion-blur-receipt.d.ts.map +1 -0
  248. package/dist/record/probe-blend-buffer.d.ts +16 -0
  249. package/dist/record/probe-blend-buffer.d.ts.map +1 -0
  250. package/dist/record/recovery-pipeline.d.ts.map +1 -1
  251. package/dist/record/render-context.d.ts +34 -31
  252. package/dist/record/render-context.d.ts.map +1 -1
  253. package/dist/record/shadow-pass.d.ts +2 -0
  254. package/dist/record/shadow-pass.d.ts.map +1 -1
  255. package/dist/record/skybox-post-pass.d.ts +6 -4
  256. package/dist/record/skybox-post-pass.d.ts.map +1 -1
  257. package/dist/record/typed-frame-graph.d.ts +22 -2
  258. package/dist/record/typed-frame-graph.d.ts.map +1 -1
  259. package/dist/record/view-ubo.d.ts +11 -3
  260. package/dist/record/view-ubo.d.ts.map +1 -1
  261. package/dist/record/volume-params.d.ts +9 -0
  262. package/dist/record/volume-params.d.ts.map +1 -0
  263. package/dist/recovery/render-system-candidate.d.ts +10 -0
  264. package/dist/recovery/render-system-candidate.d.ts.map +1 -1
  265. package/dist/reflection/record-owner.d.ts.map +1 -1
  266. package/dist/render-contract.d.ts +66 -8
  267. package/dist/render-contract.d.ts.map +1 -1
  268. package/dist/render-graph-primitives.d.ts.map +1 -1
  269. package/dist/render-pipeline.d.ts +106 -3
  270. package/dist/render-pipeline.d.ts.map +1 -1
  271. package/dist/render-system-extract-tail.d.ts +3 -2
  272. package/dist/render-system-extract-tail.d.ts.map +1 -1
  273. package/dist/render-system-extract.d.ts +24 -10
  274. package/dist/render-system-extract.d.ts.map +1 -1
  275. package/dist/render-system-presentation.d.ts +23 -0
  276. package/dist/render-system-presentation.d.ts.map +1 -0
  277. package/dist/render-system-producer-roots.d.ts +10 -0
  278. package/dist/render-system-producer-roots.d.ts.map +1 -0
  279. package/dist/render-system-residency.d.ts +12 -0
  280. package/dist/render-system-residency.d.ts.map +1 -0
  281. package/dist/render-system.d.ts +26 -15
  282. package/dist/render-system.d.ts.map +1 -1
  283. package/dist/scene/probe-blend.d.ts +27 -0
  284. package/dist/scene/probe-blend.d.ts.map +1 -1
  285. package/dist/scene/render-scene.d.ts +14 -5
  286. package/dist/scene/render-scene.d.ts.map +1 -1
  287. package/dist/ssao-buffers.d.ts +9 -0
  288. package/dist/ssao-buffers.d.ts.map +1 -1
  289. package/dist/surface/dynamic-input.d.ts +133 -0
  290. package/dist/surface/dynamic-input.d.ts.map +1 -0
  291. package/dist/surface/gpu-driven.d.ts +41 -0
  292. package/dist/surface/gpu-driven.d.ts.map +1 -0
  293. package/dist/surface/submission-observation.d.ts +136 -0
  294. package/dist/surface/submission-observation.d.ts.map +1 -0
  295. package/dist/systems/skin-palette-allocator.d.ts.map +1 -1
  296. package/dist/temporal/frame-coordinator.d.ts.map +1 -1
  297. package/dist/temporal/frame.d.ts +7 -0
  298. package/dist/temporal/frame.d.ts.map +1 -1
  299. package/dist/temporal/gpu.d.ts +13 -1
  300. package/dist/temporal/gpu.d.ts.map +1 -1
  301. package/dist/temporal/index.mjs +5 -5
  302. package/dist/temporal/inspection.d.ts.map +1 -1
  303. package/dist/temporal/standard-scene-data.d.ts.map +1 -1
  304. package/dist/temporal/target-coverage-attachment.d.ts.map +1 -1
  305. package/dist/temporal/view.d.ts +6 -1
  306. package/dist/temporal/view.d.ts.map +1 -1
  307. package/dist/transmission/single-layer-medium.d.ts +89 -0
  308. package/dist/transmission/single-layer-medium.d.ts.map +1 -0
  309. package/dist/typed-render-graph-primitives.d.ts +24 -9
  310. package/dist/typed-render-graph-primitives.d.ts.map +1 -1
  311. package/dist/volume/component.d.ts +9 -5
  312. package/dist/volume/component.d.ts.map +1 -1
  313. package/dist/volume/extract.d.ts +1 -1
  314. package/dist/volume/extract.d.ts.map +1 -1
  315. package/dist/volume/inspection.d.ts +2 -0
  316. package/dist/volume/inspection.d.ts.map +1 -1
  317. package/dist/volume/passes.d.ts +4 -1
  318. package/dist/volume/passes.d.ts.map +1 -1
  319. package/dist/volume/resources.d.ts.map +1 -1
  320. package/dist/volume/temporal.d.ts +3 -1
  321. package/dist/volume/temporal.d.ts.map +1 -1
  322. package/package.json +22 -21
  323. package/src/__tests__/analytic-fog-graph.unit.test.ts +199 -0
  324. package/src/__tests__/analytic-fog-optics.unit.test.ts +38 -0
  325. package/src/__tests__/atmosphere-daylight.dawn.test.ts +72 -0
  326. package/src/__tests__/barrel-distortion-lkg.integration.test.ts +353 -0
  327. package/src/__tests__/barrel-distortion.dawn.test.ts +41 -0
  328. package/src/__tests__/barrel-distortion.unit.test.ts +364 -0
  329. package/src/__tests__/bloom-exact-zero.unit.test.ts +112 -18
  330. package/src/__tests__/bloom-lifecycle.integration.test.ts +17 -4
  331. package/src/__tests__/construct-renderer-identity.unit.test.ts +49 -0
  332. package/src/__tests__/detached-recovery-graph.unit.test.ts +277 -0
  333. package/src/__tests__/device-loss-fanout.unit.test.ts +36 -1
  334. package/src/__tests__/docs-gate-green.unit.test.ts +112 -1
  335. package/src/__tests__/dynamic-resolution-plugin.integration.test.ts +20 -0
  336. package/src/__tests__/environment-fog-lanes.integration.test.ts +14 -0
  337. package/src/__tests__/environment-selection.unit.test.ts +12 -0
  338. package/src/__tests__/factory-contract.integration.test.ts +626 -113
  339. package/src/__tests__/feature-depth-input.dawn.test.ts +129 -2
  340. package/src/__tests__/frame-camera-selection.unit.test.ts +39 -1
  341. package/src/__tests__/frame-plan-contract.unit.test.ts +2 -0
  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-indirect-raster-evidence.ts +2 -1
  347. package/src/__tests__/gpu-driven-material-artifacts.unit.test.ts +143 -0
  348. package/src/__tests__/gpu-driven-pbr.dawn.test.ts +2 -2
  349. package/src/__tests__/gpu-driven-production.integration.test.ts +482 -3
  350. package/src/__tests__/gpu-driven-shadow-views.dawn.test.ts +7 -6
  351. package/src/__tests__/gpu-driven-shadow-views.integration.test.ts +1 -1
  352. package/src/__tests__/gpu-driven-view-gpu-evidence.ts +103 -4
  353. package/src/__tests__/gpu-driven-view-graph.integration.test.ts +18 -2
  354. package/src/__tests__/gpu-driven-view.browser.test.ts +5 -8
  355. package/src/__tests__/gpu-driven-view.dawn.test.ts +6 -2
  356. package/src/__tests__/gpu-driven-view.unit.test.ts +1 -1
  357. package/src/__tests__/gpu-pass-timing-lifecycle.integration.test.ts +1 -0
  358. package/src/__tests__/gpu-pass-timing.browser.test.ts +6 -4
  359. package/src/__tests__/gpu-pass-timing.rhi-null.unit.test.ts +1 -0
  360. package/src/__tests__/gpu-resource-store-stride.unit.test.ts +12 -0
  361. package/src/__tests__/gpu-scene.unit.test.ts +210 -9
  362. package/src/__tests__/instance-allocation-failure.unit.test.ts +57 -0
  363. package/src/__tests__/instances-culling.integration.test.ts +10 -36
  364. package/src/__tests__/instances-store.unit.test.ts +105 -238
  365. package/src/__tests__/instances-world-ownership.integration.test.ts +62 -0
  366. package/src/__tests__/main-pass-material-medium-selection.unit.test.ts +146 -0
  367. package/src/__tests__/material-shader-prewarm.unit.test.ts +59 -0
  368. package/src/__tests__/material-snapshot-mutation.integration.test.ts +39 -1
  369. package/src/__tests__/mesh-submission-lifetime.unit.test.ts +31 -0
  370. package/src/__tests__/morph-culling-reentry.dawn.test.ts +5 -5
  371. package/src/__tests__/morph-visual-evidence.integration.test.ts +8 -7
  372. package/src/__tests__/motion-blur-compute.dawn.test.ts +589 -0
  373. package/src/__tests__/motion-blur.pixel.integration.test.ts +2 -2
  374. package/src/__tests__/nineslice-handle-surface.unit.test.ts +4 -4
  375. package/src/__tests__/pbr-view-layout.unit.test.ts +9 -0
  376. package/src/__tests__/physical-clearcoat.integration.test.ts +58 -0
  377. package/src/__tests__/prepared-gpu-driven-pbr.integration.test.ts +21 -0
  378. package/src/__tests__/prepared-graphics-capability.unit.test.ts +66 -2
  379. package/src/__tests__/prepared-graphics-lifecycle.unit.test.ts +86 -0
  380. package/src/__tests__/probe-bindings.unit.test.ts +582 -1
  381. package/src/__tests__/probe-scene-dirty.integration.test.ts +28 -1
  382. package/src/__tests__/public-surface.test-d.ts +8 -0
  383. package/src/__tests__/receipt-observation-retirement.unit.test.ts +65 -0
  384. package/src/__tests__/recovery-candidate-prepare.contract.test.ts +69 -0
  385. package/src/__tests__/render-error-code-owner.test-d.ts +9 -0
  386. package/src/__tests__/render-feature-diagnostics.unit.test.ts +15 -2
  387. package/src/__tests__/render-feature-error-reporting.unit.test.ts +44 -0
  388. package/src/__tests__/render-feature-prepared-diagnostics.unit.test.ts +10 -1
  389. package/src/__tests__/render-feature-retry.unit.test.ts +12 -1
  390. package/src/__tests__/render-feature-stage-fault-recovery.unit.test.ts +23 -0
  391. package/src/__tests__/render-scene-mixed-updates.integration.test.ts +145 -19
  392. package/src/__tests__/render-scene-projection.unit.test.ts +36 -11
  393. package/src/__tests__/render-scene-temporal-retry.unit.test.ts +37 -6
  394. package/src/__tests__/render-target-probe-soak.perf.test.ts +2 -2
  395. package/src/__tests__/render-temporal-environment-consumer.browser.test.ts +3 -3
  396. package/src/__tests__/render-temporal-environment-consumer.dawn.test.ts +5 -2
  397. package/src/__tests__/renderer-factory-material-contract.unit.test.ts +41 -7
  398. package/src/__tests__/renderer-frame-generation-fence.integration.test.ts +16 -0
  399. package/src/__tests__/renderer-frame-transaction.integration.test.ts +33 -11
  400. package/src/__tests__/resource-allocation.unit.test.ts +123 -0
  401. package/src/__tests__/shader-manifest-fixture.ts +4 -4
  402. package/src/__tests__/single-layer-medium-passes.unit.test.ts +275 -0
  403. package/src/__tests__/skin-motion-regression.unit.test.ts +70 -1
  404. package/src/__tests__/skin-palette-recycling.dawn.test.ts +97 -0
  405. package/src/__tests__/skinned-shadow-caster.test.ts +17 -0
  406. package/src/__tests__/ssr-carrier-public-contract.unit.test.ts +21 -0
  407. package/src/__tests__/ssr-gpu-dispatch.browser.test.ts +4 -4
  408. package/src/__tests__/ssr-gpu-dispatch.dawn.test.ts +2 -2
  409. package/src/__tests__/ssr-gpu-dispatch.ts +1 -1
  410. package/src/__tests__/ssr-receiver-coverage.dawn.test.ts +6 -2
  411. package/src/__tests__/standard-lighting-write.unit.test.ts +2 -1
  412. package/src/__tests__/standard-output-chain-contract.unit.test.ts +28 -0
  413. package/src/__tests__/standard-pbr-artifact-assembly.unit.test.ts +46 -1
  414. package/src/__tests__/standard-pipeline.dawn.test.ts +1 -1
  415. package/src/__tests__/standard-pipeline.integration.test.ts +200 -9
  416. package/src/__tests__/surface-dynamic-buffer-lifecycle.unit.test.ts +506 -0
  417. package/src/__tests__/surface-submission-observation.unit.test.ts +812 -0
  418. package/src/__tests__/temporal-history-lifecycle.unit.test.ts +32 -0
  419. package/src/__tests__/temporal-performance.integration.test.ts +3 -3
  420. package/src/__tests__/temporal-reset-matrix.unit.test.ts +10 -0
  421. package/src/__tests__/temporal-view.unit.test.ts +2 -1
  422. package/src/__tests__/typed-pipeline-topology.unit.test.ts +20 -4
  423. package/src/__tests__/visibility-instances.integration.test.ts +7 -19
  424. package/src/__tests__/visibility-producer-matrix.integration.test.ts +9 -20
  425. package/src/__tests__/volume-optics-oracle.unit.test.ts +7 -3
  426. package/src/__tests__/volumetric-fog-budget-recovery.integration.test.ts +189 -15
  427. package/src/__tests__/volumetric-fog-errors.unit.test.ts +4 -3
  428. package/src/__tests__/volumetric-fog-multiple.unit.test.ts +55 -0
  429. package/src/__tests__/volumetric-fog-spot-frame-optics.integration.test.ts +1 -1
  430. package/src/__tests__/volumetric-fog-stage-readback.dawn.test.ts +558 -68
  431. package/src/__tests__/volumetric-fog-temporal.unit.test.ts +27 -0
  432. package/src/__tests__/volumetric-fog-topology.unit.test.ts +23 -5
  433. package/src/assembly/analytic-fog-registration.ts +14 -0
  434. package/src/assembly/backend-contract.ts +30 -0
  435. package/src/assembly/barrel-distortion-inspection.ts +22 -0
  436. package/src/assembly/canvas-draw-guard.ts +11 -0
  437. package/src/assembly/cloud-shadow-entry.ts +22 -0
  438. package/src/assembly/dynamic-geometry-host.ts +65 -37
  439. package/src/assembly/dynamic-geometry-runtime.ts +7 -1
  440. package/src/assembly/factory.ts +2 -30
  441. package/src/assembly/fxaa-registration.ts +17 -0
  442. package/src/assembly/host-contract.ts +3 -3
  443. package/src/assembly/lod-observation.ts +12 -0
  444. package/src/assembly/material/assembly.ts +25 -13
  445. package/src/assembly/material/pipeline-helpers.ts +53 -12
  446. package/src/assembly/material-shader-policy.ts +55 -0
  447. package/src/assembly/material-shader-prewarm.ts +21 -10
  448. package/src/assembly/motion-blur-registration.ts +17 -0
  449. package/src/assembly/recovery/device-loss-fanout.ts +13 -0
  450. package/src/assembly/recovery/renderer-recover.ts +41 -18
  451. package/src/assembly/render-feature-post-processes.ts +54 -0
  452. package/src/assembly/renderer-facade.ts +6 -1
  453. package/src/assembly/renderer-feature-inspection.ts +8 -2
  454. package/src/assembly/renderer-frame-transaction.ts +23 -0
  455. package/src/assembly/renderer-inspection.ts +28 -0
  456. package/src/assembly/skin-palette-owner.ts +1 -1
  457. package/src/assembly/temporal-post-process-prewarm.ts +40 -0
  458. package/src/assembly/webgpu-pbr-ready.ts +9 -1
  459. package/src/assembly/webgpu-ready-contract.ts +8 -3
  460. package/src/assembly/webgpu-ready-per-pass.ts +104 -0
  461. package/src/assembly/webgpu-ready.ts +296 -306
  462. package/src/assembly/webgpu-renderer-bootstrap.ts +0 -12
  463. package/src/assembly/webgpu-renderer-observation-owner.ts +222 -0
  464. package/src/assembly/webgpu-renderer.ts +228 -281
  465. package/src/assembly/webgpu-vertex-layouts.ts +1 -1
  466. package/src/barrel-distortion.ts +247 -0
  467. package/src/bloom-admission.ts +21 -0
  468. package/src/cloud/__tests__/cloud-density-parity.dawn.test.ts +173 -0
  469. package/src/cloud/__tests__/cloud-layer-framebuffer-y.dawn.test.ts +265 -0
  470. package/src/cloud/__tests__/cloud-layer.browser.test.ts +432 -0
  471. package/src/cloud/__tests__/cloud-layer.unit.test.ts +634 -0
  472. package/src/cloud/density.ts +600 -0
  473. package/src/cloud/extract.ts +110 -0
  474. package/src/cloud/feature.ts +1810 -0
  475. package/src/cloud/frame-context.ts +42 -0
  476. package/src/cloud/inspection.ts +130 -0
  477. package/src/cloud/optics.ts +285 -0
  478. package/src/cloud/parameters.ts +255 -0
  479. package/src/cloud/resources.ts +122 -0
  480. package/src/cloud/shadow.ts +167 -0
  481. package/src/cloud/temporal.ts +226 -0
  482. package/src/components/__tests__/motion-blur.unit.test.ts +1 -0
  483. package/src/components/atmosphere.ts +4 -0
  484. package/src/components/barrel-distortion.ts +46 -0
  485. package/src/components/camera.ts +66 -10
  486. package/src/components/cloud-layer.ts +47 -0
  487. package/src/components/index.ts +2 -0
  488. package/src/components/instances.ts +18 -45
  489. package/src/components/mesh-filter.ts +11 -9
  490. package/src/components/motion-blur.ts +1 -0
  491. package/src/components/sprite-instances.ts +1 -1
  492. package/src/construct-renderer.ts +1 -1
  493. package/src/device/gpu-residency.ts +56 -12
  494. package/src/dynamic-geometry.ts +12 -1
  495. package/src/environment/analytic-fog.ts +44 -0
  496. package/src/environment/background.ts +2 -2
  497. package/src/errors/cloud.ts +103 -0
  498. package/src/errors/render.ts +58 -8
  499. package/src/examples/single-layer-medium-surface.ts +59 -0
  500. package/src/extract/camera.ts +35 -8
  501. package/src/extract/contracts.ts +12 -0
  502. package/src/extract/environment.ts +4 -0
  503. package/src/features/barrel-distortion.ts +172 -0
  504. package/src/features/error-reporting.ts +98 -0
  505. package/src/features/host.ts +138 -24
  506. package/src/features/motion-blur/__tests__/motion-blur-feature.unit.test.ts +111 -1
  507. package/src/features/motion-blur/__tests__/motion-blur-params.unit.test.ts +58 -3
  508. package/src/features/motion-blur/motion-blur-feature.ts +1519 -15
  509. package/src/features/motion-blur/motion-blur-params.ts +70 -2
  510. package/src/features/motion-blur/motion-blur-runtime.ts +176 -0
  511. package/src/features/plan.ts +33 -8
  512. package/src/features/prepared-gpu-work.ts +86 -35
  513. package/src/features/render-graph-compute.ts +13 -5
  514. package/src/features/render-graph-contribution.ts +11 -0
  515. package/src/features/render-graph-raster.ts +45 -3
  516. package/src/features/targets.ts +66 -0
  517. package/src/features/types.ts +47 -0
  518. package/src/fullscreen-post-process-pass.ts +41 -9
  519. package/src/gpu-dirty-ranges.ts +48 -0
  520. package/src/gpu-driven/batch-topology.ts +53 -0
  521. package/src/gpu-driven/material-artifacts.ts +35 -32
  522. package/src/gpu-driven/prepared-draw.ts +27 -14
  523. package/src/gpu-driven/production-raster-material.ts +1894 -0
  524. package/src/gpu-driven/production-raster.ts +904 -787
  525. package/src/gpu-driven/resource-allocation.ts +142 -0
  526. package/src/gpu-driven/shadow-ownership.ts +71 -0
  527. package/src/gpu-driven/view-gpu.ts +181 -10
  528. package/src/gpu-scene.ts +259 -101
  529. package/src/hdrp-buffers.ts +4 -3
  530. package/src/ibl/skylight-bind-group.ts +49 -7
  531. package/src/index.ts +228 -9
  532. package/src/inspection-types.ts +222 -2
  533. package/src/instance-buffer-cache.ts +4 -4
  534. package/src/instances.ts +151 -492
  535. package/src/pbr-pipeline.ts +219 -13
  536. package/src/pipeline/single-layer-medium-passes.ts +267 -0
  537. package/src/pipeline/standard-forward-lane.ts +313 -57
  538. package/src/pipeline/standard-output/graph.ts +8 -2
  539. package/src/pipeline/standard-output/types.ts +12 -1
  540. package/src/pipeline/standard-pipeline.ts +291 -18
  541. package/src/pipeline/standard-post.ts +397 -102
  542. package/src/pipeline-builder.ts +1 -1
  543. package/src/pipeline-spec.ts +5 -5
  544. package/src/plugin.ts +4 -0
  545. package/src/points-lines/__tests__/points-lines.bench.ts +17 -8
  546. package/src/points-lines/__tests__/view-ubo.unit.test.ts +2 -1
  547. package/src/prepare/prepared-graphics-resolver.ts +2 -0
  548. package/src/record/__tests__/main-pass-geometry.unit.test.ts +30 -0
  549. package/src/record/__tests__/sprite-material-abi.unit.test.ts +1 -1
  550. package/src/record/__tests__/temporal-payload.unit.test.ts +3 -2
  551. package/src/record/__tests__/transparent-group2-selection.unit.test.ts +11 -0
  552. package/src/record/__tests__/typed-frame-graph-plan.unit.test.ts +1 -0
  553. package/src/record/__tests__/view-ubo-layout.unit.test.ts +4 -3
  554. package/src/record/barrel-distortion-frame.ts +110 -0
  555. package/src/record/dynamic-geometry-consumption.ts +39 -9
  556. package/src/record/fold-buckets.ts +852 -0
  557. package/src/record/fold-instance-buffer.ts +51 -0
  558. package/src/record/frame-lighting.ts +36 -2
  559. package/src/record/frame-snapshot.ts +44 -4
  560. package/src/record/frame-targets.ts +10 -6
  561. package/src/record/frame.ts +373 -1099
  562. package/src/record/gpu-draw-receipts.ts +38 -0
  563. package/src/record/gpu-timing.ts +48 -5
  564. package/src/record/main-pass-geometry.ts +281 -83
  565. package/src/record/main-pass-material.ts +66 -4
  566. package/src/record/main-pass-sprite-draws.ts +13 -66
  567. package/src/record/main-pass.ts +156 -20
  568. package/src/record/mesh-ssbo.ts +43 -6
  569. package/src/record/motion-blur-receipt.ts +91 -0
  570. package/src/record/probe-blend-buffer.ts +180 -0
  571. package/src/record/recovery-pipeline.ts +35 -3
  572. package/src/record/render-context.ts +51 -31
  573. package/src/record/shadow-pass.ts +36 -2
  574. package/src/record/skybox-post-pass.ts +150 -200
  575. package/src/record/typed-frame-graph.ts +824 -44
  576. package/src/record/view-ubo.ts +26 -3
  577. package/src/record/volume-params.ts +225 -0
  578. package/src/recovery/render-system-candidate.ts +257 -52
  579. package/src/reflection/record-owner.ts +7 -3
  580. package/src/render-contract.ts +71 -8
  581. package/src/render-graph-primitives.ts +7 -1
  582. package/src/render-pipeline.ts +136 -1
  583. package/src/render-system-extract-tail.ts +72 -60
  584. package/src/render-system-extract.ts +117 -87
  585. package/src/render-system-presentation.ts +56 -0
  586. package/src/render-system-producer-roots.ts +96 -0
  587. package/src/render-system-residency.ts +159 -0
  588. package/src/render-system.ts +601 -482
  589. package/src/scene/probe-blend.ts +96 -4
  590. package/src/scene/render-scene.ts +431 -281
  591. package/src/ssao-buffers.ts +95 -2
  592. package/src/surface/__tests__/dynamic-input.unit.test.ts +374 -0
  593. package/src/surface/__tests__/gpu-driven.unit.test.ts +87 -0
  594. package/src/surface/dynamic-input.ts +658 -0
  595. package/src/surface/gpu-driven.ts +147 -0
  596. package/src/surface/submission-observation.ts +517 -0
  597. package/src/systems/skin-palette-allocator.ts +4 -1
  598. package/src/temporal/__tests__/temporal-frame-transaction.unit.test.ts +36 -0
  599. package/src/temporal/frame-coordinator.ts +8 -1
  600. package/src/temporal/frame.ts +20 -0
  601. package/src/temporal/gpu.ts +101 -17
  602. package/src/temporal/inspection.ts +7 -1
  603. package/src/temporal/standard-scene-data.ts +5 -0
  604. package/src/temporal/target-coverage-attachment.ts +4 -0
  605. package/src/temporal/view.ts +13 -2
  606. package/src/transmission/__tests__/single-layer-medium.unit.test.ts +149 -0
  607. package/src/transmission/__tests__/standard-transmission.dawn.test.ts +12 -11
  608. package/src/transmission/single-layer-medium.ts +322 -0
  609. package/src/typed-render-graph-primitives.ts +191 -50
  610. package/src/volume/component.ts +10 -10
  611. package/src/volume/extract.ts +11 -5
  612. package/src/volume/inspection.ts +3 -0
  613. package/src/volume/passes.ts +95 -8
  614. package/src/volume/resources.ts +2 -1
  615. package/src/volume/temporal.ts +11 -0
  616. package/dist/chunk-4NNZQCL3.mjs.map +0 -1
  617. package/dist/chunk-6TFBXLRJ.mjs.map +0 -1
  618. package/dist/chunk-DRR7D3KX.mjs.map +0 -1
  619. package/dist/chunk-GWCEMDVR.mjs.map +0 -1
  620. package/dist/chunk-JCIRYQ4V.mjs.map +0 -1
  621. package/dist/chunk-JRIPCMYC.mjs.map +0 -1
  622. package/dist/chunk-LULCA3OF.mjs +0 -1713
  623. package/dist/chunk-LULCA3OF.mjs.map +0 -1
  624. package/dist/chunk-PA5DRJNI.mjs.map +0 -1
@@ -5,8 +5,13 @@ import type {
5
5
  } from '@forgeax/engine-render-graph';
6
6
  import { RenderGraphError } from '@forgeax/engine-render-graph';
7
7
  import { err, ok, type Result } from '@forgeax/engine-types';
8
+ import { standardBloomAdmitted } from '../bloom-admission';
8
9
  import { addTypedDebugOverlayPass } from '../debug-draw-glue';
9
- import { SceneDataUnavailableError } from '../errors/render';
10
+ import { RenderFeatureCapabilityMissingError, SceneDataUnavailableError } from '../errors/render';
11
+ import {
12
+ BARREL_DISTORTION_FEATURE_IDENTITY,
13
+ BARREL_DISTORTION_POST_PROCESS_ID,
14
+ } from '../features/barrel-distortion';
10
15
  import { addDepthOfFieldPasses } from '../features/depth-of-field/depth-of-field-feature';
11
16
  import { addMotionBlurPass } from '../features/motion-blur/motion-blur-feature';
12
17
  import { GPU_TEXTURE_USAGE_COPY_SRC } from '../gpu-texture-usage';
@@ -30,6 +35,7 @@ import {
30
35
  TYPED_BLOOM_PASS_NAMES,
31
36
  type TypedTemporalResolveTargets,
32
37
  } from '../typed-render-graph-primitives';
38
+ import { renderExtentSize } from './render-extent';
33
39
  import {
34
40
  addAutoExposureExposurePass,
35
41
  addAutoExposureGraphPasses,
@@ -42,22 +48,81 @@ interface StandardPostSurface {
42
48
  readonly storage: RenderPipelineTarget;
43
49
  }
44
50
 
51
+ export const STANDARD_BLOOM_MAX_LEVELS = 5;
52
+
45
53
  /** One authored Bloom contract drives declaration and compiled-graph validation. */
46
54
  export const STANDARD_BLOOM_TARGET_SPEC = {
47
- composited: { label: 'bloom-composited', format: 'rgba16float', size: 'surface' },
48
- bright: { label: 'bloom-bright', format: 'rgba16float', size: 'half-surface' },
49
- blurH: { label: 'bloom-blur-h', format: 'rgba16float', size: 'half-surface' },
50
- blurV: { label: 'bloom-blur-v', format: 'rgba16float', size: 'half-surface' },
51
- } as const satisfies Record<
52
- 'composited' | 'bright' | 'blurH' | 'blurV',
53
- Pick<GraphTextureDescriptor, 'format' | 'size'> & { readonly label: string }
54
- >;
55
+ composited: { label: 'bloom-composited', format: 'rgba16float' },
56
+ downsamplePrefix: 'bloom-downsample-',
57
+ upsamplePrefix: 'bloom-upsample-',
58
+ } as const;
59
+
60
+ export interface StandardBloomLevelDimensions {
61
+ readonly width: number;
62
+ readonly height: number;
63
+ }
64
+
65
+ /** Derive the bounded ceil-halving output pyramid, including D0. */
66
+ export function deriveStandardBloomLevels(
67
+ outputWidth: number,
68
+ outputHeight: number,
69
+ ): readonly StandardBloomLevelDimensions[] {
70
+ const levels: StandardBloomLevelDimensions[] = [];
71
+ let width = Math.max(1, Math.ceil(outputWidth / 2));
72
+ let height = Math.max(1, Math.ceil(outputHeight / 2));
73
+ for (let level = 0; level < STANDARD_BLOOM_MAX_LEVELS; level += 1) {
74
+ levels.push({ width, height });
75
+ if (width === 1 && height === 1) break;
76
+ width = Math.max(1, Math.ceil(width / 2));
77
+ height = Math.max(1, Math.ceil(height / 2));
78
+ }
79
+ return levels;
80
+ }
81
+
82
+ export interface StandardBloomTargetSpecs {
83
+ readonly composited: GraphTextureDescriptor & { readonly label: string };
84
+ readonly downsample: readonly (GraphTextureDescriptor & { readonly label: string })[];
85
+ readonly upsample: readonly (GraphTextureDescriptor & { readonly label: string })[];
86
+ readonly levels: readonly StandardBloomLevelDimensions[];
87
+ }
88
+
89
+ function standardBloomTargetSpecs(
90
+ outputWidth: number,
91
+ outputHeight: number,
92
+ ): StandardBloomTargetSpecs {
93
+ const levels = deriveStandardBloomLevels(outputWidth, outputHeight);
94
+ return {
95
+ composited: {
96
+ label: STANDARD_BLOOM_TARGET_SPEC.composited.label,
97
+ format: STANDARD_BLOOM_TARGET_SPEC.composited.format,
98
+ size: { width: outputWidth, height: outputHeight },
99
+ domain: 'linear-hdr',
100
+ },
101
+ downsample: levels.map((size, level) => ({
102
+ label: `${STANDARD_BLOOM_TARGET_SPEC.downsamplePrefix}${level}`,
103
+ format: 'rgba16float' as const,
104
+ size,
105
+ domain: 'linear-hdr' as const,
106
+ })),
107
+ upsample: levels.slice(0, -1).map((size, level) => ({
108
+ label: `${STANDARD_BLOOM_TARGET_SPEC.upsamplePrefix}${level}`,
109
+ format: 'rgba16float' as const,
110
+ size,
111
+ domain: 'linear-hdr' as const,
112
+ })),
113
+ levels,
114
+ };
115
+ }
55
116
 
56
117
  export interface StandardBloomGraphInspection {
57
118
  readonly status: 'empty' | 'valid' | 'invalid';
58
119
  readonly targetCount: number;
59
120
  readonly targetBytes: number;
60
121
  readonly passCount: number;
122
+ readonly levelCount: number;
123
+ readonly levelDimensions: readonly StandardBloomLevelDimensions[];
124
+ readonly downsamplePassCount: number;
125
+ readonly upsamplePassCount: number;
61
126
  }
62
127
 
63
128
  const emptyBloomGraphInspection = (): StandardBloomGraphInspection => ({
@@ -65,6 +130,10 @@ const emptyBloomGraphInspection = (): StandardBloomGraphInspection => ({
65
130
  targetCount: 0,
66
131
  targetBytes: 0,
67
132
  passCount: 0,
133
+ levelCount: 0,
134
+ levelDimensions: [],
135
+ downsamplePassCount: 0,
136
+ upsamplePassCount: 0,
68
137
  });
69
138
 
70
139
  const invalidBloomGraphInspection = (): StandardBloomGraphInspection => ({
@@ -72,21 +141,23 @@ const invalidBloomGraphInspection = (): StandardBloomGraphInspection => ({
72
141
  targetCount: 0,
73
142
  targetBytes: 0,
74
143
  passCount: 0,
144
+ levelCount: 0,
145
+ levelDimensions: [],
146
+ downsamplePassCount: 0,
147
+ upsamplePassCount: 0,
75
148
  });
76
149
 
77
- function textureBytes(
78
- resource: CompiledRenderGraphInfo['resources'][number],
79
- expected: (typeof STANDARD_BLOOM_TARGET_SPEC)[keyof typeof STANDARD_BLOOM_TARGET_SPEC],
80
- ): number {
150
+ type CompiledBloomResource = CompiledRenderGraphInfo['resources'][number];
151
+
152
+ function textureBytes(resource: CompiledBloomResource): number | undefined {
81
153
  const descriptor = resource.descriptor;
82
154
  if (
155
+ resource.kind !== 'texture' ||
83
156
  descriptor === undefined ||
84
157
  descriptor.kind !== 'texture' ||
85
- descriptor.format !== expected.format ||
86
- !('size' in descriptor) ||
87
- descriptor.size !== expected.size
158
+ descriptor.format !== 'rgba16float'
88
159
  )
89
- return 0;
160
+ return undefined;
90
161
  const texelBytes = 8;
91
162
  let bytes = 0;
92
163
  for (let level = 0; level < descriptor.mipLevelCount; level += 1) {
@@ -96,7 +167,56 @@ function textureBytes(
96
167
  descriptor.depthOrArrayLayers *
97
168
  texelBytes;
98
169
  }
99
- return bytes * descriptor.sampleCount;
170
+ const descriptorBytes = bytes * descriptor.sampleCount;
171
+ return resource.byteSize === descriptorBytes && descriptorBytes > 0 ? descriptorBytes : undefined;
172
+ }
173
+
174
+ function resourceSize(
175
+ resource: CompiledBloomResource,
176
+ ): { readonly width: number; readonly height: number } | undefined {
177
+ const descriptor = resource.descriptor;
178
+ if (resource.kind !== 'texture' || descriptor.kind !== 'texture') return undefined;
179
+ if (typeof descriptor.size === 'string') return undefined;
180
+ if (
181
+ resource.extent === undefined ||
182
+ resource.extent.width !== descriptor.width ||
183
+ resource.extent.height !== descriptor.height ||
184
+ resource.extent.depthOrArrayLayers !== descriptor.depthOrArrayLayers
185
+ ) {
186
+ return undefined;
187
+ }
188
+ if (
189
+ descriptor.format !== 'rgba16float' ||
190
+ descriptor.domain !== 'linear-hdr' ||
191
+ descriptor.width <= 0 ||
192
+ descriptor.height <= 0 ||
193
+ descriptor.depthOrArrayLayers !== 1 ||
194
+ descriptor.mipLevelCount !== 1 ||
195
+ descriptor.sampleCount !== 1 ||
196
+ resource.dimension !== '2d' ||
197
+ descriptor.size.width !== descriptor.width ||
198
+ descriptor.size.height !== descriptor.height ||
199
+ textureBytes(resource) === undefined
200
+ ) {
201
+ return undefined;
202
+ }
203
+ return { width: descriptor.width, height: descriptor.height };
204
+ }
205
+
206
+ function hasPassAccesses(
207
+ pass: CompiledRenderGraphInfo['passes'][number] | undefined,
208
+ accesses: readonly { readonly resource: string; readonly usage: string }[],
209
+ ): boolean {
210
+ return (
211
+ pass !== undefined &&
212
+ pass.kind === 'raster' &&
213
+ pass.accesses.length === accesses.length &&
214
+ accesses.every(
215
+ (access, index) =>
216
+ pass.accesses[index]?.resource === access.resource &&
217
+ pass.accesses[index]?.usage === access.usage,
218
+ )
219
+ );
100
220
  }
101
221
 
102
222
  /** Derive Bloom target/pass facts solely from the compiled Standard graph. */
@@ -104,33 +224,125 @@ export function inspectStandardBloomGraph(
104
224
  graph: CompiledRenderGraphInfo | undefined,
105
225
  ): StandardBloomGraphInspection {
106
226
  if (graph === undefined) return emptyBloomGraphInspection();
107
- type BloomTargetSpec =
108
- (typeof STANDARD_BLOOM_TARGET_SPEC)[keyof typeof STANDARD_BLOOM_TARGET_SPEC];
109
- const targetSpec = new Map<string, BloomTargetSpec>(
110
- Object.values(STANDARD_BLOOM_TARGET_SPEC).map((entry) => [entry.label, entry] as const),
227
+ const composited = graph.resources.filter(
228
+ (resource) => resource.label === STANDARD_BLOOM_TARGET_SPEC.composited.label,
111
229
  );
112
- const targets = graph.resources.flatMap((resource) => {
113
- const expected = targetSpec.get(resource.label);
114
- return expected === undefined ? [] : [{ resource, expected }];
115
- });
116
- const passNames = new Set<string>(Object.values(TYPED_BLOOM_PASS_NAMES));
117
- const passes = graph.passes.filter((pass) => passNames.has(pass.name));
230
+ const downsample = graph.resources
231
+ .filter((resource) => resource.label.startsWith(STANDARD_BLOOM_TARGET_SPEC.downsamplePrefix))
232
+ .sort((a, b) => a.label.localeCompare(b.label, undefined, { numeric: true }));
233
+ const upsample = graph.resources
234
+ .filter((resource) => resource.label.startsWith(STANDARD_BLOOM_TARGET_SPEC.upsamplePrefix))
235
+ .sort((a, b) => a.label.localeCompare(b.label, undefined, { numeric: true }));
236
+ const targets = [...composited, ...downsample, ...upsample];
237
+ const passes = graph.passes
238
+ .filter(
239
+ (pass) =>
240
+ pass.name === TYPED_BLOOM_PASS_NAMES.composite ||
241
+ pass.name.startsWith(`${TYPED_BLOOM_PASS_NAMES.downsample}-`) ||
242
+ pass.name.startsWith(`${TYPED_BLOOM_PASS_NAMES.upsample}-`),
243
+ )
244
+ .sort((left, right) => left.executionIndex - right.executionIndex);
118
245
  if (targets.length === 0 && passes.length === 0) return emptyBloomGraphInspection();
246
+ if (composited.length !== 1) return invalidBloomGraphInspection();
247
+ const compositedResource = composited[0];
248
+ if (compositedResource === undefined) return invalidBloomGraphInspection();
249
+ const compositedSize = resourceSize(compositedResource);
250
+ if (compositedSize === undefined) return invalidBloomGraphInspection();
251
+
252
+ const expected = standardBloomTargetSpecs(compositedSize.width, compositedSize.height);
253
+ const expectedDownsampleLabels = expected.downsample.map((entry) => entry.label);
254
+ const expectedUpsampleLabels = expected.upsample.map((entry) => entry.label);
255
+ const orderedDownsample = downsample.sort((left, right) =>
256
+ left.label.localeCompare(right.label, undefined, { numeric: true }),
257
+ );
258
+ const orderedUpsample = upsample.sort((left, right) =>
259
+ left.label.localeCompare(right.label, undefined, { numeric: true }),
260
+ );
119
261
  const completeTargetSet =
120
- targets.length === Object.values(STANDARD_BLOOM_TARGET_SPEC).length &&
121
- targets.every(({ resource, expected }) => textureBytes(resource, expected) > 0);
122
- const completePassSet = passes.length === Object.values(TYPED_BLOOM_PASS_NAMES).length;
123
- if (!completeTargetSet || !completePassSet) {
262
+ targets.length === 1 + expectedDownsampleLabels.length + expectedUpsampleLabels.length &&
263
+ orderedDownsample.length === expectedDownsampleLabels.length &&
264
+ orderedUpsample.length === expectedUpsampleLabels.length &&
265
+ orderedDownsample.every(
266
+ (resource, level) => resource.label === expectedDownsampleLabels[level],
267
+ ) &&
268
+ orderedUpsample.every((resource, level) => resource.label === expectedUpsampleLabels[level]) &&
269
+ orderedDownsample.every(
270
+ (resource, level) =>
271
+ resourceSize(resource)?.width === expected.levels[level]?.width &&
272
+ resourceSize(resource)?.height === expected.levels[level]?.height,
273
+ ) &&
274
+ orderedUpsample.every(
275
+ (resource, level) =>
276
+ resourceSize(resource)?.width === expected.levels[level]?.width &&
277
+ resourceSize(resource)?.height === expected.levels[level]?.height,
278
+ );
279
+ const expectedPassNames = [
280
+ ...expectedDownsampleLabels,
281
+ ...[...expectedUpsampleLabels].reverse(),
282
+ TYPED_BLOOM_PASS_NAMES.composite,
283
+ ];
284
+ const completePassSet =
285
+ passes.length === expected.levels.length + expected.upsample.length + 1 &&
286
+ passes.every((pass, index) => pass.name === expectedPassNames[index]);
287
+ const sceneLabel = passes[0]?.accesses[0]?.resource;
288
+ const passTopology =
289
+ completePassSet &&
290
+ sceneLabel !== undefined &&
291
+ !sceneLabel.startsWith(STANDARD_BLOOM_TARGET_SPEC.downsamplePrefix) &&
292
+ !sceneLabel.startsWith(STANDARD_BLOOM_TARGET_SPEC.upsamplePrefix) &&
293
+ sceneLabel !== STANDARD_BLOOM_TARGET_SPEC.composited.label &&
294
+ graph.resources.some((resource) => resource.label === sceneLabel) &&
295
+ orderedDownsample.every((_, level) =>
296
+ hasPassAccesses(passes[level], [
297
+ {
298
+ resource: level === 0 ? sceneLabel : `bloom-downsample-${level - 1}`,
299
+ usage: 'sampled-read',
300
+ },
301
+ { resource: `bloom-downsample-${level}`, usage: 'color-attachment' },
302
+ ]),
303
+ ) &&
304
+ orderedUpsample.every((_, level) => {
305
+ const passIndex = expected.levels.length + expected.upsample.length - 1 - level;
306
+ return hasPassAccesses(passes[passIndex], [
307
+ { resource: `bloom-downsample-${level}`, usage: 'sampled-read' },
308
+ {
309
+ resource:
310
+ level === expected.levels.length - 2
311
+ ? `bloom-downsample-${level + 1}`
312
+ : `bloom-upsample-${level + 1}`,
313
+ usage: 'sampled-read',
314
+ },
315
+ { resource: `bloom-upsample-${level}`, usage: 'color-attachment' },
316
+ ]);
317
+ }) &&
318
+ hasPassAccesses(passes.at(-1), [
319
+ { resource: sceneLabel, usage: 'sampled-read' },
320
+ {
321
+ resource: expected.levels.length === 1 ? 'bloom-downsample-0' : 'bloom-upsample-0',
322
+ usage: 'sampled-read',
323
+ },
324
+ { resource: STANDARD_BLOOM_TARGET_SPEC.composited.label, usage: 'color-attachment' },
325
+ ]);
326
+ if (!completeTargetSet || !passTopology) {
327
+ return invalidBloomGraphInspection();
328
+ }
329
+ const levelDimensions = orderedDownsample.flatMap((resource) => {
330
+ const size = resourceSize(resource);
331
+ return size === undefined ? [] : [size];
332
+ });
333
+ if (levelDimensions.length !== orderedDownsample.length) {
124
334
  return invalidBloomGraphInspection();
125
335
  }
336
+ const targetBytes = targets.reduce((bytes, resource) => bytes + (textureBytes(resource) ?? 0), 0);
126
337
  return {
127
338
  status: 'valid',
128
339
  targetCount: targets.length,
129
- targetBytes: targets.reduce(
130
- (bytes, target) => bytes + textureBytes(target.resource, target.expected),
131
- 0,
132
- ),
340
+ targetBytes,
133
341
  passCount: passes.length,
342
+ levelCount: orderedDownsample.length,
343
+ levelDimensions,
344
+ downsamplePassCount: orderedDownsample.length,
345
+ upsamplePassCount: orderedUpsample.length,
134
346
  };
135
347
  }
136
348
 
@@ -160,8 +372,8 @@ function missingTemporalContributor(
160
372
  /**
161
373
  * Build the one Standard post chain shared by direct and clustered lighting.
162
374
  * Bloom is admitted before any Bloom target is declared, keeping the disabled
163
- * path exact-zero while preserving the existing half-resolution four-pass
164
- * implementation for the enabled path.
375
+ * path exact-zero while building one bounded five-level HDR
376
+ * downsample/tent-upsample pyramid for the enabled path.
165
377
  */
166
378
  export function addStandardPost(
167
379
  context: RenderPipelineBuildContext<RenderPipelineFrame>,
@@ -179,14 +391,27 @@ export function addStandardPost(
179
391
  lane: topology.standardProfile?.renderPath === 'deferred' ? 'clustered' : 'direct',
180
392
  temporal: !clearOnly && topology.camera.antialias === 'taa',
181
393
  meter: topology.output?.autoExposure === true,
182
- bloom: !clearOnly && topology.camera.bloom === 'on' && topology.camera.tonemap !== 'none',
394
+ bloom: !clearOnly && standardBloomAdmitted(topology.camera),
183
395
  dof: !clearOnly && topology.camera.depthOfField !== undefined,
184
396
  exposure: topology.output?.autoExposure === true,
185
397
  whiteBalance: topology.output?.whiteBalance === true,
186
398
  lut: topology.output?.colorLut === true,
399
+ barrelDistortion: topology.camera.barrelDistortion === true,
187
400
  fxaa: !clearOnly && topology.camera.antialias === 'fxaa',
188
401
  outputEncoding: 'explicit-oetf',
189
402
  });
403
+ if (
404
+ outputPlan.features.barrelDistortion &&
405
+ context.capabilities?.rgba16floatRenderable !== true
406
+ ) {
407
+ return err(
408
+ new RenderFeatureCapabilityMissingError(
409
+ BARREL_DISTORTION_FEATURE_IDENTITY,
410
+ 0,
411
+ 'rgba16floatRenderable',
412
+ ),
413
+ );
414
+ }
190
415
  const hdr =
191
416
  !clearOnly && (topology.camera.tonemap !== 'none' || topology.camera.antialias === 'taa');
192
417
  // Bloom is an HDR-domain effect and its recorders intentionally no-op when
@@ -202,7 +427,15 @@ export function addStandardPost(
202
427
  const rawOnly = !clearOnly && topology.surface.profile?.kind === 'raw-only';
203
428
  const outputDither = resolveOutputDither(topology.config);
204
429
  const motionBlur = !clearOnly && topology.temporal?.motionBlur === true;
205
- const postEffects = clearOnly ? [] : (topology.config?.postEffects ?? []);
430
+ // The barrel declaration is supplied by the ordinary feature host so its
431
+ // shader stays prepared and recoverable, but Standard owns its one explicit
432
+ // linear-LDR stage below. Do not send that identity through the generic
433
+ // encoded tail, or storage-buffer lanes would sample the image twice.
434
+ const postEffects = clearOnly
435
+ ? []
436
+ : (topology.config?.postEffects ?? []).filter(
437
+ (identity) => identity !== BARREL_DISTORTION_POST_PROCESS_ID,
438
+ );
206
439
  const rawOnlyPostInput =
207
440
  rawOnly && topology.lane.storageBuffer && postEffects.length > 0
208
441
  ? target(context, 'standard-post-effects-input', {
@@ -220,6 +453,33 @@ export function addStandardPost(
220
453
  const finalPresent = surface.storage;
221
454
  let postInput = scene;
222
455
  let postTemporal = sceneTemporal;
456
+ if (!clearOnly && topology.analyticFog === true) {
457
+ if (depth.sampleCount !== 1)
458
+ return err(
459
+ new RenderGraphError({
460
+ code: 'resource-resolution-failed',
461
+ expected: 'analytic fog receives single-sample scene depth',
462
+ hint: 'select FXAA, TAA or no AA for analytic fog',
463
+ detail: { resourceLabel: 'scene-depth' },
464
+ }),
465
+ );
466
+ const fogged = target(context, 'analytic-fog-color', {
467
+ format: 'rgba16float',
468
+ size:
469
+ topology.extent === undefined ? 'surface' : renderExtentSize(topology.extent, 'internal'),
470
+ domain: hdr ? 'linear-hdr' : 'linear-ldr',
471
+ });
472
+ if (!fogged.ok) return fogged;
473
+ const fog = addTypedFullscreenPass(context.graph, {
474
+ name: 'analytic-fog',
475
+ shader: 'forgeax.analytic-fog',
476
+ input: postInput,
477
+ depth,
478
+ output: fogged.value,
479
+ });
480
+ if (!fog.ok) return fog;
481
+ postInput = fogged.value;
482
+ }
223
483
 
224
484
  const autoExposure = context.standardOutput?.autoExposure;
225
485
  if (outputPlan.features.exposure && autoExposure === undefined) {
@@ -241,7 +501,7 @@ export function addStandardPost(
241
501
  return err(missingTemporalContributor(topology, 'forgeax::standard::taa-history'));
242
502
  }
243
503
  const resolveTargets: TypedTemporalResolveTargets = {
244
- scene,
504
+ scene: postInput,
245
505
  depth,
246
506
  currentTemporal: sceneTemporal,
247
507
  ...(coverage === undefined ? {} : { coverage }),
@@ -262,26 +522,40 @@ export function addStandardPost(
262
522
  postTemporal = history.currentTemporal;
263
523
  }
264
524
 
525
+ // Meter the temporally resolved color before lens-domain filters. Motion
526
+ // Blur and Bloom must consume a single exposure decision for this frame;
527
+ // running the meter after either filter makes the measured luminance depend
528
+ // on the authored streak radius and changes the exposure feedback loop.
529
+ if (outputPlan.features.exposure && autoExposure !== undefined) {
530
+ const added = addAutoExposureGraphPasses(context, {
531
+ source: postInput,
532
+ resources: autoExposure,
533
+ width: topology.surface.width,
534
+ height: topology.surface.height,
535
+ });
536
+ if (!added.ok) return added;
537
+ }
538
+
265
539
  // Feature projection and the built-in fallback share one target contract.
266
540
  // The projection runs after TAA so Motion Blur consumes the resolved color,
267
541
  // then both paths feed the same linear float target into Bloom/Output.
542
+ const featureTargets = [
543
+ {
544
+ kind: 'scene-color' as const,
545
+ texture: scene.texture,
546
+ view: scene.view,
547
+ format: scene.format,
548
+ sampleCount: scene.sampleCount,
549
+ },
550
+ {
551
+ kind: 'scene-depth' as const,
552
+ texture: depth.texture,
553
+ view: depth.view,
554
+ format: depth.format,
555
+ sampleCount: depth.sampleCount,
556
+ },
557
+ ];
268
558
  if (!clearOnly) {
269
- const featureTargets = [
270
- {
271
- kind: 'scene-color' as const,
272
- texture: scene.texture,
273
- view: scene.view,
274
- format: scene.format,
275
- sampleCount: scene.sampleCount,
276
- },
277
- {
278
- kind: 'scene-depth' as const,
279
- texture: depth.texture,
280
- view: depth.view,
281
- format: depth.format,
282
- sampleCount: depth.sampleCount,
283
- },
284
- ];
285
559
  if (motionBlur) {
286
560
  if (postTemporal === undefined) {
287
561
  return err(
@@ -294,10 +568,16 @@ export function addStandardPost(
294
568
  domain: hdr ? 'linear-hdr' : 'linear-ldr',
295
569
  });
296
570
  if (!blurred.ok) return blurred;
297
- const features = context.contributeFeatures(featureTargets, [postTemporal], {
298
- 'motion-input': postInput,
299
- 'motion-output': blurred.value,
300
- });
571
+ const features = context.contributeFeatures(
572
+ featureTargets,
573
+ [postTemporal],
574
+ {
575
+ 'motion-input': postInput,
576
+ 'motion-output': blurred.value,
577
+ },
578
+ [],
579
+ { exclude: [BARREL_DISTORTION_FEATURE_IDENTITY] },
580
+ );
301
581
  if (!features.ok) return features;
302
582
  if (context.hasFeature?.('forgeax.motion-blur') === true) {
303
583
  postInput = blurred.value;
@@ -310,23 +590,14 @@ export function addStandardPost(
310
590
  const features = context.contributeFeatures(
311
591
  featureTargets,
312
592
  sceneTemporal === undefined ? [] : [sceneTemporal],
593
+ {},
594
+ [],
595
+ { exclude: [BARREL_DISTORTION_FEATURE_IDENTITY] },
313
596
  );
314
597
  if (!features.ok) return features;
315
598
  }
316
599
  }
317
600
 
318
- // Meter the temporally resolved color before DoF/Bloom. This preserves the
319
- // Standard order: temporal -> motion -> meter -> DoF -> bloom -> output.
320
- if (outputPlan.features.exposure && autoExposure !== undefined) {
321
- const added = addAutoExposureGraphPasses(context, {
322
- source: postInput,
323
- resources: autoExposure,
324
- width: topology.surface.width,
325
- height: topology.surface.height,
326
- });
327
- if (!added.ok) return added;
328
- }
329
-
330
601
  if (outputPlan.features.dof) {
331
602
  const dof = addDepthOfFieldPasses(
332
603
  {
@@ -343,38 +614,30 @@ export function addStandardPost(
343
614
  if (!dof.ok) return dof;
344
615
  postInput = dof.value;
345
616
  }
346
-
347
617
  if (bloomActive) {
348
- const composited = target(
349
- context,
350
- STANDARD_BLOOM_TARGET_SPEC.composited.label,
351
- STANDARD_BLOOM_TARGET_SPEC.composited,
352
- );
618
+ const outputWidth = topology.extent?.outputWidth ?? topology.surface.width;
619
+ const outputHeight = topology.extent?.outputHeight ?? topology.surface.height;
620
+ const bloomSpecs = standardBloomTargetSpecs(outputWidth, outputHeight);
621
+ const composited = target(context, bloomSpecs.composited.label, bloomSpecs.composited);
353
622
  if (!composited.ok) return composited;
354
- const bright = target(
355
- context,
356
- STANDARD_BLOOM_TARGET_SPEC.bright.label,
357
- STANDARD_BLOOM_TARGET_SPEC.bright,
358
- );
359
- if (!bright.ok) return bright;
360
- const blurH = target(
361
- context,
362
- STANDARD_BLOOM_TARGET_SPEC.blurH.label,
363
- STANDARD_BLOOM_TARGET_SPEC.blurH,
364
- );
365
- if (!blurH.ok) return blurH;
366
- const blurV = target(
367
- context,
368
- STANDARD_BLOOM_TARGET_SPEC.blurV.label,
369
- STANDARD_BLOOM_TARGET_SPEC.blurV,
370
- );
371
- if (!blurV.ok) return blurV;
623
+ const downsample: RenderPipelineTarget[] = [];
624
+ for (const spec of bloomSpecs.downsample) {
625
+ const level = target(context, spec.label, spec);
626
+ if (!level.ok) return level;
627
+ downsample.push(level.value);
628
+ }
629
+ const upsample: RenderPipelineTarget[] = [];
630
+ for (const spec of bloomSpecs.upsample) {
631
+ const level = target(context, spec.label, spec);
632
+ if (!level.ok) return level;
633
+ upsample.push(level.value);
634
+ }
372
635
  const bloom = addTypedBloomPasses(context.graph, {
373
636
  scene: postInput,
374
637
  composited: composited.value,
375
- bright: bright.value,
376
- blurH: blurH.value,
377
- blurV: blurV.value,
638
+ downsample,
639
+ upsample,
640
+ levelDimensions: bloomSpecs.levels,
378
641
  });
379
642
  if (!bloom.ok) return bloom;
380
643
  postInput = composited.value;
@@ -409,6 +672,7 @@ export function addStandardPost(
409
672
  outputPlan.features.lut ||
410
673
  outputPlan.features.exposure ||
411
674
  outputPlan.features.whiteBalance ||
675
+ outputPlan.features.barrelDistortion ||
412
676
  // A receipt-bound observation request is an explicit producer demand, not
413
677
  // a new authored color feature. When a caller asks for the linear-LDR
414
678
  // domain on the ordinary ACES path, retain the same tone/output boundary
@@ -460,11 +724,42 @@ export function addStandardPost(
460
724
  postInput = lutOutput.value;
461
725
  }
462
726
 
463
- if (rawOnly) {
727
+ // Debug geometry is world-space scene content. Insert it before the spatial
728
+ // warp so its lines and markers bend with the rendered world. Screen-space
729
+ // diagnostics remain on the final surface below when no warp is active.
730
+ const debugOverlayBeforeBarrel = outputPlan.features.barrelDistortion;
731
+ if (rawOnly || debugOverlayBeforeBarrel) {
464
732
  const overlay = addTypedDebugOverlayPass(context.graph, postInput);
465
733
  if (!overlay.ok) return overlay;
466
734
  }
467
735
 
736
+ if (outputPlan.features.barrelDistortion) {
737
+ const barrelOutput = target(context, 'standard-barrel-distortion', {
738
+ format: 'rgba16float',
739
+ size: 'surface',
740
+ domain: 'linear-ldr',
741
+ });
742
+ if (!barrelOutput.ok) return barrelOutput;
743
+ const barrel = context.contributeFeatures(
744
+ featureTargets,
745
+ [],
746
+ { 'barrel-input': postInput, 'barrel-output': barrelOutput.value },
747
+ [],
748
+ { include: [BARREL_DISTORTION_FEATURE_IDENTITY] },
749
+ );
750
+ if (!barrel.ok) return barrel;
751
+ if (context.hasFeature?.(BARREL_DISTORTION_FEATURE_IDENTITY) !== true) {
752
+ return err(
753
+ new RenderFeatureCapabilityMissingError(
754
+ BARREL_DISTORTION_FEATURE_IDENTITY,
755
+ 0,
756
+ 'rgba16floatRenderable',
757
+ ),
758
+ );
759
+ }
760
+ postInput = barrelOutput.value;
761
+ }
762
+
468
763
  if (hdr || linearLdr || fxaa || rawOnly || motionBlur) {
469
764
  if (fxaa) {
470
765
  const output = splitOutput
@@ -568,7 +863,7 @@ export function addStandardPost(
568
863
  if (!effects.ok) return effects;
569
864
  }
570
865
 
571
- return rawOnly
866
+ return rawOnly || debugOverlayBeforeBarrel
572
867
  ? ok(undefined)
573
868
  : addTypedDebugOverlayPass(context.graph, surface.display ?? surface.storage);
574
869
  }
@@ -135,7 +135,7 @@ export interface PipelineBuilderContext {
135
135
  */
136
136
  readonly vertexBuffers: readonly GPUVertexBufferLayout[];
137
137
  /** Explicit layout family selected by the renderer assembly. */
138
- readonly layoutKind?: 'pbr-skin' | 'gpu-driven-skin' | undefined;
138
+ readonly layoutKind?: 'pbr-skin' | 'gpu-driven-skin' | 'gpu-driven-cluster-skin' | undefined;
139
139
  /** Pipeline label (for GPU debug captures); defaults to `pbr-pipeline-${id}`. */
140
140
  readonly label?: string | undefined;
141
141
  /**