@forgeax/engine-render 0.1.33 → 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 (518) hide show
  1. package/README.md +1010 -124
  2. package/dist/assembly/backend-contract.d.ts +2 -0
  3. package/dist/assembly/backend-contract.d.ts.map +1 -1
  4. package/dist/assembly/barrel-distortion-inspection.d.ts +3 -0
  5. package/dist/assembly/barrel-distortion-inspection.d.ts.map +1 -0
  6. package/dist/assembly/canvas-draw-guard.d.ts +3 -0
  7. package/dist/assembly/canvas-draw-guard.d.ts.map +1 -0
  8. package/dist/assembly/cloud-shadow-entry.d.ts +4 -0
  9. package/dist/assembly/cloud-shadow-entry.d.ts.map +1 -0
  10. package/dist/assembly/dynamic-geometry-host.d.ts +4 -1
  11. package/dist/assembly/dynamic-geometry-host.d.ts.map +1 -1
  12. package/dist/assembly/dynamic-geometry-runtime.d.ts +1 -1
  13. package/dist/assembly/dynamic-geometry-runtime.d.ts.map +1 -1
  14. package/dist/assembly/factory.d.ts +1 -1
  15. package/dist/assembly/factory.d.ts.map +1 -1
  16. package/dist/assembly/host-contract.d.ts +3 -3
  17. package/dist/assembly/host-contract.d.ts.map +1 -1
  18. package/dist/assembly/material/assembly.d.ts.map +1 -1
  19. package/dist/assembly/material/pipeline-helpers.d.ts +5 -0
  20. package/dist/assembly/material/pipeline-helpers.d.ts.map +1 -1
  21. package/dist/assembly/material-shader-policy.d.ts +16 -2
  22. package/dist/assembly/material-shader-policy.d.ts.map +1 -1
  23. package/dist/assembly/material-shader-prewarm.d.ts.map +1 -1
  24. package/dist/assembly/recovery/device-loss-fanout.d.ts.map +1 -1
  25. package/dist/assembly/recovery/renderer-recover.d.ts +2 -0
  26. package/dist/assembly/recovery/renderer-recover.d.ts.map +1 -1
  27. package/dist/assembly/render-feature-post-processes.d.ts +6 -0
  28. package/dist/assembly/render-feature-post-processes.d.ts.map +1 -0
  29. package/dist/assembly/renderer-facade.d.ts.map +1 -1
  30. package/dist/assembly/renderer-feature-inspection.d.ts +1 -1
  31. package/dist/assembly/renderer-feature-inspection.d.ts.map +1 -1
  32. package/dist/assembly/renderer-frame-transaction.d.ts +12 -0
  33. package/dist/assembly/renderer-frame-transaction.d.ts.map +1 -1
  34. package/dist/assembly/renderer-inspection.d.ts +11 -0
  35. package/dist/assembly/renderer-inspection.d.ts.map +1 -1
  36. package/dist/assembly/webgpu-pbr-ready.d.ts +1 -0
  37. package/dist/assembly/webgpu-pbr-ready.d.ts.map +1 -1
  38. package/dist/assembly/webgpu-ready-per-pass.d.ts +39 -0
  39. package/dist/assembly/webgpu-ready-per-pass.d.ts.map +1 -0
  40. package/dist/assembly/webgpu-ready.d.ts +1 -1
  41. package/dist/assembly/webgpu-ready.d.ts.map +1 -1
  42. package/dist/assembly/webgpu-renderer-bootstrap.d.ts.map +1 -1
  43. package/dist/assembly/webgpu-renderer-observation-owner.d.ts +35 -0
  44. package/dist/assembly/webgpu-renderer-observation-owner.d.ts.map +1 -0
  45. package/dist/assembly/webgpu-renderer.d.ts +1 -1
  46. package/dist/assembly/webgpu-renderer.d.ts.map +1 -1
  47. package/dist/authoring.mjs +1 -1
  48. package/dist/barrel-distortion.d.ts +47 -0
  49. package/dist/barrel-distortion.d.ts.map +1 -0
  50. package/dist/{chunk-PA5DRJNI.mjs → chunk-ELJFJ2BU.mjs} +2 -2
  51. package/dist/chunk-ELJFJ2BU.mjs.map +1 -0
  52. package/dist/{chunk-ZDQWGQW7.mjs → chunk-HEB564WF.mjs} +4 -4
  53. package/dist/{chunk-ZDQWGQW7.mjs.map → chunk-HEB564WF.mjs.map} +1 -1
  54. package/dist/{chunk-VOZWDM3L.mjs → chunk-MKDIT2EM.mjs} +1307 -188
  55. package/dist/chunk-MKDIT2EM.mjs.map +1 -0
  56. package/dist/{chunk-LEAXOMYJ.mjs → chunk-OCDLEI6I.mjs} +3 -3
  57. package/dist/{chunk-LEAXOMYJ.mjs.map → chunk-OCDLEI6I.mjs.map} +1 -1
  58. package/dist/chunk-ODZWR6JQ.mjs +4927 -0
  59. package/dist/chunk-ODZWR6JQ.mjs.map +1 -0
  60. package/dist/{chunk-3RTCJTH4.mjs → chunk-SHFUFJ5N.mjs} +184 -13
  61. package/dist/chunk-SHFUFJ5N.mjs.map +1 -0
  62. package/dist/{chunk-OO3DRYK7.mjs → chunk-UI5SFODX.mjs} +176 -96
  63. package/dist/chunk-UI5SFODX.mjs.map +1 -0
  64. package/dist/{chunk-PLAXOOX5.mjs → chunk-UINHLCZA.mjs} +561 -79
  65. package/dist/chunk-UINHLCZA.mjs.map +1 -0
  66. package/dist/{chunk-NB2S7ZRX.mjs → chunk-WEX45HKH.mjs} +127 -386
  67. package/dist/chunk-WEX45HKH.mjs.map +1 -0
  68. package/dist/cloud/density.d.ts +55 -0
  69. package/dist/cloud/density.d.ts.map +1 -0
  70. package/dist/cloud/extract.d.ts +25 -0
  71. package/dist/cloud/extract.d.ts.map +1 -0
  72. package/dist/cloud/feature.d.ts +57 -0
  73. package/dist/cloud/feature.d.ts.map +1 -0
  74. package/dist/cloud/frame-context.d.ts +8 -0
  75. package/dist/cloud/frame-context.d.ts.map +1 -0
  76. package/dist/cloud/inspection.d.ts +59 -0
  77. package/dist/cloud/inspection.d.ts.map +1 -0
  78. package/dist/cloud/optics.d.ts +56 -0
  79. package/dist/cloud/optics.d.ts.map +1 -0
  80. package/dist/cloud/parameters.d.ts +73 -0
  81. package/dist/cloud/parameters.d.ts.map +1 -0
  82. package/dist/cloud/resources.d.ts +60 -0
  83. package/dist/cloud/resources.d.ts.map +1 -0
  84. package/dist/cloud/shadow.d.ts +42 -0
  85. package/dist/cloud/shadow.d.ts.map +1 -0
  86. package/dist/cloud/temporal.d.ts +74 -0
  87. package/dist/cloud/temporal.d.ts.map +1 -0
  88. package/dist/components/barrel-distortion.d.ts +13 -0
  89. package/dist/components/barrel-distortion.d.ts.map +1 -0
  90. package/dist/components/cloud-layer.d.ts +29 -0
  91. package/dist/components/cloud-layer.d.ts.map +1 -0
  92. package/dist/components/index.d.ts +2 -0
  93. package/dist/components/index.d.ts.map +1 -1
  94. package/dist/components/instances.d.ts +20 -6
  95. package/dist/components/instances.d.ts.map +1 -1
  96. package/dist/construct-renderer.d.ts +1 -1
  97. package/dist/construct-renderer.d.ts.map +1 -1
  98. package/dist/construct-renderer.mjs +6759 -2875
  99. package/dist/construct-renderer.mjs.map +1 -1
  100. package/dist/dynamic-geometry.d.ts +5 -1
  101. package/dist/dynamic-geometry.d.ts.map +1 -1
  102. package/dist/errors/cloud.d.ts +59 -0
  103. package/dist/errors/cloud.d.ts.map +1 -0
  104. package/dist/errors/render.d.ts +18 -4
  105. package/dist/errors/render.d.ts.map +1 -1
  106. package/dist/examples/single-layer-medium-surface.d.ts +47 -0
  107. package/dist/examples/single-layer-medium-surface.d.ts.map +1 -0
  108. package/dist/extract/camera.d.ts.map +1 -1
  109. package/dist/extract/contracts.d.ts +5 -1
  110. package/dist/extract/contracts.d.ts.map +1 -1
  111. package/dist/features/barrel-distortion.d.ts +29 -0
  112. package/dist/features/barrel-distortion.d.ts.map +1 -0
  113. package/dist/features/error-reporting.d.ts +6 -2
  114. package/dist/features/error-reporting.d.ts.map +1 -1
  115. package/dist/features/host.d.ts +10 -0
  116. package/dist/features/host.d.ts.map +1 -1
  117. package/dist/features/plan.d.ts +8 -0
  118. package/dist/features/plan.d.ts.map +1 -1
  119. package/dist/features/render-graph-contribution.d.ts +5 -0
  120. package/dist/features/render-graph-contribution.d.ts.map +1 -1
  121. package/dist/features/render-graph-raster.d.ts +1 -0
  122. package/dist/features/render-graph-raster.d.ts.map +1 -1
  123. package/dist/features/targets.d.ts +2 -0
  124. package/dist/features/targets.d.ts.map +1 -1
  125. package/dist/features/types.d.ts +44 -0
  126. package/dist/features/types.d.ts.map +1 -1
  127. package/dist/fullscreen-post-process-pass.d.ts +15 -7
  128. package/dist/fullscreen-post-process-pass.d.ts.map +1 -1
  129. package/dist/gpu-dirty-ranges.d.ts +11 -0
  130. package/dist/gpu-dirty-ranges.d.ts.map +1 -0
  131. package/dist/gpu-driven/batch-topology.d.ts +17 -0
  132. package/dist/gpu-driven/batch-topology.d.ts.map +1 -1
  133. package/dist/gpu-driven/material-artifacts.d.ts +6 -0
  134. package/dist/gpu-driven/material-artifacts.d.ts.map +1 -1
  135. package/dist/gpu-driven/prepared-draw.d.ts.map +1 -1
  136. package/dist/gpu-driven/production-raster-material.d.ts +178 -0
  137. package/dist/gpu-driven/production-raster-material.d.ts.map +1 -0
  138. package/dist/gpu-driven/production-raster.d.ts +47 -3
  139. package/dist/gpu-driven/production-raster.d.ts.map +1 -1
  140. package/dist/gpu-driven/resource-allocation.d.ts +31 -0
  141. package/dist/gpu-driven/resource-allocation.d.ts.map +1 -0
  142. package/dist/gpu-driven/shadow-ownership.d.ts +14 -0
  143. package/dist/gpu-driven/shadow-ownership.d.ts.map +1 -0
  144. package/dist/gpu-driven/view-gpu.d.ts +26 -2
  145. package/dist/gpu-driven/view-gpu.d.ts.map +1 -1
  146. package/dist/gpu-scene.d.ts +5 -0
  147. package/dist/gpu-scene.d.ts.map +1 -1
  148. package/dist/hdrp-buffers.d.ts +2 -2
  149. package/dist/hdrp-buffers.d.ts.map +1 -1
  150. package/dist/ibl/skylight-bind-group.d.ts +10 -1
  151. package/dist/ibl/skylight-bind-group.d.ts.map +1 -1
  152. package/dist/index.d.ts +27 -7
  153. package/dist/index.d.ts.map +1 -1
  154. package/dist/index.mjs +258 -8
  155. package/dist/index.mjs.map +1 -1
  156. package/dist/inspection-types.d.ts +135 -1
  157. package/dist/inspection-types.d.ts.map +1 -1
  158. package/dist/instance-buffer-cache.d.ts +4 -4
  159. package/dist/instance-buffer-cache.d.ts.map +1 -1
  160. package/dist/instances.d.ts +48 -100
  161. package/dist/instances.d.ts.map +1 -1
  162. package/dist/internal.mjs +7 -7
  163. package/dist/pbr-pipeline.d.ts +19 -1
  164. package/dist/pbr-pipeline.d.ts.map +1 -1
  165. package/dist/pipeline/single-layer-medium-passes.d.ts +73 -0
  166. package/dist/pipeline/single-layer-medium-passes.d.ts.map +1 -0
  167. package/dist/pipeline/standard-forward-lane.d.ts.map +1 -1
  168. package/dist/pipeline/standard-output/graph.d.ts.map +1 -1
  169. package/dist/pipeline/standard-output/types.d.ts +4 -2
  170. package/dist/pipeline/standard-output/types.d.ts.map +1 -1
  171. package/dist/pipeline/standard-pipeline.d.ts.map +1 -1
  172. package/dist/pipeline/standard-post.d.ts.map +1 -1
  173. package/dist/pipeline-builder.d.ts +1 -1
  174. package/dist/pipeline-builder.d.ts.map +1 -1
  175. package/dist/plugin.d.ts.map +1 -1
  176. package/dist/prepare/prepared-graphics-resolver.d.ts +2 -0
  177. package/dist/prepare/prepared-graphics-resolver.d.ts.map +1 -1
  178. package/dist/record/barrel-distortion-frame.d.ts +15 -0
  179. package/dist/record/barrel-distortion-frame.d.ts.map +1 -0
  180. package/dist/record/dynamic-geometry-consumption.d.ts +10 -2
  181. package/dist/record/dynamic-geometry-consumption.d.ts.map +1 -1
  182. package/dist/record/fold-buckets.d.ts +95 -0
  183. package/dist/record/fold-buckets.d.ts.map +1 -0
  184. package/dist/record/fold-instance-buffer.d.ts +6 -0
  185. package/dist/record/fold-instance-buffer.d.ts.map +1 -0
  186. package/dist/record/frame-lighting.d.ts +1 -0
  187. package/dist/record/frame-lighting.d.ts.map +1 -1
  188. package/dist/record/frame-snapshot.d.ts +37 -3
  189. package/dist/record/frame-snapshot.d.ts.map +1 -1
  190. package/dist/record/frame.d.ts +10 -61
  191. package/dist/record/frame.d.ts.map +1 -1
  192. package/dist/record/gpu-draw-receipts.d.ts +11 -0
  193. package/dist/record/gpu-draw-receipts.d.ts.map +1 -0
  194. package/dist/record/gpu-timing.d.ts +8 -0
  195. package/dist/record/gpu-timing.d.ts.map +1 -1
  196. package/dist/record/main-pass-geometry.d.ts +21 -5
  197. package/dist/record/main-pass-geometry.d.ts.map +1 -1
  198. package/dist/record/main-pass-material.d.ts +7 -1
  199. package/dist/record/main-pass-material.d.ts.map +1 -1
  200. package/dist/record/main-pass-sprite-draws.d.ts.map +1 -1
  201. package/dist/record/main-pass.d.ts +13 -2
  202. package/dist/record/main-pass.d.ts.map +1 -1
  203. package/dist/record/motion-blur-receipt.d.ts +11 -0
  204. package/dist/record/motion-blur-receipt.d.ts.map +1 -0
  205. package/dist/record/probe-blend-buffer.d.ts +16 -0
  206. package/dist/record/probe-blend-buffer.d.ts.map +1 -0
  207. package/dist/record/recovery-pipeline.d.ts.map +1 -1
  208. package/dist/record/render-context.d.ts +22 -3
  209. package/dist/record/render-context.d.ts.map +1 -1
  210. package/dist/record/shadow-pass.d.ts +2 -0
  211. package/dist/record/shadow-pass.d.ts.map +1 -1
  212. package/dist/record/skybox-post-pass.d.ts +1 -1
  213. package/dist/record/skybox-post-pass.d.ts.map +1 -1
  214. package/dist/record/typed-frame-graph.d.ts +22 -2
  215. package/dist/record/typed-frame-graph.d.ts.map +1 -1
  216. package/dist/record/view-ubo.d.ts +11 -3
  217. package/dist/record/view-ubo.d.ts.map +1 -1
  218. package/dist/record/volume-params.d.ts +9 -0
  219. package/dist/record/volume-params.d.ts.map +1 -0
  220. package/dist/recovery/render-system-candidate.d.ts +10 -0
  221. package/dist/recovery/render-system-candidate.d.ts.map +1 -1
  222. package/dist/reflection/record-owner.d.ts.map +1 -1
  223. package/dist/render-contract.d.ts +42 -4
  224. package/dist/render-contract.d.ts.map +1 -1
  225. package/dist/render-graph-primitives.d.ts.map +1 -1
  226. package/dist/render-pipeline.d.ts +103 -2
  227. package/dist/render-pipeline.d.ts.map +1 -1
  228. package/dist/render-system-extract-tail.d.ts +3 -2
  229. package/dist/render-system-extract-tail.d.ts.map +1 -1
  230. package/dist/render-system-extract.d.ts +16 -9
  231. package/dist/render-system-extract.d.ts.map +1 -1
  232. package/dist/render-system-presentation.d.ts +23 -0
  233. package/dist/render-system-presentation.d.ts.map +1 -0
  234. package/dist/render-system-producer-roots.d.ts +10 -0
  235. package/dist/render-system-producer-roots.d.ts.map +1 -0
  236. package/dist/render-system-residency.d.ts +12 -0
  237. package/dist/render-system-residency.d.ts.map +1 -0
  238. package/dist/render-system.d.ts +19 -14
  239. package/dist/render-system.d.ts.map +1 -1
  240. package/dist/scene/probe-blend.d.ts +27 -0
  241. package/dist/scene/probe-blend.d.ts.map +1 -1
  242. package/dist/scene/render-scene.d.ts +12 -5
  243. package/dist/scene/render-scene.d.ts.map +1 -1
  244. package/dist/ssao-buffers.d.ts +9 -0
  245. package/dist/ssao-buffers.d.ts.map +1 -1
  246. package/dist/surface/dynamic-input.d.ts +133 -0
  247. package/dist/surface/dynamic-input.d.ts.map +1 -0
  248. package/dist/surface/gpu-driven.d.ts +41 -0
  249. package/dist/surface/gpu-driven.d.ts.map +1 -0
  250. package/dist/surface/submission-observation.d.ts +136 -0
  251. package/dist/surface/submission-observation.d.ts.map +1 -0
  252. package/dist/systems/skin-palette-allocator.d.ts.map +1 -1
  253. package/dist/temporal/gpu.d.ts +13 -1
  254. package/dist/temporal/gpu.d.ts.map +1 -1
  255. package/dist/temporal/index.mjs +5 -5
  256. package/dist/temporal/inspection.d.ts.map +1 -1
  257. package/dist/temporal/standard-scene-data.d.ts.map +1 -1
  258. package/dist/temporal/target-coverage-attachment.d.ts.map +1 -1
  259. package/dist/transmission/single-layer-medium.d.ts +89 -0
  260. package/dist/transmission/single-layer-medium.d.ts.map +1 -0
  261. package/dist/typed-render-graph-primitives.d.ts +14 -2
  262. package/dist/typed-render-graph-primitives.d.ts.map +1 -1
  263. package/dist/volume/component.d.ts +9 -4
  264. package/dist/volume/component.d.ts.map +1 -1
  265. package/dist/volume/extract.d.ts +1 -1
  266. package/dist/volume/extract.d.ts.map +1 -1
  267. package/dist/volume/inspection.d.ts +2 -0
  268. package/dist/volume/inspection.d.ts.map +1 -1
  269. package/dist/volume/passes.d.ts +4 -1
  270. package/dist/volume/passes.d.ts.map +1 -1
  271. package/dist/volume/resources.d.ts.map +1 -1
  272. package/package.json +22 -21
  273. package/src/__tests__/atmosphere-daylight.dawn.test.ts +72 -0
  274. package/src/__tests__/barrel-distortion-lkg.integration.test.ts +353 -0
  275. package/src/__tests__/barrel-distortion.dawn.test.ts +41 -0
  276. package/src/__tests__/barrel-distortion.unit.test.ts +364 -0
  277. package/src/__tests__/construct-renderer-identity.unit.test.ts +49 -0
  278. package/src/__tests__/detached-recovery-graph.unit.test.ts +277 -0
  279. package/src/__tests__/device-loss-fanout.unit.test.ts +36 -1
  280. package/src/__tests__/docs-gate-green.unit.test.ts +112 -1
  281. package/src/__tests__/factory-contract.integration.test.ts +295 -45
  282. package/src/__tests__/feature-depth-input.dawn.test.ts +129 -2
  283. package/src/__tests__/fullscreen-feature-plan.unit.test.ts +14 -3
  284. package/src/__tests__/gpu-dirty-ranges.unit.test.ts +22 -0
  285. package/src/__tests__/gpu-driven-baseline.characterization.test.ts +16 -3
  286. package/src/__tests__/gpu-driven-batch-topology-pbr.unit.test.ts +12 -0
  287. package/src/__tests__/gpu-driven-material-artifacts.unit.test.ts +143 -0
  288. package/src/__tests__/gpu-driven-pbr.dawn.test.ts +2 -2
  289. package/src/__tests__/gpu-driven-production.integration.test.ts +482 -3
  290. package/src/__tests__/gpu-driven-shadow-views.dawn.test.ts +6 -5
  291. package/src/__tests__/gpu-driven-view-gpu-evidence.ts +94 -6
  292. package/src/__tests__/gpu-driven-view-graph.integration.test.ts +18 -2
  293. package/src/__tests__/gpu-driven-view.browser.test.ts +5 -8
  294. package/src/__tests__/gpu-driven-view.dawn.test.ts +6 -2
  295. package/src/__tests__/gpu-driven-view.unit.test.ts +1 -1
  296. package/src/__tests__/gpu-pass-timing-lifecycle.integration.test.ts +1 -0
  297. package/src/__tests__/gpu-pass-timing.browser.test.ts +6 -4
  298. package/src/__tests__/gpu-pass-timing.rhi-null.unit.test.ts +1 -0
  299. package/src/__tests__/gpu-scene.unit.test.ts +119 -9
  300. package/src/__tests__/instance-allocation-failure.unit.test.ts +57 -0
  301. package/src/__tests__/instances-culling.integration.test.ts +10 -36
  302. package/src/__tests__/instances-store.unit.test.ts +97 -305
  303. package/src/__tests__/instances-world-ownership.integration.test.ts +62 -0
  304. package/src/__tests__/main-pass-material-medium-selection.unit.test.ts +146 -0
  305. package/src/__tests__/material-shader-prewarm.unit.test.ts +59 -0
  306. package/src/__tests__/material-snapshot-mutation.integration.test.ts +39 -1
  307. package/src/__tests__/morph-culling-reentry.dawn.test.ts +5 -5
  308. package/src/__tests__/morph-visual-evidence.integration.test.ts +8 -7
  309. package/src/__tests__/motion-blur-compute.dawn.test.ts +13 -7
  310. package/src/__tests__/motion-blur.pixel.integration.test.ts +2 -2
  311. package/src/__tests__/nineslice-handle-surface.unit.test.ts +4 -4
  312. package/src/__tests__/pbr-view-layout.unit.test.ts +9 -0
  313. package/src/__tests__/physical-clearcoat.integration.test.ts +58 -0
  314. package/src/__tests__/prepared-graphics-capability.unit.test.ts +66 -2
  315. package/src/__tests__/probe-bindings.unit.test.ts +582 -1
  316. package/src/__tests__/probe-scene-dirty.integration.test.ts +28 -1
  317. package/src/__tests__/receipt-observation-retirement.unit.test.ts +65 -0
  318. package/src/__tests__/recovery-candidate-prepare.contract.test.ts +69 -0
  319. package/src/__tests__/render-error-code-owner.test-d.ts +7 -0
  320. package/src/__tests__/render-feature-diagnostics.unit.test.ts +15 -2
  321. package/src/__tests__/render-feature-error-reporting.unit.test.ts +21 -1
  322. package/src/__tests__/render-feature-prepared-diagnostics.unit.test.ts +10 -1
  323. package/src/__tests__/render-feature-retry.unit.test.ts +12 -1
  324. package/src/__tests__/render-scene-mixed-updates.integration.test.ts +145 -19
  325. package/src/__tests__/render-scene-projection.unit.test.ts +36 -11
  326. package/src/__tests__/render-scene-temporal-retry.unit.test.ts +20 -20
  327. package/src/__tests__/render-target-probe-soak.perf.test.ts +2 -2
  328. package/src/__tests__/render-temporal-environment-consumer.browser.test.ts +3 -3
  329. package/src/__tests__/render-temporal-environment-consumer.dawn.test.ts +5 -2
  330. package/src/__tests__/renderer-factory-material-contract.unit.test.ts +41 -7
  331. package/src/__tests__/renderer-frame-generation-fence.integration.test.ts +16 -0
  332. package/src/__tests__/renderer-frame-transaction.integration.test.ts +26 -10
  333. package/src/__tests__/resource-allocation.unit.test.ts +123 -0
  334. package/src/__tests__/single-layer-medium-passes.unit.test.ts +275 -0
  335. package/src/__tests__/skin-motion-regression.unit.test.ts +70 -1
  336. package/src/__tests__/skin-palette-recycling.dawn.test.ts +97 -0
  337. package/src/__tests__/skinned-shadow-caster.test.ts +15 -0
  338. package/src/__tests__/ssr-carrier-public-contract.unit.test.ts +21 -0
  339. package/src/__tests__/ssr-gpu-dispatch.browser.test.ts +4 -4
  340. package/src/__tests__/ssr-gpu-dispatch.dawn.test.ts +2 -2
  341. package/src/__tests__/ssr-gpu-dispatch.ts +1 -1
  342. package/src/__tests__/ssr-receiver-coverage.dawn.test.ts +6 -2
  343. package/src/__tests__/standard-output-chain-contract.unit.test.ts +28 -0
  344. package/src/__tests__/standard-pbr-artifact-assembly.unit.test.ts +46 -1
  345. package/src/__tests__/standard-pipeline.integration.test.ts +182 -1
  346. package/src/__tests__/surface-dynamic-buffer-lifecycle.unit.test.ts +506 -0
  347. package/src/__tests__/surface-submission-observation.unit.test.ts +812 -0
  348. package/src/__tests__/temporal-history-lifecycle.unit.test.ts +32 -0
  349. package/src/__tests__/temporal-performance.integration.test.ts +3 -3
  350. package/src/__tests__/visibility-instances.integration.test.ts +7 -19
  351. package/src/__tests__/visibility-producer-matrix.integration.test.ts +9 -20
  352. package/src/__tests__/volume-optics-oracle.unit.test.ts +4 -2
  353. package/src/__tests__/volumetric-fog-budget-recovery.integration.test.ts +30 -20
  354. package/src/__tests__/volumetric-fog-errors.unit.test.ts +4 -3
  355. package/src/__tests__/volumetric-fog-multiple.unit.test.ts +55 -0
  356. package/src/__tests__/volumetric-fog-spot-frame-optics.integration.test.ts +1 -1
  357. package/src/__tests__/volumetric-fog-stage-readback.dawn.test.ts +113 -9
  358. package/src/__tests__/volumetric-fog-topology.unit.test.ts +5 -3
  359. package/src/assembly/backend-contract.ts +30 -0
  360. package/src/assembly/barrel-distortion-inspection.ts +22 -0
  361. package/src/assembly/canvas-draw-guard.ts +11 -0
  362. package/src/assembly/cloud-shadow-entry.ts +22 -0
  363. package/src/assembly/dynamic-geometry-host.ts +65 -37
  364. package/src/assembly/dynamic-geometry-runtime.ts +7 -1
  365. package/src/assembly/factory.ts +2 -30
  366. package/src/assembly/host-contract.ts +3 -3
  367. package/src/assembly/material/assembly.ts +25 -13
  368. package/src/assembly/material/pipeline-helpers.ts +53 -12
  369. package/src/assembly/material-shader-policy.ts +55 -0
  370. package/src/assembly/material-shader-prewarm.ts +21 -10
  371. package/src/assembly/recovery/device-loss-fanout.ts +13 -0
  372. package/src/assembly/recovery/renderer-recover.ts +41 -18
  373. package/src/assembly/render-feature-post-processes.ts +54 -0
  374. package/src/assembly/renderer-facade.ts +4 -1
  375. package/src/assembly/renderer-feature-inspection.ts +8 -2
  376. package/src/assembly/renderer-frame-transaction.ts +23 -0
  377. package/src/assembly/renderer-inspection.ts +28 -0
  378. package/src/assembly/skin-palette-owner.ts +1 -1
  379. package/src/assembly/temporal-post-process-prewarm.ts +3 -3
  380. package/src/assembly/webgpu-pbr-ready.ts +9 -1
  381. package/src/assembly/webgpu-ready-per-pass.ts +104 -0
  382. package/src/assembly/webgpu-ready.ts +115 -61
  383. package/src/assembly/webgpu-renderer-bootstrap.ts +0 -12
  384. package/src/assembly/webgpu-renderer-observation-owner.ts +222 -0
  385. package/src/assembly/webgpu-renderer.ts +214 -252
  386. package/src/assembly/webgpu-vertex-layouts.ts +1 -1
  387. package/src/barrel-distortion.ts +247 -0
  388. package/src/cloud/__tests__/cloud-density-parity.dawn.test.ts +173 -0
  389. package/src/cloud/__tests__/cloud-layer-framebuffer-y.dawn.test.ts +265 -0
  390. package/src/cloud/__tests__/cloud-layer.browser.test.ts +432 -0
  391. package/src/cloud/__tests__/cloud-layer.unit.test.ts +634 -0
  392. package/src/cloud/density.ts +600 -0
  393. package/src/cloud/extract.ts +110 -0
  394. package/src/cloud/feature.ts +1810 -0
  395. package/src/cloud/frame-context.ts +42 -0
  396. package/src/cloud/inspection.ts +130 -0
  397. package/src/cloud/optics.ts +285 -0
  398. package/src/cloud/parameters.ts +255 -0
  399. package/src/cloud/resources.ts +122 -0
  400. package/src/cloud/shadow.ts +167 -0
  401. package/src/cloud/temporal.ts +226 -0
  402. package/src/components/barrel-distortion.ts +46 -0
  403. package/src/components/cloud-layer.ts +47 -0
  404. package/src/components/index.ts +2 -0
  405. package/src/components/instances.ts +18 -45
  406. package/src/components/sprite-instances.ts +1 -1
  407. package/src/construct-renderer.ts +1 -1
  408. package/src/dynamic-geometry.ts +12 -1
  409. package/src/errors/cloud.ts +103 -0
  410. package/src/errors/render.ts +44 -7
  411. package/src/examples/single-layer-medium-surface.ts +59 -0
  412. package/src/extract/camera.ts +15 -1
  413. package/src/extract/contracts.ts +5 -0
  414. package/src/features/barrel-distortion.ts +172 -0
  415. package/src/features/error-reporting.ts +26 -6
  416. package/src/features/host.ts +115 -14
  417. package/src/features/plan.ts +8 -0
  418. package/src/features/render-graph-contribution.ts +9 -0
  419. package/src/features/render-graph-raster.ts +45 -3
  420. package/src/features/targets.ts +66 -0
  421. package/src/features/types.ts +47 -0
  422. package/src/fullscreen-post-process-pass.ts +41 -9
  423. package/src/gpu-dirty-ranges.ts +48 -0
  424. package/src/gpu-driven/batch-topology.ts +53 -0
  425. package/src/gpu-driven/material-artifacts.ts +33 -25
  426. package/src/gpu-driven/prepared-draw.ts +12 -4
  427. package/src/gpu-driven/production-raster-material.ts +1894 -0
  428. package/src/gpu-driven/production-raster.ts +825 -784
  429. package/src/gpu-driven/resource-allocation.ts +142 -0
  430. package/src/gpu-driven/shadow-ownership.ts +71 -0
  431. package/src/gpu-driven/view-gpu.ts +164 -10
  432. package/src/gpu-scene.ts +75 -84
  433. package/src/hdrp-buffers.ts +4 -3
  434. package/src/ibl/skylight-bind-group.ts +49 -7
  435. package/src/index.ts +196 -9
  436. package/src/inspection-types.ts +162 -0
  437. package/src/instance-buffer-cache.ts +4 -4
  438. package/src/instances.ts +149 -569
  439. package/src/pbr-pipeline.ts +219 -13
  440. package/src/pipeline/single-layer-medium-passes.ts +267 -0
  441. package/src/pipeline/standard-forward-lane.ts +313 -57
  442. package/src/pipeline/standard-output/graph.ts +8 -2
  443. package/src/pipeline/standard-output/types.ts +12 -1
  444. package/src/pipeline/standard-pipeline.ts +291 -18
  445. package/src/pipeline/standard-post.ts +90 -24
  446. package/src/pipeline-builder.ts +1 -1
  447. package/src/plugin.ts +4 -0
  448. package/src/points-lines/__tests__/points-lines.bench.ts +17 -8
  449. package/src/prepare/prepared-graphics-resolver.ts +2 -0
  450. package/src/record/__tests__/main-pass-geometry.unit.test.ts +30 -0
  451. package/src/record/__tests__/sprite-material-abi.unit.test.ts +1 -1
  452. package/src/record/__tests__/temporal-payload.unit.test.ts +1 -1
  453. package/src/record/__tests__/transparent-group2-selection.unit.test.ts +11 -0
  454. package/src/record/__tests__/typed-frame-graph-plan.unit.test.ts +1 -0
  455. package/src/record/__tests__/view-ubo-layout.unit.test.ts +4 -3
  456. package/src/record/barrel-distortion-frame.ts +110 -0
  457. package/src/record/dynamic-geometry-consumption.ts +39 -9
  458. package/src/record/fold-buckets.ts +852 -0
  459. package/src/record/fold-instance-buffer.ts +51 -0
  460. package/src/record/frame-lighting.ts +36 -2
  461. package/src/record/frame-snapshot.ts +39 -3
  462. package/src/record/frame.ts +217 -1084
  463. package/src/record/gpu-draw-receipts.ts +38 -0
  464. package/src/record/gpu-timing.ts +48 -5
  465. package/src/record/main-pass-geometry.ts +251 -82
  466. package/src/record/main-pass-material.ts +66 -4
  467. package/src/record/main-pass-sprite-draws.ts +7 -65
  468. package/src/record/main-pass.ts +156 -20
  469. package/src/record/motion-blur-receipt.ts +91 -0
  470. package/src/record/probe-blend-buffer.ts +180 -0
  471. package/src/record/recovery-pipeline.ts +35 -3
  472. package/src/record/render-context.ts +39 -3
  473. package/src/record/shadow-pass.ts +30 -1
  474. package/src/record/skybox-post-pass.ts +28 -4
  475. package/src/record/typed-frame-graph.ts +770 -134
  476. package/src/record/view-ubo.ts +26 -3
  477. package/src/record/volume-params.ts +225 -0
  478. package/src/recovery/render-system-candidate.ts +235 -42
  479. package/src/reflection/record-owner.ts +7 -3
  480. package/src/render-contract.ts +48 -4
  481. package/src/render-graph-primitives.ts +7 -1
  482. package/src/render-pipeline.ts +130 -0
  483. package/src/render-system-extract-tail.ts +57 -61
  484. package/src/render-system-extract.ts +74 -76
  485. package/src/render-system-presentation.ts +56 -0
  486. package/src/render-system-producer-roots.ts +96 -0
  487. package/src/render-system-residency.ts +159 -0
  488. package/src/render-system.ts +347 -363
  489. package/src/scene/probe-blend.ts +96 -4
  490. package/src/scene/render-scene.ts +349 -280
  491. package/src/ssao-buffers.ts +95 -2
  492. package/src/surface/__tests__/dynamic-input.unit.test.ts +374 -0
  493. package/src/surface/__tests__/gpu-driven.unit.test.ts +87 -0
  494. package/src/surface/dynamic-input.ts +658 -0
  495. package/src/surface/gpu-driven.ts +147 -0
  496. package/src/surface/submission-observation.ts +517 -0
  497. package/src/systems/skin-palette-allocator.ts +4 -1
  498. package/src/temporal/gpu.ts +101 -17
  499. package/src/temporal/inspection.ts +7 -1
  500. package/src/temporal/standard-scene-data.ts +5 -0
  501. package/src/temporal/target-coverage-attachment.ts +4 -0
  502. package/src/transmission/__tests__/single-layer-medium.unit.test.ts +149 -0
  503. package/src/transmission/__tests__/standard-transmission.dawn.test.ts +12 -11
  504. package/src/transmission/single-layer-medium.ts +322 -0
  505. package/src/typed-render-graph-primitives.ts +70 -2
  506. package/src/volume/component.ts +10 -9
  507. package/src/volume/extract.ts +11 -5
  508. package/src/volume/inspection.ts +3 -0
  509. package/src/volume/passes.ts +87 -4
  510. package/src/volume/resources.ts +2 -1
  511. package/dist/chunk-3RTCJTH4.mjs.map +0 -1
  512. package/dist/chunk-NB2S7ZRX.mjs.map +0 -1
  513. package/dist/chunk-NNQL7CB3.mjs +0 -1713
  514. package/dist/chunk-NNQL7CB3.mjs.map +0 -1
  515. package/dist/chunk-OO3DRYK7.mjs.map +0 -1
  516. package/dist/chunk-PA5DRJNI.mjs.map +0 -1
  517. package/dist/chunk-PLAXOOX5.mjs.map +0 -1
  518. package/dist/chunk-VOZWDM3L.mjs.map +0 -1
