@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
@@ -1,6 +1,7 @@
1
1
  import type { BindGroupLayout } from '@forgeax/engine-rhi';
2
2
  import type { MaterialShaderArtifact, ShaderRegistry } from '@forgeax/engine-shader';
3
3
  import { type GpuDrivenPbrProgram, resolveStandardPbrProgram } from '../../gpu-driven/pbr-program';
4
+ import { type PipelineGroup2Contract, resolvePipelineGroup2Contract } from '../../pbr-pipeline';
4
5
  import type { LayoutKind } from '../material-shader-policy';
5
6
  import { type MaterialShaderArtifactRequest, resolveMaterialShaderArtifact } from './assembly';
6
7
 
@@ -42,7 +43,11 @@ export function resolveMaterialPipelineVertexEntry(
42
43
  vertexEntryPoint: string | undefined,
43
44
  authoredVertexEntry: string | undefined,
44
45
  ): string | undefined {
45
- const sceneIndex = layoutKind === 'gpu-driven-pbr' || layoutKind === 'gpu-driven-skin';
46
+ const sceneIndex =
47
+ layoutKind === 'gpu-driven-pbr' ||
48
+ layoutKind === 'gpu-driven-skin' ||
49
+ layoutKind === 'gpu-driven-cluster-pbr' ||
50
+ layoutKind === 'gpu-driven-cluster-skin';
46
51
  // Scene-index is a renderer submission ABI. An authored/direct entry may
47
52
  // accompany the artifact for diagnostics, but it must not replace the
48
53
  // receipt entry when the GPU-driven layout is selected.
@@ -51,6 +56,33 @@ export function resolveMaterialPipelineVertexEntry(
51
56
  : (authoredVertexEntry ?? vertexEntryPoint);
52
57
  }
53
58
 
59
+ /** Keep the recorded group(2) receipt identical to the selected pipeline layout. */
60
+ export function resolveMaterialPipelineGroup2Contract(
61
+ source: string,
62
+ layoutKind: LayoutKind | undefined,
63
+ ): PipelineGroup2Contract {
64
+ switch (layoutKind) {
65
+ case 'hdrp-pbr':
66
+ case 'gpu-driven-cluster-pbr':
67
+ case 'surface-direct-cluster-pbr':
68
+ return 'cluster';
69
+ case 'hdrp-skin':
70
+ case 'gpu-driven-cluster-skin':
71
+ return 'skin-cluster';
72
+ case 'pbr-skin':
73
+ case 'gpu-driven-skin':
74
+ return 'skin';
75
+ case 'pbr':
76
+ case 'gpu-driven-pbr':
77
+ case 'surface-direct-pbr':
78
+ case 'sprite-urp':
79
+ case 'unlit-urp':
80
+ return 'mesh';
81
+ case undefined:
82
+ return resolvePipelineGroup2Contract(source);
83
+ }
84
+ }
85
+
54
86
  export interface MaterialPipelineBindGroupState {
55
87
  readonly meshBindGroupLayout: BindGroupLayout;
56
88
  readonly pbrSkinMeshBindGroupLayout: BindGroupLayout | null;
@@ -58,6 +90,8 @@ export interface MaterialPipelineBindGroupState {
58
90
  readonly hdrpMeshBindGroupLayout?: BindGroupLayout | null;
59
91
  readonly instancesBindGroupLayout: BindGroupLayout;
60
92
  readonly gpuDrivenInstancesBindGroupLayout?: BindGroupLayout | null;
93
+ readonly surfaceDirectInstancesBindGroupLayout?: BindGroupLayout | null;
94
+ readonly gpuDrivenClusterMeshBindGroupLayout?: BindGroupLayout | null;
61
95
  }
62
96
 
63
97
  export function resolveMaterialPipelineBindGroups(
@@ -66,20 +100,27 @@ export function resolveMaterialPipelineBindGroups(
66
100
  clustered = false,
67
101
  ): { readonly meshLayout: BindGroupLayout; readonly instancesLayout: BindGroupLayout } | null {
68
102
  const meshLayout =
69
- clustered && layoutKind === 'gpu-driven-pbr'
70
- ? state.hdrpMeshBindGroupLayout
71
- : clustered && layoutKind === 'gpu-driven-skin'
72
- ? state.hdrpSkinMeshBindGroupLayout
73
- : layoutKind === 'pbr-skin' || layoutKind === 'gpu-driven-skin'
74
- ? state.pbrSkinMeshBindGroupLayout
75
- : layoutKind === 'hdrp-skin'
103
+ layoutKind === 'gpu-driven-cluster-pbr' || layoutKind === 'surface-direct-cluster-pbr'
104
+ ? state.gpuDrivenClusterMeshBindGroupLayout
105
+ : clustered && layoutKind === 'gpu-driven-pbr'
106
+ ? state.hdrpMeshBindGroupLayout
107
+ : clustered && layoutKind === 'gpu-driven-skin'
108
+ ? state.hdrpSkinMeshBindGroupLayout
109
+ : layoutKind === 'gpu-driven-cluster-skin' || layoutKind === 'hdrp-skin'
76
110
  ? state.hdrpSkinMeshBindGroupLayout
77
- : state.meshBindGroupLayout;
111
+ : layoutKind === 'pbr-skin' || layoutKind === 'gpu-driven-skin'
112
+ ? state.pbrSkinMeshBindGroupLayout
113
+ : state.meshBindGroupLayout;
78
114
  if (meshLayout == null) return null;
79
115
  const instancesLayout =
80
- layoutKind === 'gpu-driven-pbr' || layoutKind === 'gpu-driven-skin'
81
- ? state.gpuDrivenInstancesBindGroupLayout
82
- : state.instancesBindGroupLayout;
116
+ layoutKind === 'surface-direct-pbr' || layoutKind === 'surface-direct-cluster-pbr'
117
+ ? state.surfaceDirectInstancesBindGroupLayout
118
+ : layoutKind === 'gpu-driven-pbr' ||
119
+ layoutKind === 'gpu-driven-skin' ||
120
+ layoutKind === 'gpu-driven-cluster-pbr' ||
121
+ layoutKind === 'gpu-driven-cluster-skin'
122
+ ? state.gpuDrivenInstancesBindGroupLayout
123
+ : state.instancesBindGroupLayout;
83
124
  return instancesLayout === null || instancesLayout === undefined
84
125
  ? null
85
126
  : { meshLayout, instancesLayout };
@@ -9,6 +9,7 @@ import { err, ok, RhiError } from '@forgeax/engine-rhi';
9
9
  import {
10
10
  DEFAULT_STANDARD_PBR_PARAM_SCHEMA,
11
11
  findVariantByKey,
12
+ type MaterialShaderEntry,
12
13
  type MaterialShaderManifestEntry,
13
14
  type ShaderCatalog,
14
15
  type ShaderCatalogDevice,
@@ -543,6 +544,10 @@ export type LayoutKind =
543
544
  | 'pbr-skin'
544
545
  | 'gpu-driven-pbr'
545
546
  | 'gpu-driven-skin'
547
+ | 'gpu-driven-cluster-pbr'
548
+ | 'gpu-driven-cluster-skin'
549
+ | 'surface-direct-pbr'
550
+ | 'surface-direct-cluster-pbr'
546
551
  | 'hdrp-pbr'
547
552
  | 'hdrp-skin'
548
553
  | 'sprite-urp'
@@ -781,6 +786,48 @@ export function resolveMaterialShaderBackendArtifactKey(
781
786
  return fallback?.specializationKey ?? materialShaderId;
782
787
  }
783
788
 
789
+ /**
790
+ * Remove the optional cloud-shadow sampler pair from a cooked material when
791
+ * the active device has no spare sampled-texture lanes. Pack-cooked material
792
+ * programs are immutable artifacts and therefore do not carry the engine
793
+ * manifest's capability Cartesian product. The low-limit renderer contract is
794
+ * still explicit: direct solar remains fully lit, while the view BGL stays at
795
+ * its 16-texture limit. Only the cloud sampler declarations and their sample
796
+ * are rewritten; the material's surface, parameters, and lighting remain
797
+ * unchanged.
798
+ */
799
+ export function stripCloudShadowBindingsForLowLimit(source: string): string {
800
+ const textureDeclaration =
801
+ /@group\s*\(\s*0\s*\)\s*@binding\s*\(\s*16\s*\)\s*var\s+(\w+)\s*:\s*texture_2d<f32>\s*;\s*/u;
802
+ const samplerDeclaration =
803
+ /@group\s*\(\s*0\s*\)\s*@binding\s*\(\s*17\s*\)\s*var\s+(\w+)\s*:\s*sampler\s*;\s*/u;
804
+ const textureMatch = textureDeclaration.exec(source);
805
+ const samplerMatch = samplerDeclaration.exec(source);
806
+ if (textureMatch === null || samplerMatch === null) return source;
807
+ const textureName = textureMatch[1];
808
+ const samplerName = samplerMatch[1];
809
+ if (textureName === undefined || samplerName === undefined) return source;
810
+
811
+ let rewritten = source.replace(textureDeclaration, '').replace(samplerDeclaration, '');
812
+ const escapedTexture = textureName.replace(/[.*+?^${}()|[\]\\]/gu, '\\$&');
813
+ const escapedSampler = samplerName.replace(/[.*+?^${}()|[\]\\]/gu, '\\$&');
814
+ const cloudSample = new RegExp(
815
+ `textureSampleLevel\\(\\s*${escapedTexture}\\s*,\\s*${escapedSampler}\\s*,[^;\\n]*\\)`,
816
+ 'gu',
817
+ );
818
+ rewritten = rewritten.replace(cloudSample, 'vec4<f32>(1.0)');
819
+ return rewritten;
820
+ }
821
+
822
+ export function prepareLowLimitMaterialShaderEntry<T extends MaterialShaderEntry>(
823
+ entry: T,
824
+ sampledTextureLimit: number | undefined,
825
+ ): T {
826
+ if ((sampledTextureLimit ?? 0) >= STANDARD_PBR_REQUIRED_SAMPLED_TEXTURES) return entry;
827
+ const source = stripCloudShadowBindingsForLowLimit(entry.source);
828
+ return source === entry.source ? entry : ({ ...entry, source } as T);
829
+ }
830
+
784
831
  export function allowsUnlitPreparedFallback(
785
832
  depthFormatOverride: GPUTextureFormat | null | undefined,
786
833
  vertexLayout: string | undefined,
@@ -822,6 +869,8 @@ export function selectPipelineLayoutForVariant(
822
869
  readonly pbrSkinProbePipelineLayout?: PipelineLayout | null;
823
870
  readonly gpuDrivenPbrPipelineLayout?: PipelineLayout | null;
824
871
  readonly gpuDrivenPbrSkinPipelineLayout?: PipelineLayout | null;
872
+ readonly gpuDrivenClusterPbrPipelineLayout?: PipelineLayout | null;
873
+ readonly gpuDrivenClusterPbrSkinPipelineLayout?: PipelineLayout | null;
825
874
  readonly hdrpSkinPipelineLayout?: PipelineLayout | null;
826
875
  } | null,
827
876
  variantSet: string | undefined,
@@ -835,6 +884,12 @@ export function selectPipelineLayoutForVariant(
835
884
  if (layoutKind === 'gpu-driven-skin') {
836
885
  return state.gpuDrivenPbrSkinPipelineLayout ?? null;
837
886
  }
887
+ if (layoutKind === 'gpu-driven-cluster-pbr') {
888
+ return state.gpuDrivenClusterPbrPipelineLayout ?? null;
889
+ }
890
+ if (layoutKind === 'gpu-driven-cluster-skin') {
891
+ return state.gpuDrivenClusterPbrSkinPipelineLayout ?? null;
892
+ }
838
893
  // bug-20260611: skin layout selection takes precedence over HDRP variant
839
894
  // resolution. HDRP × skin is OOS-1 (plan-strategy R-2 — left for a
840
895
  // dedicated feat); when an HDRP-variant skin call ever lands, we fail
@@ -2,7 +2,10 @@ import type { Result, RhiDevice, ShaderModule } from '@forgeax/engine-rhi';
2
2
  import { RhiError } from '@forgeax/engine-rhi';
3
3
  import type { ShaderCatalog } from '@forgeax/engine-shader';
4
4
 
5
- import { invokeDeviceCreateShaderModule } from './material-shader-policy';
5
+ import {
6
+ invokeDeviceCreateShaderModule,
7
+ prepareLowLimitMaterialShaderEntry,
8
+ } from './material-shader-policy';
6
9
  import { runShimStep } from './renderer-helpers';
7
10
 
8
11
  type AsyncCreateShaderModule = (
@@ -37,12 +40,18 @@ export async function prewarmRequiredMaterialShaders({
37
40
  hint: `add material shader '${materialShaderId}' to the shader manifest or remove it from the feature declaration`,
38
41
  });
39
42
  }
43
+ // Prewarm and lazy pipelines share a module label, so they must compile
44
+ // the same capability-adjusted source on the replacement device.
45
+ const entry = prepareLowLimitMaterialShaderEntry(
46
+ lookup.value,
47
+ rhiDevice.limits.maxSampledTexturesPerShaderStage,
48
+ );
40
49
  const label = `module-${materialShaderId}`;
41
50
  const shaderResult = await runShimStep(
42
51
  () =>
43
52
  asyncCreateShaderModule
44
- ? asyncCreateShaderModule(rhiDevice, { code: lookup.value.source, label })
45
- : invokeDeviceCreateShaderModule(rhiDevice, { code: lookup.value.source, label }),
53
+ ? asyncCreateShaderModule(rhiDevice, { code: entry.source, label })
54
+ : invokeDeviceCreateShaderModule(rhiDevice, { code: entry.source, label }),
46
55
  'shader-compile-failed',
47
56
  `declared render feature material shader '${materialShaderId}' compiled`,
48
57
  `inspect the composed WGSL for '${materialShaderId}' and check device.features`,
@@ -50,28 +59,30 @@ export async function prewarmRequiredMaterialShaders({
50
59
  if (!shaderResult.ok) throw shaderResult.error;
51
60
  seedShaderModule(label, shaderResult.value);
52
61
 
53
- const prewarmedSources = new Map<string, ShaderModule>([
54
- [lookup.value.source, shaderResult.value],
55
- ]);
62
+ const prewarmedSources = new Map<string, ShaderModule>([[entry.source, shaderResult.value]]);
56
63
  const manifestEntry = [...registry.materialShaderManifestEntries()].find(
57
64
  (candidate) => candidate.identifier === materialShaderId,
58
65
  );
59
66
  if (manifestEntry === undefined) continue;
60
67
 
61
68
  for (const variant of manifestEntry.variants) {
69
+ const variantSource = prepareLowLimitMaterialShaderEntry(
70
+ { ...entry, source: variant.composedWgsl },
71
+ rhiDevice.limits.maxSampledTexturesPerShaderStage,
72
+ ).source;
62
73
  const variantLabel = `module-${materialShaderId}#${variant.definesKey}`;
63
74
  if (variantLabel === label) continue;
64
- let variantModule = prewarmedSources.get(variant.composedWgsl);
75
+ let variantModule = prewarmedSources.get(variantSource);
65
76
  if (variantModule === undefined) {
66
77
  const variantResult = await runShimStep(
67
78
  () =>
68
79
  asyncCreateShaderModule
69
80
  ? asyncCreateShaderModule(rhiDevice, {
70
- code: variant.composedWgsl,
81
+ code: variantSource,
71
82
  label: variantLabel,
72
83
  })
73
84
  : invokeDeviceCreateShaderModule(rhiDevice, {
74
- code: variant.composedWgsl,
85
+ code: variantSource,
75
86
  label: variantLabel,
76
87
  }),
77
88
  'shader-compile-failed',
@@ -80,7 +91,7 @@ export async function prewarmRequiredMaterialShaders({
80
91
  );
81
92
  if (!variantResult.ok) throw variantResult.error;
82
93
  variantModule = variantResult.value;
83
- prewarmedSources.set(variant.composedWgsl, variantModule);
94
+ prewarmedSources.set(variantSource, variantModule);
84
95
  }
85
96
  seedShaderModule(variantLabel, variantModule);
86
97
  }
@@ -0,0 +1,17 @@
1
+ import { MOTION_BLUR_PARAMS_BYTE_SIZE } from '../features/motion-blur/motion-blur-params';
2
+ import type { PostProcessShaderEntry } from '../fullscreen-post-process-pass';
3
+ import type { RenderSystem } from '../render-system';
4
+
5
+ export function registerMotionBlurPostProcess(
6
+ renderSystem: Pick<RenderSystem, 'registerBuiltinPostProcess'>,
7
+ source: string,
8
+ ): void {
9
+ renderSystem.registerBuiltinPostProcess('forgeax.motion-blur', {
10
+ source,
11
+ params: {
12
+ byteSize: MOTION_BLUR_PARAMS_BYTE_SIZE,
13
+ defaultValue: new Uint8Array(MOTION_BLUR_PARAMS_BYTE_SIZE),
14
+ },
15
+ reads: ['scene-color', 'scene-temporal'],
16
+ } satisfies PostProcessShaderEntry);
17
+ }
@@ -30,6 +30,19 @@ export function attachDeviceLostFanout(
30
30
  onStaleLoss,
31
31
  onDeviceLost,
32
32
  } = registries;
33
+ if (pack._internal_getRawDevice && pack.translateErrorEventToRhiError) {
34
+ const backendDevice = pack._internal_getRawDevice(device);
35
+ if (backendDevice && typeof backendDevice === 'object') {
36
+ const target = backendDevice as {
37
+ onuncapturederror?: ((event: unknown) => void) | null;
38
+ };
39
+ target.onuncapturederror = (event: unknown): void => {
40
+ if (generation !== currentGeneration()) return;
41
+ const translated = pack.translateErrorEventToRhiError?.(event);
42
+ if (translated && !translated.ok) errorRegistry.fire(translated.error);
43
+ };
44
+ }
45
+ }
33
46
  const dispatch = (safe: {
34
47
  readonly reason: 'destroyed' | 'unknown';
35
48
  readonly message: string;
@@ -126,6 +126,8 @@ export interface RendererRecoveryDependencies {
126
126
  readonly getCandidateMaterialShaderUvSetCounts: () => Map<string, number> | undefined;
127
127
  readonly setCandidateMaterialShaderUvSetCounts: (state: Map<string, number> | undefined) => void;
128
128
  readonly setCandidateEmptyPostProcessBgl: (layout: BindGroupLayout | null | undefined) => void;
129
+ readonly getShaderModuleAdapter: () => ShaderDeviceAdapterInternal;
130
+ readonly getImmediateShaderModuleAdapter: () => ShaderDeviceAdapterInternal;
129
131
  readonly getShader: () => ShaderCatalog;
130
132
  readonly assets: AssetRegistry;
131
133
  readonly adaptMipmapShaderModuleFactory: (
@@ -197,6 +199,8 @@ export function createRendererRecovery(deps: RendererRecoveryDependencies): Rend
197
199
  getCandidateMaterialShaderUvSetCounts,
198
200
  setCandidateMaterialShaderUvSetCounts,
199
201
  setCandidateEmptyPostProcessBgl,
202
+ getShaderModuleAdapter,
203
+ getImmediateShaderModuleAdapter,
200
204
  getShader,
201
205
  assets,
202
206
  adaptMipmapShaderModuleFactory,
@@ -319,24 +323,8 @@ export function createRendererRecovery(deps: RendererRecoveryDependencies): Rend
319
323
  setCandidatePipelineCacheState(candidateState.pipelineCacheState);
320
324
  setCandidateMaterialShaderUvSetCounts(candidateState.materialShaderUvSetCounts);
321
325
  setCandidateEmptyPostProcessBgl(candidateState.emptyPostProcessBgl);
322
- // Copy only the active catalog's CPU declarations into the candidate.
323
- // Its manifest/module cache remains candidate-owned, so no lost-device
324
- // ShaderModule can cross the recovery boundary while late-installed
325
- // material shaders remain available to the normal builder.
326
- const activeShaderCatalog = getActiveShaderState().shaderInstance;
327
- if (activeShaderCatalog !== null) {
328
- const candidateShaderCatalog = getShader();
329
- for (const identifier of activeShaderCatalog.materialShaderIdentifiers()) {
330
- const entry = activeShaderCatalog.findMaterialArtifact(identifier);
331
- if (entry.ok && !candidateShaderCatalog.findMaterialArtifact(identifier).ok) {
332
- candidateShaderCatalog.installMaterialArtifact(identifier, {
333
- source: entry.value.source,
334
- paramSchema: entry.value.paramSchema,
335
- ...(entry.value.receipt === undefined ? {} : { receipt: entry.value.receipt }),
336
- });
337
- }
338
- }
339
- }
326
+ // getShader forks the admitted CPU catalog into the candidate on first
327
+ // access. Shader modules and all device-bound caches start empty.
340
328
  let candidatePostProcessResources: RecoveryPostProcessResources | undefined;
341
329
  let recoveryGraphCandidate: RecoveryGraphCandidate | undefined;
342
330
  let recoveryRootBundle: RecoveryRootBundle | undefined;
@@ -486,6 +474,27 @@ export function createRendererRecovery(deps: RendererRecoveryDependencies): Rend
486
474
  if (preparation.kind === 'error') throw preparation.error;
487
475
  const abortedAfterShaders = abortDisposedRecovery('rehydrate');
488
476
  if (abortedAfterShaders !== undefined) return abortedAfterShaders;
477
+ // Rehydrate manifest-selected builtins before carrying over late-
478
+ // installed user declarations. Builtin material sources are capability
479
+ // variants: copying the active generation first can retain a shader that
480
+ // declares cloud bindings 16/17 while the replacement device only
481
+ // admits the low-limit view layout. The candidate catalog owns fresh CPU
482
+ // declarations and modules; only identifiers still absent after
483
+ // preparation cross the generation boundary.
484
+ const activeShaderCatalog = getActiveShaderState().shaderInstance;
485
+ if (activeShaderCatalog !== null) {
486
+ const candidateShaderCatalog = getShader();
487
+ for (const identifier of activeShaderCatalog.materialShaderIdentifiers()) {
488
+ const entry = activeShaderCatalog.findMaterialArtifact(identifier);
489
+ if (entry.ok && !candidateShaderCatalog.findMaterialArtifact(identifier).ok) {
490
+ candidateShaderCatalog.installMaterialArtifact(identifier, {
491
+ source: entry.value.source,
492
+ paramSchema: entry.value.paramSchema,
493
+ ...(entry.value.receipt === undefined ? {} : { receipt: entry.value.receipt }),
494
+ });
495
+ }
496
+ }
497
+ }
489
498
  setRecoveryPhase('compile-graph');
490
499
  const pipeline = await runRecoveryStep(
491
500
  async (attemptToken) => {
@@ -580,6 +589,20 @@ export function createRendererRecovery(deps: RendererRecoveryDependencies): Rend
580
589
  getParamSchema: { value: getParamSchema },
581
590
  getMaterialBindGroupLayout: { value: getMaterialBindGroupLayout },
582
591
  metrics: { value: metrics },
592
+ shaderModuleFactory: {
593
+ value: {
594
+ createShaderModule: (
595
+ descriptor: Parameters<ShaderDeviceAdapterInternal['createShaderModule']>[0],
596
+ ) => getShaderModuleAdapter().createShaderModule(descriptor),
597
+ },
598
+ },
599
+ immediateShaderModuleFactory: {
600
+ value: {
601
+ createShaderModule: (
602
+ descriptor: Parameters<ShaderDeviceAdapterInternal['createShaderModule']>[0],
603
+ ) => getImmediateShaderModuleAdapter().createShaderModule(descriptor),
604
+ },
605
+ },
583
606
  buildPostProcessPipeline: { value: buildPostProcessPipeline },
584
607
  getPipelineState: { value: () => candidatePipelineState },
585
608
  featureHost: { value: createdCandidateFeatureHost },
@@ -0,0 +1,54 @@
1
+ import { RhiError } from '@forgeax/engine-rhi';
2
+ import {
3
+ SINGLE_LAYER_MEDIUM_MSAA_PAIRED_COLOR_WGSL,
4
+ SINGLE_LAYER_MEDIUM_MSAA_RAW_DEPTH_WGSL,
5
+ SINGLE_LAYER_MEDIUM_RAW_DEPTH_WGSL,
6
+ } from '@forgeax/engine-shader';
7
+ import type { RenderFeature } from '../features/types';
8
+ import {
9
+ SINGLE_LAYER_MEDIUM_MSAA_PAIRED_COLOR_POST_PROCESS_ID,
10
+ SINGLE_LAYER_MEDIUM_MSAA_RAW_DEPTH_POST_PROCESS_ID,
11
+ SINGLE_LAYER_MEDIUM_RAW_DEPTH_POST_PROCESS_ID,
12
+ } from '../pipeline/single-layer-medium-passes';
13
+
14
+ export function collectRequiredFullscreenPostProcesses(
15
+ features: readonly RenderFeature<unknown>[],
16
+ ): readonly { readonly identity: string; readonly source: string }[] {
17
+ const entries = new Map<string, { readonly identity: string; readonly source: string }>([
18
+ [
19
+ SINGLE_LAYER_MEDIUM_RAW_DEPTH_POST_PROCESS_ID,
20
+ {
21
+ identity: SINGLE_LAYER_MEDIUM_RAW_DEPTH_POST_PROCESS_ID,
22
+ source: SINGLE_LAYER_MEDIUM_RAW_DEPTH_WGSL,
23
+ },
24
+ ],
25
+ [
26
+ SINGLE_LAYER_MEDIUM_MSAA_PAIRED_COLOR_POST_PROCESS_ID,
27
+ {
28
+ identity: SINGLE_LAYER_MEDIUM_MSAA_PAIRED_COLOR_POST_PROCESS_ID,
29
+ source: SINGLE_LAYER_MEDIUM_MSAA_PAIRED_COLOR_WGSL,
30
+ },
31
+ ],
32
+ [
33
+ SINGLE_LAYER_MEDIUM_MSAA_RAW_DEPTH_POST_PROCESS_ID,
34
+ {
35
+ identity: SINGLE_LAYER_MEDIUM_MSAA_RAW_DEPTH_POST_PROCESS_ID,
36
+ source: SINGLE_LAYER_MEDIUM_MSAA_RAW_DEPTH_WGSL,
37
+ },
38
+ ],
39
+ ]);
40
+ for (const feature of features) {
41
+ for (const entry of feature.requiredFullscreenPostProcesses ?? []) {
42
+ const existing = entries.get(entry.identity);
43
+ if (existing !== undefined && existing.source !== entry.source) {
44
+ throw new RhiError({
45
+ code: 'internal-error',
46
+ expected: `fullscreen identity '${entry.identity}' has one source across render features`,
47
+ hint: 'rename the conflicting fullscreen identity or make its WGSL source identical',
48
+ });
49
+ }
50
+ entries.set(entry.identity, entry);
51
+ }
52
+ }
53
+ return Object.freeze([...entries.values()]);
54
+ }
@@ -15,6 +15,7 @@ import {
15
15
  type RendererOperationCause,
16
16
  RendererOperationError,
17
17
  } from '../errors/render';
18
+ import { MotionBlurValidationError } from '../features/motion-blur/motion-blur-params';
18
19
  import {
19
20
  STANDARD_LIGHT_COUNTS,
20
21
  STANDARD_PIPELINE_ID,
@@ -63,6 +64,7 @@ export function exposeRenderer(renderer: RendererHostImplementation): Renderer {
63
64
  cause: structuredRendererCause(cause, 'renderer-event'),
64
65
  });
65
66
  const drawError = (cause: RhiError | RenderError): RenderError => {
67
+ if (cause instanceof MotionBlurValidationError) return cause;
66
68
  if (cause instanceof RendererOperationError) return cause;
67
69
  if (cause instanceof RendererContractFailureError) {
68
70
  return new RendererOperationError('device-operation-failed', {
@@ -90,7 +92,7 @@ export function exposeRenderer(renderer: RendererHostImplementation): Renderer {
90
92
  });
91
93
 
92
94
  return {
93
- instances: renderer.instances,
95
+ setSurfaceDynamicInput: (frame) => renderer.setSurfaceDynamicInput(frame),
94
96
  bounds: (world, entity) => (disposed ? undefined : renderer.bounds(world, entity)),
95
97
  attach: (world) => {
96
98
  const result = renderer.attach(world);
@@ -153,6 +155,9 @@ export function exposeRenderer(renderer: RendererHostImplementation): Renderer {
153
155
  kind: 'frame-submitted',
154
156
  frameId: result.value.frameId,
155
157
  deviceGeneration: result.value.deviceGeneration,
158
+ ...(result.value.graphGeneration === undefined
159
+ ? {}
160
+ : { graphGeneration: result.value.graphGeneration }),
156
161
  receipt: result.value,
157
162
  }),
158
163
  );
@@ -1,13 +1,19 @@
1
+ import type { CloudLayerInspection } from '../cloud/inspection';
1
2
  import type { RenderFeatureHost } from '../features/host';
2
3
  import type { RenderInspection } from '../render-contract';
3
4
 
4
5
  /** Project feature-host lifecycle facts without exposing the live host. */
5
6
  export function projectRendererFeatureInspection(
6
7
  featureHost: RenderFeatureHost | undefined,
7
- ): Pick<RenderInspection, 'features' | 'featureDiagnostics' | 'featureHost'> {
8
+ ): Pick<RenderInspection, 'features' | 'featureDiagnostics' | 'featureHost' | 'cloudLayer'> {
9
+ const featureDiagnostics = featureHost?.diagnostics() ?? Object.freeze([]);
10
+ const cloudLayer = featureDiagnostics.find(
11
+ (diagnostic) => diagnostic.identity === 'forgeax.cloud-layer',
12
+ )?.inspection as CloudLayerInspection | undefined;
8
13
  return {
9
14
  features: Object.freeze((featureHost?.features ?? []).map((feature) => feature.identity)),
10
- featureDiagnostics: featureHost?.diagnostics() ?? Object.freeze([]),
15
+ featureDiagnostics,
16
+ ...(cloudLayer === undefined ? {} : { cloudLayer }),
11
17
  ...(featureHost?.inspection === undefined ? {} : { featureHost: featureHost.inspection() }),
12
18
  };
13
19
  }
@@ -64,6 +64,29 @@ export interface ContinuationTerminator {
64
64
  guard(kind: ContinuationKind): boolean;
65
65
  }
66
66
 
67
+ export type FrameCompletionResult<T, E> =
68
+ | { readonly ok: true; readonly value: T }
69
+ | { readonly ok: false; readonly error: E };
70
+
71
+ /**
72
+ * Preserve producer Result failures while fencing a fulfilled GPU completion
73
+ * against disposal or device-generation loss.
74
+ */
75
+ export function guardFrameCompletion<T, E>(
76
+ completion: PromiseLike<FrameCompletionResult<T, E>>,
77
+ isCurrent: () => boolean,
78
+ staleError: () => E,
79
+ rejectedError: (cause: unknown) => E,
80
+ ): Promise<FrameCompletionResult<T, E>> {
81
+ return Promise.resolve(completion).then(
82
+ (result) => {
83
+ if (!result.ok) return result;
84
+ return isCurrent() ? result : { ok: false, error: staleError() };
85
+ },
86
+ (cause) => ({ ok: false, error: rejectedError(cause) }),
87
+ );
88
+ }
89
+
67
90
  export function createContinuationTerminator(): ContinuationTerminator {
68
91
  let termination: ContinuationTerminationReason | undefined;
69
92
  let resolveTermination: ((reason: ContinuationTerminationReason) => void) | undefined;
@@ -2,6 +2,7 @@ import type { CompiledRenderGraphInfo } from '@forgeax/engine-render-graph';
2
2
  import type { RhiCanvasSurfacePresentationProof, TextureFormat } from '@forgeax/engine-rhi';
3
3
  import type { AutoExposureInspection } from '../pipeline/standard-output/auto-exposure/inspection';
4
4
  import type { StandardLutInspection } from '../pipeline/standard-output/lut-state';
5
+ import type { PipelineState } from '../record/render-context';
5
6
  import {
6
7
  type RenderOutputInspection,
7
8
  type RenderStandardOutputColorInspection,
@@ -112,6 +113,33 @@ export function projectRendererOutputInspection(
112
113
  };
113
114
  }
114
115
 
116
+ /** Assemble output inspection inputs from the live surface owner. */
117
+ export function projectRendererOutputInspectionFromSurface(input: {
118
+ readonly graph: CompiledRenderGraphInfo | undefined;
119
+ readonly surfaceReleased: boolean;
120
+ readonly pipelineState: PipelineState | null;
121
+ readonly rgba16floatRenderable: boolean;
122
+ readonly presentationProof?: RhiCanvasSurfacePresentationProof | undefined;
123
+ readonly autoExposure?: AutoExposureInspection | undefined;
124
+ readonly standardLut?: StandardLutInspection | undefined;
125
+ }): RenderOutputInspection {
126
+ return projectRendererOutputInspection({
127
+ graph: input.graph,
128
+ surfaceAvailable: !input.surfaceReleased && input.pipelineState !== null,
129
+ surfaceStorage: input.pipelineState?.format ?? 'rgba8unorm',
130
+ surfaceDisplay: input.pipelineState?.colorAttachmentFormat ?? 'rgba8unorm',
131
+ ...(input.pipelineState?.surfaceProfile === undefined
132
+ ? {}
133
+ : { surfaceProfile: input.pipelineState.surfaceProfile }),
134
+ rgba16floatRenderable: input.rgba16floatRenderable,
135
+ autoExposure: input.autoExposure,
136
+ standardLut: input.standardLut,
137
+ ...(input.presentationProof === undefined
138
+ ? {}
139
+ : { presentationProof: input.presentationProof }),
140
+ });
141
+ }
142
+
115
143
  /** Detached inspection projection helper; live renderer objects never cross this boundary. */
116
144
  export function detachRendererInspection<T extends object>(inspection: T): Readonly<T> {
117
145
  return Object.freeze({ ...inspection });
@@ -15,7 +15,7 @@ export function createSkinPaletteOwner(
15
15
  const limitKey = storageBufferCapable
16
16
  ? 'maxStorageBufferBindingSize'
17
17
  : 'maxUniformBufferBindingSize';
18
- const deviceLimit = (device.limits as Readonly<Record<string, number>>)[limitKey];
18
+ const deviceLimit = device.limits[limitKey];
19
19
  const maxBindingBytes = typeof deviceLimit === 'number' && deviceLimit > 0 ? deviceLimit : 65536;
20
20
  return createSkinPaletteAllocator(device, maxBindingBytes, storageBufferCapable);
21
21
  }
@@ -0,0 +1,40 @@
1
+ import type { Result, RhiDevice, RhiError, ShaderModule } from '@forgeax/engine-rhi';
2
+ import type { ManifestEntry } from '@forgeax/engine-types';
3
+ import { postProcessShaderModuleLabel } from '../fullscreen-post-process-pass';
4
+ import { invokeDeviceCreateShaderModule } from './material-shader-policy';
5
+ import { runShimStep } from './renderer-helpers';
6
+
7
+ export type AsyncShaderModuleFactory =
8
+ | ((
9
+ device: RhiDevice,
10
+ desc: { readonly code: string; readonly label?: string },
11
+ ) => Promise<Result<ShaderModule, RhiError>>)
12
+ | undefined;
13
+
14
+ /** Create the shared readiness prewarmer for temporal/fullscreen shader entries. */
15
+ export function createTemporalShaderPrewarmer(input: {
16
+ readonly device: RhiDevice;
17
+ readonly asyncCreateShaderModule: AsyncShaderModuleFactory;
18
+ readonly seedShaderModule: (label: string, module: ShaderModule) => void;
19
+ }): (entry: ManifestEntry | undefined, id: string) => Promise<void> {
20
+ return async (entry, id): Promise<void> => {
21
+ if (entry === undefined) return;
22
+ const prewarm = await runShimStep(
23
+ () =>
24
+ input.asyncCreateShaderModule
25
+ ? input.asyncCreateShaderModule(input.device, {
26
+ code: entry.wgsl,
27
+ label: postProcessShaderModuleLabel(entry.wgsl),
28
+ })
29
+ : invokeDeviceCreateShaderModule(input.device, {
30
+ code: entry.wgsl,
31
+ label: postProcessShaderModuleLabel(entry.wgsl),
32
+ }),
33
+ 'shader-compile-failed',
34
+ `${id} shader module compiled (unified post-process prewarm)`,
35
+ `inspect manifest ${id} entry composed wgsl; check device.features`,
36
+ );
37
+ if (!prewarm.ok) throw prewarm.error;
38
+ input.seedShaderModule(postProcessShaderModuleLabel(entry.wgsl), prewarm.value);
39
+ };
40
+ }