@@ -245,7 +245,17 @@ function selectPublishedVariant(
245
245
  withColor = withColor.filter((variant) => variant.defines.COVERAGE_ONLY !== true);
246
246
  }
247
247
  if (options.variantSet !== undefined) {
248
- return withColor.find((variant) => variant.definesKey === options.variantSet);
248
+ const requestedAxes = new Map(
249
+ options.variantSet.length === 0
250
+ ? []
251
+ : options.variantSet.split('+').map((entry) => {
252
+ const [name, value] = entry.split('=');
253
+ return [name ?? '', value === 'true'] as const;
254
+ }),
255
+ );
256
+ withColor = withColor.filter((variant) =>
257
+ [...requestedAxes].every(([name, value]) => variant.defines[name] === value),
258
+ );
249
259
  }
250
260
  // GPU-driven Standard owns the storage-backed scene-index variant. Prefer that exact family, then fall back to the closest variant
251
261
  // carrying the requested COLOR_0 fact. This keeps the selection deterministic
@@ -296,12 +306,13 @@ export function resolveStandardPbrArtifact(
296
306
  for (const lookupId of lookupIds) {
297
307
  const lookup = shader.findMaterialArtifact(lookupId);
298
308
  if (!lookup.ok) continue;
299
- const manifestEntry =
300
- shader.materialShaderManifestEntries === undefined
301
- ? undefined
302
- : Array.from(shader.materialShaderManifestEntries()).find(
303
- (entry) => entry.identifier === lookupId,
304
- );
309
+ let manifestEntry: MaterialShaderManifestEntry | undefined;
310
+ for (const entry of shader.materialShaderManifestEntries?.() ?? []) {
311
+ if (entry.identifier === lookupId) {
312
+ manifestEntry = entry;
313
+ break;
314
+ }
315
+ }
305
316
  const selected =
306
317
  manifestEntry === undefined || manifestEntry.variants.length === 0
307
318
  ? undefined
@@ -356,12 +367,13 @@ export function resolveMaterialShaderArtifact(
356
367
  for (const lookupId of lookupIds) {
357
368
  const lookup = shader.findMaterialArtifact(lookupId);
358
369
  if (!lookup.ok) continue;
359
- const manifestEntry =
360
- shader.materialShaderManifestEntries === undefined
361
- ? undefined
362
- : Array.from(shader.materialShaderManifestEntries()).find(
363
- (entry) => entry.identifier === lookupId,
364
- );
370
+ let manifestEntry: MaterialShaderManifestEntry | undefined;
371
+ for (const entry of shader.materialShaderManifestEntries?.() ?? []) {
372
+ if (entry.identifier === lookupId) {
373
+ manifestEntry = entry;
374
+ break;
375
+ }
376
+ }
365
377
  let cache = publishedArtifacts.get(lookup.value);
366
378
  if (cache === undefined || cache.manifest !== manifestEntry) {
367
379
  cache = { manifest: manifestEntry, requests: new Map() };
@@ -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
  }
@@ -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
+ }
@@ -92,7 +92,7 @@ export function exposeRenderer(renderer: RendererHostImplementation): Renderer {
92
92
  });
93
93
 
94
94
  return {
95
- instances: renderer.instances,
95
+ setSurfaceDynamicInput: (frame) => renderer.setSurfaceDynamicInput(frame),
96
96
  bounds: (world, entity) => (disposed ? undefined : renderer.bounds(world, entity)),
97
97
  attach: (world) => {
98
98
  const result = renderer.attach(world);
@@ -155,6 +155,9 @@ export function exposeRenderer(renderer: RendererHostImplementation): Renderer {
155
155
  kind: 'frame-submitted',
156
156
  frameId: result.value.frameId,
157
157
  deviceGeneration: result.value.deviceGeneration,
158
+ ...(result.value.graphGeneration === undefined
159
+ ? {}
160
+ : { graphGeneration: result.value.graphGeneration }),
158
161
  receipt: result.value,
159
162
  }),
160
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
  }
@@ -24,17 +24,17 @@ export function createTemporalShaderPrewarmer(input: {
24
24
  input.asyncCreateShaderModule
25
25
  ? input.asyncCreateShaderModule(input.device, {
26
26
  code: entry.wgsl,
27
- label: postProcessShaderModuleLabel(id, entry.wgsl),
27
+ label: postProcessShaderModuleLabel(entry.wgsl),
28
28
  })
29
29
  : invokeDeviceCreateShaderModule(input.device, {
30
30
  code: entry.wgsl,
31
- label: postProcessShaderModuleLabel(id, entry.wgsl),
31
+ label: postProcessShaderModuleLabel(entry.wgsl),
32
32
  }),
33
33
  'shader-compile-failed',
34
34
  `${id} shader module compiled (unified post-process prewarm)`,
35
35
  `inspect manifest ${id} entry composed wgsl; check device.features`,
36
36
  );
37
37
  if (!prewarm.ok) throw prewarm.error;
38
- input.seedShaderModule(postProcessShaderModuleLabel(id, entry.wgsl), prewarm.value);
38
+ input.seedShaderModule(postProcessShaderModuleLabel(entry.wgsl), prewarm.value);
39
39
  };
40
40
  }