@forgeax/engine-render 0.1.29 → 0.1.31

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 (350) hide show
  1. package/README.md +248 -21
  2. package/dist/assembly/atmosphere-shader-prewarm.d.ts +1 -1
  3. package/dist/assembly/atmosphere-shader-prewarm.d.ts.map +1 -1
  4. package/dist/assembly/device-feature-admission.d.ts +4 -3
  5. package/dist/assembly/device-feature-admission.d.ts.map +1 -1
  6. package/dist/assembly/dynamic-geometry-host.d.ts +6 -0
  7. package/dist/assembly/dynamic-geometry-host.d.ts.map +1 -1
  8. package/dist/assembly/host-contract.d.ts +6 -0
  9. package/dist/assembly/host-contract.d.ts.map +1 -1
  10. package/dist/assembly/material/assembly.d.ts +26 -3
  11. package/dist/assembly/material/assembly.d.ts.map +1 -1
  12. package/dist/assembly/material/pipeline-helpers.d.ts +24 -0
  13. package/dist/assembly/material/pipeline-helpers.d.ts.map +1 -0
  14. package/dist/assembly/material-shader-policy.d.ts.map +1 -1
  15. package/dist/assembly/recovery/device-loss-fanout.d.ts.map +1 -1
  16. package/dist/assembly/recovery/recovery-attempt.d.ts +1 -6
  17. package/dist/assembly/recovery/recovery-attempt.d.ts.map +1 -1
  18. package/dist/assembly/recovery/renderer-recover.d.ts +1 -0
  19. package/dist/assembly/recovery/renderer-recover.d.ts.map +1 -1
  20. package/dist/assembly/renderer-facade.d.ts.map +1 -1
  21. package/dist/assembly/shader-prewarm-policy.d.ts +1 -1
  22. package/dist/assembly/shader-prewarm-policy.d.ts.map +1 -1
  23. package/dist/assembly/webgpu-ready.d.ts +1 -1
  24. package/dist/assembly/webgpu-ready.d.ts.map +1 -1
  25. package/dist/assembly/webgpu-renderer.d.ts.map +1 -1
  26. package/dist/capture/scene-projection.d.ts +41 -0
  27. package/dist/capture/scene-projection.d.ts.map +1 -0
  28. package/dist/{chunk-BQVQOQJH.mjs → chunk-7MQ3XBSP.mjs} +20 -14
  29. package/dist/chunk-7MQ3XBSP.mjs.map +1 -0
  30. package/dist/{chunk-S4DNKQYQ.mjs → chunk-C3DDSXYK.mjs} +86 -33
  31. package/dist/chunk-C3DDSXYK.mjs.map +1 -0
  32. package/dist/{chunk-BTWH7BP4.mjs → chunk-FUUO4UND.mjs} +73 -29
  33. package/dist/chunk-FUUO4UND.mjs.map +1 -0
  34. package/dist/{chunk-NRNXBLIJ.mjs → chunk-JRBDO2KB.mjs} +46 -6
  35. package/dist/chunk-JRBDO2KB.mjs.map +1 -0
  36. package/dist/{chunk-NICXSHAT.mjs → chunk-MDQJPY3T.mjs} +8 -6
  37. package/dist/chunk-MDQJPY3T.mjs.map +1 -0
  38. package/dist/{chunk-JQTSEI3Z.mjs → chunk-NO4WZCAH.mjs} +3 -3
  39. package/dist/chunk-NO4WZCAH.mjs.map +1 -0
  40. package/dist/{chunk-FUODTTIA.mjs → chunk-PSEQ6QPH.mjs} +621 -108
  41. package/dist/chunk-PSEQ6QPH.mjs.map +1 -0
  42. package/dist/{chunk-33XZFTQU.mjs → chunk-S5UE2T5P.mjs} +48 -6
  43. package/dist/chunk-S5UE2T5P.mjs.map +1 -0
  44. package/dist/components/directional-light.d.ts +2 -2
  45. package/dist/components/dynamic-resolution.d.ts +15 -0
  46. package/dist/components/dynamic-resolution.d.ts.map +1 -0
  47. package/dist/components/index.d.ts +1 -0
  48. package/dist/components/index.d.ts.map +1 -1
  49. package/dist/components/light-helpers.d.ts.map +1 -1
  50. package/dist/components/reflection-probe.d.ts +1 -0
  51. package/dist/components/reflection-probe.d.ts.map +1 -1
  52. package/dist/components/skylight.d.ts +4 -1
  53. package/dist/components/skylight.d.ts.map +1 -1
  54. package/dist/construct-renderer.mjs +2172 -796
  55. package/dist/construct-renderer.mjs.map +1 -1
  56. package/dist/device/device-scope.d.ts +2 -0
  57. package/dist/device/device-scope.d.ts.map +1 -1
  58. package/dist/device/gpu-residency.d.ts +2 -2
  59. package/dist/device/gpu-residency.d.ts.map +1 -1
  60. package/dist/dynamic-geometry.d.ts.map +1 -1
  61. package/dist/environment/background.d.ts +3 -2
  62. package/dist/environment/background.d.ts.map +1 -1
  63. package/dist/environment/ibl.d.ts +11 -0
  64. package/dist/environment/ibl.d.ts.map +1 -0
  65. package/dist/environment/storage.d.ts +14 -0
  66. package/dist/environment/storage.d.ts.map +1 -0
  67. package/dist/errors/gpu-driven.d.ts +2 -2
  68. package/dist/errors/gpu-driven.d.ts.map +1 -1
  69. package/dist/errors/render.d.ts +35 -1
  70. package/dist/errors/render.d.ts.map +1 -1
  71. package/dist/extract/camera.d.ts.map +1 -1
  72. package/dist/extract/contracts.d.ts +7 -0
  73. package/dist/extract/contracts.d.ts.map +1 -1
  74. package/dist/extract/gpu-driven.d.ts +18 -1
  75. package/dist/extract/gpu-driven.d.ts.map +1 -1
  76. package/dist/gpu-driven/batch-topology.d.ts.map +1 -1
  77. package/dist/gpu-driven/material-artifacts.d.ts +24 -0
  78. package/dist/gpu-driven/material-artifacts.d.ts.map +1 -0
  79. package/dist/gpu-driven/material-bindings.d.ts +7 -0
  80. package/dist/gpu-driven/material-bindings.d.ts.map +1 -0
  81. package/dist/gpu-driven/prepared-draw.d.ts +2 -0
  82. package/dist/gpu-driven/prepared-draw.d.ts.map +1 -1
  83. package/dist/gpu-driven/production-raster.d.ts +27 -6
  84. package/dist/gpu-driven/production-raster.d.ts.map +1 -1
  85. package/dist/gpu-resource.d.ts +5 -2
  86. package/dist/gpu-resource.d.ts.map +1 -1
  87. package/dist/gpu-scene-schema.d.ts.map +1 -1
  88. package/dist/gpu-scene.d.ts.map +1 -1
  89. package/dist/hdrp-buffers.d.ts +3 -0
  90. package/dist/hdrp-buffers.d.ts.map +1 -1
  91. package/dist/ibl/IblPipelineCache.d.ts +2 -0
  92. package/dist/ibl/IblPipelineCache.d.ts.map +1 -1
  93. package/dist/ibl/skylight-bind-group.d.ts +3 -1
  94. package/dist/ibl/skylight-bind-group.d.ts.map +1 -1
  95. package/dist/index.d.ts +83 -81
  96. package/dist/index.d.ts.map +1 -1
  97. package/dist/index.mjs +7 -5
  98. package/dist/index.mjs.map +1 -1
  99. package/dist/inspection-types.d.ts +16 -1
  100. package/dist/inspection-types.d.ts.map +1 -1
  101. package/dist/internal.mjs +6 -6
  102. package/dist/material-row.d.ts +10 -0
  103. package/dist/material-row.d.ts.map +1 -1
  104. package/dist/pbr-pipeline.d.ts +3 -1
  105. package/dist/pbr-pipeline.d.ts.map +1 -1
  106. package/dist/pipeline/render-extent.d.ts +51 -0
  107. package/dist/pipeline/render-extent.d.ts.map +1 -0
  108. package/dist/pipeline/standard-build-context.d.ts +7 -0
  109. package/dist/pipeline/standard-build-context.d.ts.map +1 -0
  110. package/dist/pipeline/standard-forward-lane.d.ts +3 -2
  111. package/dist/pipeline/standard-forward-lane.d.ts.map +1 -1
  112. package/dist/pipeline/standard-pipeline.d.ts.map +1 -1
  113. package/dist/pipeline/standard-post.d.ts +1 -1
  114. package/dist/pipeline/standard-post.d.ts.map +1 -1
  115. package/dist/pipeline/standard-profile.d.ts +2 -1
  116. package/dist/pipeline/standard-profile.d.ts.map +1 -1
  117. package/dist/pipeline-builder.d.ts +3 -1
  118. package/dist/pipeline-builder.d.ts.map +1 -1
  119. package/dist/plugin.d.ts.map +1 -1
  120. package/dist/post-process-errors.d.ts +9 -2
  121. package/dist/post-process-errors.d.ts.map +1 -1
  122. package/dist/prepare/extended-lighting/resources.d.ts +3 -3
  123. package/dist/record/frame-lighting.d.ts.map +1 -1
  124. package/dist/record/frame-snapshot.d.ts +3 -8
  125. package/dist/record/frame-snapshot.d.ts.map +1 -1
  126. package/dist/record/frame.d.ts +3 -2
  127. package/dist/record/frame.d.ts.map +1 -1
  128. package/dist/record/main-pass-geometry.d.ts +7 -2
  129. package/dist/record/main-pass-geometry.d.ts.map +1 -1
  130. package/dist/record/main-pass-material.d.ts +6 -3
  131. package/dist/record/main-pass-material.d.ts.map +1 -1
  132. package/dist/record/main-pass.d.ts +2 -0
  133. package/dist/record/main-pass.d.ts.map +1 -1
  134. package/dist/record/prepared-material-bindings.d.ts.map +1 -1
  135. package/dist/record/recovery-pipeline.d.ts +9 -1
  136. package/dist/record/recovery-pipeline.d.ts.map +1 -1
  137. package/dist/record/render-context.d.ts +34 -3
  138. package/dist/record/render-context.d.ts.map +1 -1
  139. package/dist/record/shadow-pass.d.ts +2 -2
  140. package/dist/record/shadow-pass.d.ts.map +1 -1
  141. package/dist/record/typed-frame-graph.d.ts +5 -2
  142. package/dist/record/typed-frame-graph.d.ts.map +1 -1
  143. package/dist/recovery/render-system-candidate.d.ts.map +1 -1
  144. package/dist/reflection/background.d.ts +14 -0
  145. package/dist/reflection/background.d.ts.map +1 -0
  146. package/dist/reflection/filter.d.ts.map +1 -1
  147. package/dist/reflection/projection.d.ts +1 -0
  148. package/dist/reflection/projection.d.ts.map +1 -1
  149. package/dist/reflection/record-owner.d.ts +4 -2
  150. package/dist/reflection/record-owner.d.ts.map +1 -1
  151. package/dist/render-contract.d.ts +47 -32
  152. package/dist/render-contract.d.ts.map +1 -1
  153. package/dist/render-graph-primitives.d.ts.map +1 -1
  154. package/dist/render-pipeline.d.ts +17 -1
  155. package/dist/render-pipeline.d.ts.map +1 -1
  156. package/dist/render-system-extract-tail.d.ts +9 -2
  157. package/dist/render-system-extract-tail.d.ts.map +1 -1
  158. package/dist/render-system-extract.d.ts +29 -2
  159. package/dist/render-system-extract.d.ts.map +1 -1
  160. package/dist/render-system.d.ts.map +1 -1
  161. package/dist/scene/render-scene.d.ts +2 -0
  162. package/dist/scene/render-scene.d.ts.map +1 -1
  163. package/dist/ssao-config.d.ts +8 -6
  164. package/dist/ssao-config.d.ts.map +1 -1
  165. package/dist/ssr/graph.d.ts.map +1 -1
  166. package/dist/temporal/gpu.d.ts.map +1 -1
  167. package/dist/temporal/index.mjs +5 -5
  168. package/dist/temporal/standard-scene-data.d.ts +2 -1
  169. package/dist/temporal/standard-scene-data.d.ts.map +1 -1
  170. package/dist/temporal/target-coverage-attachment.d.ts +15 -0
  171. package/dist/temporal/target-coverage-attachment.d.ts.map +1 -0
  172. package/dist/temporal/temporal-view.d.ts +6 -2
  173. package/dist/temporal/temporal-view.d.ts.map +1 -1
  174. package/dist/temporal/view.d.ts +6 -0
  175. package/dist/temporal/view.d.ts.map +1 -1
  176. package/dist/typed-render-graph-primitives.d.ts +6 -0
  177. package/dist/typed-render-graph-primitives.d.ts.map +1 -1
  178. package/dist/volume/component.d.ts +1 -0
  179. package/dist/volume/component.d.ts.map +1 -1
  180. package/package.json +21 -21
  181. package/src/__tests__/capture-scene-projection.unit.test.ts +24 -0
  182. package/src/__tests__/device-feature-admission.unit.test.ts +15 -24
  183. package/src/__tests__/device-loss-fanout.unit.test.ts +43 -0
  184. package/src/__tests__/dynamic-geometry-batch.unit.test.ts +157 -0
  185. package/src/__tests__/dynamic-geometry.unit.test.ts +36 -0
  186. package/src/__tests__/dynamic-resolution-plugin.integration.test.ts +81 -0
  187. package/src/__tests__/factory-contract.integration.test.ts +164 -1
  188. package/src/__tests__/frame-observation.contract.test.ts +21 -0
  189. package/src/__tests__/gpu-driven-baseline.characterization.test.ts +1 -1
  190. package/src/__tests__/gpu-driven-batch-topology-pbr.unit.test.ts +20 -1
  191. package/src/__tests__/gpu-driven-lod-cache.unit.test.ts +0 -3
  192. package/src/__tests__/gpu-driven-mesh-world-identity.unit.test.ts +0 -3
  193. package/src/__tests__/gpu-driven-pbr.dawn.test.ts +11 -6
  194. package/src/__tests__/gpu-driven-production.integration.test.ts +13 -25
  195. package/src/__tests__/gpu-driven-view.unit.test.ts +1 -0
  196. package/src/__tests__/gpu-pass-timing-browser-runner.ts +15 -0
  197. package/src/__tests__/gpu-pass-timing.browser.test.ts +14 -1
  198. package/src/__tests__/gpu-resource-scope.unit.test.ts +71 -0
  199. package/src/__tests__/gpu-scene.unit.test.ts +55 -1
  200. package/src/__tests__/materials-standard-contract.unit.test.ts +5 -1
  201. package/src/__tests__/mesh-submission-lifetime.unit.test.ts +8 -0
  202. package/src/__tests__/morph-neutral-admission.unit.test.ts +19 -0
  203. package/src/__tests__/physical-clearcoat.integration.test.ts +6 -1
  204. package/src/__tests__/post-process-error-policy-owner.unit.test.ts +6 -5
  205. package/src/__tests__/prepared-gpu-driven-pbr.integration.test.ts +216 -5
  206. package/src/__tests__/reflection-fallback-async-publication.unit.test.ts +68 -1
  207. package/src/__tests__/reflection-probe-authoring.unit.test.ts +12 -10
  208. package/src/__tests__/reflection-probe-box.dawn.test.ts +71 -0
  209. package/src/__tests__/reflection-probe-filter.unit.test.ts +9 -0
  210. package/src/__tests__/reflection-probe-orientation.dawn.test.ts +294 -0
  211. package/src/__tests__/reflection-probe-record-owner.characterization.unit.test.ts +5 -15
  212. package/src/__tests__/reflection-probe-updates.unit.test.ts +129 -0
  213. package/src/__tests__/render-error-code-owner.test-d.ts +3 -0
  214. package/src/__tests__/render-error-detail-ssot.test-d.ts +5 -1
  215. package/src/__tests__/render-extent.unit.test.ts +63 -0
  216. package/src/__tests__/render-scene-projection.unit.test.ts +3 -2
  217. package/src/__tests__/renderer-factory-material-contract.unit.test.ts +173 -9
  218. package/src/__tests__/shader-manifest-fixture.ts +6 -0
  219. package/src/__tests__/skinned-shadow-caster.test.ts +8 -1
  220. package/src/__tests__/specular-environment-scale.dawn.test.ts +4 -2
  221. package/src/__tests__/ssao-config.unit.test.ts +7 -0
  222. package/src/__tests__/ssao-surface.dawn.test.ts +252 -0
  223. package/src/__tests__/ssr-cube-silhouette.dawn.test.ts +270 -0
  224. package/src/__tests__/ssr-gpu-dispatch.browser.test.ts +51 -43
  225. package/src/__tests__/ssr-gpu-dispatch.dawn.test.ts +4 -0
  226. package/src/__tests__/ssr-gpu-dispatch.ts +10 -5
  227. package/src/__tests__/ssr-graph-topology.unit.test.ts +2 -2
  228. package/src/__tests__/ssr-hiz.browser.test.ts +1 -1
  229. package/src/__tests__/ssr-hiz.dawn.test.ts +1 -1
  230. package/src/__tests__/ssr-spatial.integration.test.ts +1 -1
  231. package/src/__tests__/standard-cluster-variant-resolution.unit.test.ts +40 -0
  232. package/src/__tests__/standard-pbr-artifact-assembly.unit.test.ts +238 -1
  233. package/src/__tests__/standard-profile-oracle.unit.test.ts +27 -0
  234. package/src/__tests__/taa-coverage-edge.dawn.test.ts +6 -0
  235. package/src/__tests__/taa-neighborhood-equivalence.dawn.test.ts +5 -1
  236. package/src/__tests__/taa-stability-feedback.ts +1 -0
  237. package/src/__tests__/temporal-reset-matrix.unit.test.ts +2 -2
  238. package/src/__tests__/temporal-view.unit.test.ts +17 -0
  239. package/src/__tests__/transmission-prewarm.unit.test.ts +57 -0
  240. package/src/__tests__/volumetric-fog-stage-readback.dawn.test.ts +62 -13
  241. package/src/__tests__/volumetric-fog-topology.unit.test.ts +7 -7
  242. package/src/assembly/atmosphere-shader-prewarm.ts +3 -2
  243. package/src/assembly/device-feature-admission.ts +9 -4
  244. package/src/assembly/dynamic-geometry-host.ts +236 -163
  245. package/src/assembly/host-contract.ts +9 -0
  246. package/src/assembly/material/assembly.ts +350 -6
  247. package/src/assembly/material/pipeline-helpers.ts +100 -0
  248. package/src/assembly/material-shader-policy.ts +39 -18
  249. package/src/assembly/recovery/device-loss-fanout.ts +5 -0
  250. package/src/assembly/recovery/recovery-attempt.ts +2 -29
  251. package/src/assembly/recovery/renderer-recover.ts +6 -9
  252. package/src/assembly/renderer-facade.ts +22 -1
  253. package/src/assembly/shader-prewarm-policy.ts +14 -1
  254. package/src/assembly/webgpu-ready.ts +28 -19
  255. package/src/assembly/webgpu-renderer.ts +95 -95
  256. package/src/capture/scene-projection.ts +37 -0
  257. package/src/components/__tests__/dynamic-resolution-schema.unit.test.ts +65 -0
  258. package/src/components/__tests__/light-radius.integration.test.ts +59 -0
  259. package/src/components/directional-light.ts +3 -3
  260. package/src/components/dynamic-resolution.ts +67 -0
  261. package/src/components/index.ts +1 -0
  262. package/src/components/light-helpers.ts +6 -1
  263. package/src/components/reflection-probe.ts +1 -0
  264. package/src/components/skylight.ts +4 -1
  265. package/src/device/device-scope.ts +13 -7
  266. package/src/device/gpu-residency.ts +11 -11
  267. package/src/dynamic-geometry.ts +13 -8
  268. package/src/environment/background.ts +30 -12
  269. package/src/environment/ibl.ts +211 -0
  270. package/src/environment/storage.ts +63 -0
  271. package/src/errors/gpu-driven.ts +10 -3
  272. package/src/errors/render.ts +64 -0
  273. package/src/extract/camera.ts +12 -1
  274. package/src/extract/contracts.ts +10 -0
  275. package/src/extract/gpu-driven.ts +72 -17
  276. package/src/gpu-driven/batch-topology.ts +33 -11
  277. package/src/gpu-driven/material-artifacts.ts +179 -0
  278. package/src/gpu-driven/material-bindings.ts +41 -0
  279. package/src/gpu-driven/prepared-draw.ts +13 -2
  280. package/src/gpu-driven/production-raster.ts +681 -164
  281. package/src/gpu-resource.ts +21 -2
  282. package/src/gpu-scene-schema.ts +11 -2
  283. package/src/gpu-scene.ts +14 -3
  284. package/src/hdrp-buffers.ts +69 -0
  285. package/src/ibl/IblPipelineCache.ts +5 -0
  286. package/src/ibl/skylight-bind-group.ts +27 -17
  287. package/src/index.ts +92 -81
  288. package/src/inspection-types.ts +16 -1
  289. package/src/material-row.ts +60 -11
  290. package/src/pbr-pipeline.ts +13 -2
  291. package/src/pipeline/render-extent.ts +111 -0
  292. package/src/pipeline/standard-build-context.ts +7 -0
  293. package/src/pipeline/standard-forward-lane.ts +41 -24
  294. package/src/pipeline/standard-pipeline.ts +47 -18
  295. package/src/pipeline/standard-post.ts +4 -0
  296. package/src/pipeline/standard-profile.ts +2 -1
  297. package/src/pipeline-builder.ts +12 -3
  298. package/src/plugin.ts +4 -0
  299. package/src/post-process-errors.ts +26 -18
  300. package/src/prepare/__tests__/extended-lighting-capability.unit.test.ts +2 -2
  301. package/src/prepare/extended-lighting/resources.ts +3 -3
  302. package/src/record/__tests__/main-pass-geometry.unit.test.ts +68 -0
  303. package/src/record/__tests__/material-bg-cache.unit.test.ts +45 -0
  304. package/src/record/__tests__/material-slot-plan.unit.test.ts +9 -0
  305. package/src/record/__tests__/recovery-pipeline.unit.test.ts +47 -1
  306. package/src/record/__tests__/sprite-material-abi.unit.test.ts +7 -3
  307. package/src/record/__tests__/temporal-payload.unit.test.ts +2 -0
  308. package/src/record/frame-lighting.ts +3 -1
  309. package/src/record/frame-snapshot.ts +13 -11
  310. package/src/record/frame.ts +150 -74
  311. package/src/record/main-pass-geometry.ts +60 -9
  312. package/src/record/main-pass-material.ts +47 -19
  313. package/src/record/main-pass.ts +63 -4
  314. package/src/record/prepared-material-bindings.ts +4 -0
  315. package/src/record/recovery-pipeline.ts +56 -0
  316. package/src/record/render-context.ts +34 -3
  317. package/src/record/shadow-pass.ts +187 -50
  318. package/src/record/typed-frame-graph.ts +60 -3
  319. package/src/record/view-ubo.ts +1 -1
  320. package/src/recovery/render-system-candidate.ts +54 -11
  321. package/src/reflection/background.ts +151 -0
  322. package/src/reflection/filter.ts +3 -0
  323. package/src/reflection/projection.ts +16 -6
  324. package/src/reflection/record-owner.ts +282 -86
  325. package/src/render-contract.ts +50 -32
  326. package/src/render-graph-primitives.ts +28 -3
  327. package/src/render-pipeline.ts +20 -1
  328. package/src/render-system-extract-tail.ts +23 -3
  329. package/src/render-system-extract.ts +127 -42
  330. package/src/render-system.ts +35 -7
  331. package/src/scene/render-scene.ts +8 -0
  332. package/src/ssao-config.ts +25 -8
  333. package/src/ssr/graph.ts +78 -58
  334. package/src/temporal/gpu.ts +5 -0
  335. package/src/temporal/standard-scene-data.ts +7 -1
  336. package/src/temporal/target-coverage-attachment.ts +72 -0
  337. package/src/temporal/temporal-view.ts +10 -4
  338. package/src/temporal/view.ts +12 -2
  339. package/src/transmission/__tests__/standard-transmission.dawn.test.ts +24 -9
  340. package/src/typed-render-graph-primitives.ts +38 -0
  341. package/src/volume/component.ts +1 -0
  342. package/src/volume/passes.ts +3 -3
  343. package/dist/chunk-33XZFTQU.mjs.map +0 -1
  344. package/dist/chunk-BQVQOQJH.mjs.map +0 -1
  345. package/dist/chunk-BTWH7BP4.mjs.map +0 -1
  346. package/dist/chunk-FUODTTIA.mjs.map +0 -1
  347. package/dist/chunk-JQTSEI3Z.mjs.map +0 -1
  348. package/dist/chunk-NICXSHAT.mjs.map +0 -1
  349. package/dist/chunk-NRNXBLIJ.mjs.map +0 -1
  350. package/dist/chunk-S4DNKQYQ.mjs.map +0 -1
@@ -9,6 +9,7 @@ import {
9
9
  type RhiRenderPassEncoder,
10
10
  } from '@forgeax/engine-rhi';
11
11
  import type { MaterialRenderState, PassSelector } from '@forgeax/engine-types';
12
+ import { transmissionBackdropAvailable } from '../assembly/device-feature-admission';
12
13
  import { gpuDrivenShadowDrawKey } from '../extract/gpu-driven';
13
14
  import type { SubmissionPlan } from '../gpu-driven/batch-topology';
14
15
  import type { GpuDrivenShadowBatchProjection } from '../gpu-driven/production-raster';
@@ -50,7 +51,9 @@ import {
50
51
  prepareMaterialSkylight,
51
52
  } from './main-pass-material';
52
53
  import {
54
+ findFromChain,
53
55
  getOrCreateFromChain,
56
+ getOrCreateFromChainResult,
54
57
  INSTANCE_UBO_FULL_ARRAY_BYTES,
55
58
  MAX_UNIFORM_INSTANCES,
56
59
  MESH_PER_ENTITY_STRIDE,
@@ -77,8 +80,8 @@ export interface GpuDrivenShadowBatch {
77
80
  readonly meshBindGroup: BindGroup;
78
81
  readonly visibleBindGroup: BindGroup;
79
82
  readonly deformation: 'rigid' | 'skin';
80
- /** Receipt-derived material BG for alpha-mask batches; opaque uses the pass singleton. */
81
- readonly alphaMaskMaterialGroup?: BindGroup | undefined;
83
+ /** Complete binding for this batch, including opaque batches after custom casters. */
84
+ readonly materialGroup: BindGroup;
82
85
  readonly vertexBuffer: Buffer;
83
86
  readonly indexBuffer?: Buffer | undefined;
84
87
  readonly indexFormat?: 'uint16' | 'uint32' | undefined;
@@ -459,12 +462,7 @@ export function recordGpuDrivenShadowIndirect(
459
462
  pass.setVertexBuffer(0, raster.vertexBuffer);
460
463
  currentVertex = raster.vertexBuffer;
461
464
  }
462
- if (raster.alphaMaskMaterialGroup !== undefined) {
463
- // Alpha-mask shadow variants sample the receipt-owned base-color
464
- // texture. Opaque batches keep the pass-level singleton bound by the
465
- // caller, so group(1) remains one stable layout for every draw.
466
- pass.setBindGroup(1, raster.alphaMaskMaterialGroup, [0]);
467
- }
465
+ pass.setBindGroup(1, raster.materialGroup, [0]);
468
466
  if (raster.indexBuffer !== undefined) {
469
467
  if (raster.indexFormat === undefined) {
470
468
  throw new RhiError({
@@ -637,12 +635,22 @@ function validateShadowOwnership(
637
635
  const overlap = [...claimed].filter((key) => recordedKeys.has(key));
638
636
  const union = new Set([...claimed, ...recordedKeys]);
639
637
  const missing = [...expectedKeys].filter((key) => !union.has(key));
640
- const extra = [...union].filter((key) => !expectedKeys.has(key));
641
- if (overlap.length === 0 && missing.length === 0 && extra.length === 0) return;
638
+ const unexpectedClaims = [...claimed].filter((key) => !expectedKeys.has(key));
639
+ // `shadowCasterMembership` describes the concrete draws that the GPU
640
+ // producer is eligible to claim. A renderable that stays on the CPU lane
641
+ // (for example a clustered frame without a compatible GPU-driven PBR
642
+ // variant, or a dynamic mesh whose producer receipt is not ready) still
643
+ // records a valid ShadowCaster draw, but it has no membership row. Treating
644
+ // every CPU-only key as an "extra" made the ownership check reject that
645
+ // legitimate residual path and stopped the whole shadow pass. Ownership
646
+ // needs two invariants here: a draw is never both GPU-claimed and CPU-
647
+ // recorded, and every GPU-eligible membership is covered by one of those
648
+ // lanes. CPU-only residuals are already owned by the record path.
649
+ if (overlap.length === 0 && missing.length === 0 && unexpectedClaims.length === 0) return;
642
650
  throw new RhiError({
643
651
  code: 'internal-error',
644
652
  expected: `disjoint ShadowCaster ownership for ${shadowViewIdentityKey(identity)}`,
645
- hint: `claimed=${[...claimed].sort().join(',')} recorded=${[...recordedKeys].sort().join(',')} missing=${missing.sort().join(',')} extra=${extra.sort().join(',')}`,
653
+ hint: `claimed=${[...claimed].sort().join(',')} recorded=${[...recordedKeys].sort().join(',')} missing=${missing.sort().join(',')} unexpectedClaims=${unexpectedClaims.sort().join(',')}`,
646
654
  });
647
655
  }
648
656
 
@@ -698,18 +706,35 @@ function recordGpuDrivenShadowIfPublished(
698
706
  hint: 'keep shadow batch scene rows aligned with the shared SubmissionPlan',
699
707
  });
700
708
  }
709
+ const shadowArtifact = projection.shadowArtifact;
710
+ const shadowReceipt = shadowArtifact.receipt;
711
+ if (shadowReceipt === undefined) {
712
+ throw new RhiError({
713
+ code: 'rhi-not-available',
714
+ expected: `published shadow MaterialProgramAbi for batch ${batch.batchId}`,
715
+ hint: 'keep the shadow draw out of the capable lane until its producer receipt is ready',
716
+ });
717
+ }
718
+ const shadowVariantSet =
719
+ shadowArtifact.variantSet ??
720
+ (shadowArtifact.material === SHADOW_CASTER_SHADER_ID
721
+ ? shadowCasterVariantSet(
722
+ c.runtime.device.caps.storageBuffer,
723
+ projection.deformation === 'skin',
724
+ true,
725
+ batch.key.admission === 'alpha-mask',
726
+ projection.vertexColorAvailable,
727
+ )
728
+ : undefined);
701
729
  const pipeline = c.runtime.getMaterialShaderPipeline?.(
702
- SHADOW_CASTER_SHADER_ID,
730
+ // A scene-index shadow artifact may retain the logical material id for
731
+ // batching while its specialization key owns the actual WGSL module.
732
+ shadowArtifact.specializationKey ?? shadowArtifact.material,
703
733
  false,
704
734
  shadowRasterState(undefined, identity.kind === 'point'),
705
735
  batch.key.topology,
706
736
  batch.key.drawKind === 'indexed' ? projection.mesh.indexFormat : undefined,
707
- shadowCasterVariantSet(
708
- c.runtime.device.caps.storageBuffer,
709
- projection.deformation === 'skin',
710
- true,
711
- batch.key.admission === 'alpha-mask',
712
- ),
737
+ shadowVariantSet,
713
738
  'shadow-caster',
714
739
  undefined,
715
740
  undefined,
@@ -718,9 +743,15 @@ function recordGpuDrivenShadowIfPublished(
718
743
  undefined,
719
744
  undefined,
720
745
  projection.mesh.layoutProjection,
721
- undefined,
746
+ // The shadow projection carries the producer-validated receipt. Select
747
+ // the immediate module adapter so a newly loaded custom Surface cannot
748
+ // lose its first capable shadow draw to async pre-bake warm-up.
749
+ 'immediate',
722
750
  projection.deformation === 'skin' ? 'gpu-driven-skin' : 'gpu-driven-pbr',
723
- 'vs_scene_index',
751
+ shadowReceipt.sceneIndexEntry,
752
+ undefined,
753
+ projection.shadowVertexEntry,
754
+ projection.shadowFragmentEntry,
724
755
  );
725
756
  if (pipeline === null || pipeline === undefined) {
726
757
  throw new RhiError({
@@ -736,14 +767,25 @@ function recordGpuDrivenShadowIfPublished(
736
767
  hint: 'keep the geometry residency and topology draw kind aligned before capable recording',
737
768
  });
738
769
  }
770
+ const materialGroup =
771
+ shadowArtifact.material !== SHADOW_CASTER_SHADER_ID
772
+ ? ensureGpuDrivenCustomShadowMaterialBg(c, projection)
773
+ : batch.key.admission === 'alpha-mask'
774
+ ? ensureGpuDrivenAlphaMaskMaterialBg(c, projection)
775
+ : ensureSpotShadowMaterialBg(c);
776
+ if (materialGroup === null) {
777
+ throw new RhiError({
778
+ code: 'rhi-not-available',
779
+ expected: 'material resources for every GPU shadow batch',
780
+ hint: 'publish the shadow material binding before recording the indirect batch',
781
+ });
782
+ }
739
783
  batches.set(batch.batchId, {
740
784
  pipeline,
741
785
  meshBindGroup: projection.meshBindGroup,
742
786
  visibleBindGroup: projection.visibleBindGroup,
743
787
  deformation: projection.deformation,
744
- ...(batch.key.admission === 'alpha-mask'
745
- ? { alphaMaskMaterialGroup: ensureGpuDrivenAlphaMaskMaterialBg(c, projection) }
746
- : {}),
788
+ materialGroup,
747
789
  vertexBuffer: projection.mesh.vertexBuffer.handle,
748
790
  ...(batch.key.drawKind === 'indexed' && projection.mesh.indexBuffer !== null
749
791
  ? {
@@ -1627,6 +1669,9 @@ export function recordShadowCasterDraws(
1627
1669
  skinned,
1628
1670
  false,
1629
1671
  Number(shadowDispatch?.paramSnapshot?.alphaCutoff ?? 0) > 0,
1672
+ entry.mesh.layoutProjection.attributes.some(
1673
+ (attribute) => attribute.key === 'color',
1674
+ ),
1630
1675
  ),
1631
1676
  'shadow-caster',
1632
1677
  undefined, // meshAttributes
@@ -1733,15 +1778,31 @@ export function recordShadowCasterDraws(
1733
1778
  /**
1734
1779
  * Build (or reuse) the neutral `shadow-material-singleton` @group(1) BG for
1735
1780
  * default casters without an authored material dispatch. Authored opaque and
1736
- * masked residuals bind their own prepared material slots instead. Reuses the same singleton Map
1737
- * entry encodeDirectionalShadowPass / encodePointShadowPass write so the three paths share
1738
- * one allocation per frame (D-6).
1781
+ * masked residuals bind their own prepared material slots instead. Directional,
1782
+ * point, and spot passes share bindings only while every resource identity
1783
+ * matches; scene-table growth or recovery must create a fresh bind group.
1739
1784
  */
1740
1785
  function ensureSpotShadowMaterialBg(c: _InternalRenderPipelineContext): BindGroup | null {
1741
1786
  const { runtime, frameState, pipelineState } = c;
1742
- const cached = frameState.singletonMaterialCache.get('shadow-material-singleton');
1743
- if (cached !== undefined) return cached;
1744
1787
  const fb = pipelineState.skylightFallback;
1788
+ const sceneMaterialBuffer =
1789
+ c.gpuDrivenStandardPbrFrameResources?.sceneMaterialBuffer ??
1790
+ pipelineState.meshStorageBuffer.buffer;
1791
+ const handles = [
1792
+ pipelineState.materialBindGroupLayout,
1793
+ pipelineState.materialUniformBuffer.buffer,
1794
+ pipelineState.defaultSampler,
1795
+ pipelineState.defaultNormalTextureView,
1796
+ pipelineState.fallbackTextureView,
1797
+ sceneMaterialBuffer,
1798
+ ...(fb === null ? [] : [fb]),
1799
+ ];
1800
+ const cached = findFromChain(
1801
+ frameState.shadowMaterialBindGroups,
1802
+ handles,
1803
+ 'shadow-material-singleton',
1804
+ );
1805
+ if (cached !== undefined) return cached;
1745
1806
  const fallbackEntries: BindGroupEntry[] = buildPbrMaterialUserRegionEntries().map((entry) => {
1746
1807
  if (entry.buffer !== undefined) {
1747
1808
  return {
@@ -1775,15 +1836,21 @@ function ensureSpotShadowMaterialBg(c: _InternalRenderPipelineContext): BindGrou
1775
1836
  });
1776
1837
  const merged =
1777
1838
  fb !== null
1778
- ? assembleMaterialWithSkylightEntries(fallbackEntries, {
1779
- irradianceView: fb.irradianceView,
1780
- irradianceSampler: fb.sampler,
1781
- prefilterView: fb.prefilterView,
1782
- prefilterSampler: fb.sampler,
1783
- brdfLutView: fb.brdfLutView,
1784
- brdfLutSampler: fb.sampler,
1785
- intensityBuffer: fb.intensityBuffer,
1786
- })
1839
+ ? assembleMaterialWithSkylightEntries(
1840
+ fallbackEntries,
1841
+ {
1842
+ irradianceView: fb.irradianceView,
1843
+ irradianceSampler: fb.sampler,
1844
+ prefilterView: fb.prefilterView,
1845
+ prefilterSampler: fb.sampler,
1846
+ brdfLutView: fb.brdfLutView,
1847
+ brdfLutSampler: fb.sampler,
1848
+ intensityBuffer: fb.intensityBuffer,
1849
+ },
1850
+ transmissionBackdropAvailable(runtime.device.limits.maxSampledTexturesPerShaderStage)
1851
+ ? undefined
1852
+ : null,
1853
+ )
1787
1854
  : fallbackEntries;
1788
1855
  // Binding(46) is the optional scene-material storage table. The material
1789
1856
  // BGL intentionally omits it on the uniform-only WebGL2 lane, so emitting
@@ -1793,26 +1860,37 @@ function ensureSpotShadowMaterialBg(c: _InternalRenderPipelineContext): BindGrou
1793
1860
  // admission; this singleton only needs the optional slot when that same
1794
1861
  // capability is present.
1795
1862
  if (runtime.device.caps.storageBuffer) {
1863
+ // Scene-index shadow variants read MaterialParameters by the projected
1864
+ // row selected in visibleItems. The legacy singleton used the mesh SSBO
1865
+ // here because the old shadow vertex path never consumed binding(46); on
1866
+ // the capable scene-index lane that buffer is a different struct and can
1867
+ // make the alpha/depth fragment discard every caster. Reuse the frame's
1868
+ // producer-owned scene material table, with the mesh buffer only for
1869
+ // direct/legacy callers that do not publish one.
1796
1870
  merged.push({
1797
1871
  binding: 46,
1798
1872
  resource: {
1799
1873
  kind: 'buffer',
1800
- value: { buffer: pipelineState.meshStorageBuffer.buffer },
1874
+ value: { buffer: sceneMaterialBuffer },
1801
1875
  },
1802
1876
  });
1803
1877
  }
1804
- const r = runtime.device.createBindGroup({
1805
- label: 'shadow-material-bg',
1806
- layout: pipelineState.materialBindGroupLayout,
1807
- entries: merged,
1808
- });
1878
+ const r = getOrCreateFromChainResult(
1879
+ frameState.shadowMaterialBindGroups,
1880
+ handles,
1881
+ 'shadow-material-singleton',
1882
+ () =>
1883
+ runtime.device.createBindGroup({
1884
+ label: 'shadow-material-bg',
1885
+ layout: pipelineState.materialBindGroupLayout,
1886
+ entries: merged,
1887
+ }),
1888
+ c.bindGroupCounts,
1889
+ );
1809
1890
  if (!r.ok) {
1810
1891
  runtime.errorRegistry.fire(r.error);
1811
1892
  return null;
1812
1893
  }
1813
- c.bindGroupCounts.createBindGroup += 1;
1814
- c.bindGroupCounts.keys.push('shadow-material-singleton');
1815
- frameState.singletonMaterialCache.set('shadow-material-singleton', r.value);
1816
1894
  return r.value;
1817
1895
  }
1818
1896
 
@@ -1834,9 +1912,6 @@ function ensureGpuDrivenAlphaMaskMaterialBg(
1834
1912
  hint: 'publish the receipt-derived scene material table before the capable shadow pass',
1835
1913
  });
1836
1914
  }
1837
- const materialKey = `shadow-material-alpha:${projection.materialEntityKey}:${projection.material.materialHandle ?? -1}:${c.store.materialResourceEpoch}`;
1838
- const cached = c.frameState.singletonMaterialCache.get(materialKey);
1839
- if (cached !== undefined) return cached;
1840
1915
  const fallback = c.pipelineState.skylightFallback;
1841
1916
  if (fallback === null) {
1842
1917
  throw new RhiError({
@@ -1874,6 +1949,68 @@ function ensureGpuDrivenAlphaMaskMaterialBg(
1874
1949
  projection.materialEntityKey,
1875
1950
  c.world,
1876
1951
  );
1877
- c.frameState.singletonMaterialCache.set(materialKey, bindGroup);
1952
+ return bindGroup;
1953
+ }
1954
+
1955
+ /**
1956
+ * Build the group(1) binding for a receipt-backed custom shadow program. The
1957
+ * ordinary shadow singleton is Standard-only; binding it for a custom layout
1958
+ * would make the pipeline appear executable while deferring a BGL mismatch to
1959
+ * submit. Custom resources therefore use the same material producer as the
1960
+ * main pass, using the selected scene-index row when the published custom ABI
1961
+ * declares that resource. No Standard-only alpha or shader rows are
1962
+ * synthesized for the custom artifact.
1963
+ */
1964
+ function ensureGpuDrivenCustomShadowMaterialBg(
1965
+ c: _InternalRenderPipelineContext,
1966
+ projection: GpuDrivenShadowBatchProjection,
1967
+ ): BindGroup {
1968
+ const shaderId = projection.shadowArtifact.material;
1969
+ const fallback = c.pipelineState.skylightFallback;
1970
+ if (fallback === null) {
1971
+ throw new RhiError({
1972
+ code: 'rhi-not-available',
1973
+ expected: 'skylight resources for custom shadow material binding',
1974
+ hint: 'publish the custom material resource owner before recording the shadow lane',
1975
+ });
1976
+ }
1977
+ const sceneMaterialBuffer = c.gpuDrivenStandardPbrFrameResources?.sceneMaterialBuffer;
1978
+ if (sceneMaterialBuffer === undefined) {
1979
+ throw new RhiError({
1980
+ code: 'rhi-not-available',
1981
+ expected: 'producer-owned scene material buffer for custom shadow ABI',
1982
+ hint: 'publish the selected shadow MaterialProgramAbi scene-index resource before recording',
1983
+ });
1984
+ }
1985
+ const skylightResources = {
1986
+ irradianceView: fallback.irradianceView,
1987
+ irradianceSampler: fallback.sampler,
1988
+ prefilterView: fallback.prefilterView,
1989
+ prefilterSampler: fallback.sampler,
1990
+ brdfLutView: fallback.brdfLutView,
1991
+ brdfLutSampler: fallback.sampler,
1992
+ intensityBuffer: fallback.intensityBuffer,
1993
+ } satisfies import('../ibl/skylight-bind-group').SkylightBindGroupResources;
1994
+ const deps: PerSubmeshMaterialBgDeps = {
1995
+ runtime: c.runtime,
1996
+ pipelineState: c.pipelineState,
1997
+ world: c.world,
1998
+ store: c.store,
1999
+ materialSlice: STANDARD_PBR_UBO_SIZE,
2000
+ videoHighPerfAvailable: false,
2001
+ skylightResources,
2002
+ materialBgShared: c.frameState.materialBgShared,
2003
+ materialBgAssemblyCache: c.materialBgAssemblyCache,
2004
+ bindGroupCounts: c.bindGroupCounts,
2005
+ frameState: c.frameState,
2006
+ sceneMaterialBuffer,
2007
+ };
2008
+ const bindGroup = buildPerSubmeshMaterialBg(
2009
+ deps,
2010
+ projection.material,
2011
+ projection.materialEntityKey,
2012
+ c.world,
2013
+ shaderId,
2014
+ );
1878
2015
  return bindGroup;
1879
2016
  }
@@ -61,6 +61,7 @@ import {
61
61
  import { GPU_BUFFER_USAGE_COPY_DST, GPU_BUFFER_USAGE_UNIFORM } from '../gpu-usage';
62
62
  import { createStandardSurfaceLightingBindGroup } from '../hdrp-buffers';
63
63
  import type { RenderFeatureGraphInspection } from '../inspection-types';
64
+ import type { RenderExtent } from '../pipeline/render-extent';
64
65
  import {
65
66
  type StandardTopologyInputValue,
66
67
  standardLightingTopologySignature,
@@ -76,6 +77,7 @@ import {
76
77
  resetStandardLutState,
77
78
  } from '../pipeline/standard-output/lut-state';
78
79
  import { resolveVolumetricFogProfile, STANDARD_PIPELINE_ID } from '../pipeline/standard-profile';
80
+ import { type ProbeBackgroundResources, recordProbeBackground } from '../reflection/background';
79
81
  import type { CameraSnapshot } from '../render-contract';
80
82
  import type {
81
83
  RenderPipelineFeatureTarget,
@@ -99,6 +101,7 @@ import {
99
101
  temporalWriteIndex,
100
102
  } from '../temporal/gpu';
101
103
  import { isSceneDataTarget } from '../temporal/scene-data';
104
+ import { createTargetCoverageAttachment } from '../temporal/target-coverage-attachment';
102
105
  import type { TransmissionDemand } from '../transmission/projection';
103
106
  import { hasVolumetricFogCapability } from '../volume/capability';
104
107
  import { deriveVolumetricFogExtent, deriveVolumetricFogResolvedExtent } from '../volume/resources';
@@ -491,6 +494,7 @@ export interface ReflectionProbeFilterGraphState {
491
494
  }
492
495
 
493
496
  export interface ReflectionProbeGraphWork {
497
+ readonly background?: ProbeBackgroundResources;
494
498
  readonly probeIndex: number;
495
499
  readonly rawTexture: Texture;
496
500
  readonly rawCubeView: TextureView;
@@ -716,6 +720,7 @@ function addCubeCaptureGraphPasses(
716
720
  export function addReflectionProbeGraphPasses(
717
721
  builder: RenderGraphBuilder<RenderPipelineFrame>,
718
722
  state: ReflectionProbeGraphState,
723
+ environmentCube?: import('../environment/ibl').GraphEnvironment,
719
724
  ): Result<readonly import('@forgeax/engine-render-graph').GraphAccess[], RenderGraphError> {
720
725
  const accesses: import('@forgeax/engine-render-graph').GraphAccess[] = [];
721
726
  for (const work of state.work) {
@@ -801,6 +806,11 @@ export function addReflectionProbeGraphPasses(
801
806
  if (!depth.ok) return depth;
802
807
  const added = builder.addRasterPass(`reflection-probe.${work.probeIndex}.capture.${face}`, {
803
808
  accesses: [
809
+ ...(environmentCube === undefined
810
+ ? []
811
+ : [environmentCube.sky, environmentCube.irradiance, environmentCube.prefilter].map(
812
+ (resource) => ({ resource, usage: 'sampled-read' as const }),
813
+ )),
804
814
  { resource: view.value, usage: 'color-attachment' },
805
815
  { resource: depth.value, usage: 'depth-stencil-write' },
806
816
  ],
@@ -828,9 +838,35 @@ export function addReflectionProbeGraphPasses(
828
838
  if (!captureColor.ok || !captureDepth.ok) return;
829
839
  if (work.faceCamera === undefined || work.viewBindGroupDynamicOffset === undefined)
830
840
  return;
841
+ recordProbeBackground(
842
+ work.background,
843
+ internal,
844
+ work.faceCamera,
845
+ pass,
846
+ environmentCube === undefined
847
+ ? undefined
848
+ : resources.textureView(environmentCube.sky).unwrap(),
849
+ );
850
+ const captureContext = {
851
+ ...internal,
852
+ ...(environmentCube === undefined
853
+ ? {}
854
+ : {
855
+ environmentIbl: {
856
+ irradiance: resources.textureView(environmentCube.irradiance).unwrap(),
857
+ prefilter: resources.textureView(environmentCube.prefilter).unwrap(),
858
+ },
859
+ }),
860
+ };
861
+ delete captureContext.reflectionProbes;
862
+ delete captureContext.hdrpSsaoBlurredView;
863
+ delete captureContext.gpuDrivenDrawKeys;
864
+ delete captureContext.gpuDrivenStandardPbrFrameResources;
831
865
  encodeMainPass(
832
866
  {
833
- ...internal,
867
+ ...captureContext,
868
+ dispatch: internal.captureDispatch ?? internal.dispatch,
869
+ foldDispatchPlan: null,
834
870
  camera: work.faceCamera,
835
871
  viewBindGroupDynamicOffset: work.viewBindGroupDynamicOffset,
836
872
  geometryColorView: captureColor.value,
@@ -1325,6 +1361,7 @@ function topologyOf(
1325
1361
  volumetricFog: ExtractedVolumetricFog | undefined,
1326
1362
  standardLighting: StandardTopologyInputValue | undefined,
1327
1363
  ssr: SsrSpatialAdmission | undefined,
1364
+ renderExtent: RenderExtent | undefined,
1328
1365
  ): Result<RenderPipelineTopology, RhiError> {
1329
1366
  const cascadeCount = Math.max(1, Math.min(4, Math.round(lights.cascadeCount ?? 1))) as
1330
1367
  | 1
@@ -1389,6 +1426,7 @@ function topologyOf(
1389
1426
  clearOnly,
1390
1427
  reflectionFallback: { enabled: frameState.reflectionFallbackDemand === true },
1391
1428
  ssr,
1429
+ ...(renderExtent === undefined ? {} : { extent: renderExtent }),
1392
1430
  surface: {
1393
1431
  width,
1394
1432
  height,
@@ -1748,6 +1786,7 @@ export function ensureCompiledFrameGraph(
1748
1786
  standardLighting?: StandardTopologyInputValue,
1749
1787
  onRecoveryError?: (error: unknown) => void,
1750
1788
  ssr?: SsrSpatialAdmission,
1789
+ renderExtent?: RenderExtent,
1751
1790
  ): CompiledRenderGraph<RenderPipelineFrame> | null {
1752
1791
  const featureMetrics = mutableFeatureGraphInspection(internals);
1753
1792
  featureMetrics.ensureCalls += 1;
@@ -1800,6 +1839,7 @@ export function ensureCompiledFrameGraph(
1800
1839
  volumetricFog,
1801
1840
  standardLighting,
1802
1841
  ssr,
1842
+ renderExtent,
1803
1843
  );
1804
1844
  if (!topologyResult.ok) {
1805
1845
  featureMetrics.buildFailures += 1;
@@ -1972,6 +2012,16 @@ export function ensureCompiledFrameGraph(
1972
2012
  return lastKnownGood();
1973
2013
  }
1974
2014
  const taaHistory = camera.antialias === 'taa' ? importTemporalHistoryTargets(builder) : undefined;
2015
+ const targetCoverage =
2016
+ camera.dynamicResolution === undefined || topology.extent === undefined
2017
+ ? undefined
2018
+ : createTargetCoverageAttachment(builder, topology.extent);
2019
+ if (targetCoverage !== undefined && !targetCoverage.ok) {
2020
+ internals.errorRegistry.fire(targetCoverage.error);
2021
+ featureGraphCandidate?.onRejected?.();
2022
+ discardPendingStandardOutput();
2023
+ return lastKnownGood();
2024
+ }
1975
2025
  const ssrHistory = ssr?.status === 'admitted' ? importSsrHistoryTargets(builder) : undefined;
1976
2026
  let projectedFeatures = false;
1977
2027
  const featureProjection = createRenderFeatureProjectionState();
@@ -2006,6 +2056,7 @@ export function ensureCompiledFrameGraph(
2006
2056
  capabilities: { rgba16floatRenderable: internals.device.caps.rgba16floatRenderable },
2007
2057
  ...(occlusion === undefined ? {} : { occlusion }),
2008
2058
  ...(taaHistory === undefined ? {} : { taaHistory }),
2059
+ ...(targetCoverage?.ok === true ? { targetCoverage: targetCoverage.value } : {}),
2009
2060
  ...(ssrHistory === undefined ? {} : { ssrHistory }),
2010
2061
  encodeTransmissionMip: ({ pass, resources, source }) => {
2011
2062
  const sourceView = resources.textureView(source);
@@ -2016,7 +2067,12 @@ export function ensureCompiledFrameGraph(
2016
2067
  projectGpuDriven: (target) => {
2017
2068
  if (projectedGpuDriven || gpuDriven === undefined) return ok(undefined);
2018
2069
  projectedGpuDriven = true;
2019
- return gpuDriven.project(builder, target.format, target.sampleCount);
2070
+ return gpuDriven.project(
2071
+ builder,
2072
+ target.format,
2073
+ target.sampleCount,
2074
+ target.additionalColorFormats,
2075
+ );
2020
2076
  },
2021
2077
  ...(gpuDriven?.projectShadow === undefined
2022
2078
  ? {}
@@ -2069,10 +2125,11 @@ export function ensureCompiledFrameGraph(
2069
2125
  });
2070
2126
  return projected.ok ? ok(undefined) : projected;
2071
2127
  },
2072
- contributeCubeCaptures: () => {
2128
+ contributeCubeCaptures: (environmentCube) => {
2073
2129
  const reflectionProbes = addReflectionProbeGraphPasses(
2074
2130
  builder,
2075
2131
  cubeCaptureState?.reflectionProbes ?? { work: [] },
2132
+ environmentCube,
2076
2133
  );
2077
2134
  if (!reflectionProbes.ok) return reflectionProbes;
2078
2135
  return cubeCaptureState === undefined
@@ -244,7 +244,7 @@ export function writeViewUbo(
244
244
  // accepted quality union occupies the existing four-float tail [128..131].
245
245
  // Point and Spot pcfKernelSize stay in their own snapshot paths and never
246
246
  // enter this Directional View projection.
247
- viewPayload[126] = lights.depthBias ?? 0.005;
247
+ viewPayload[126] = lights.depthBias ?? 0.00001;
248
248
  viewPayload[127] = lights.normalBias ?? 0.05;
249
249
  const filterCarrier = directionalShadowFilterCarrier(lights.directionalShadowQuality);
250
250
  viewPayload[128] = filterCarrier[0] ?? 0;
@@ -27,6 +27,7 @@ import {
27
27
  type PostProcessShaderEntry,
28
28
  postProcessShaderEntrySignature,
29
29
  } from '../fullscreen-post-process-pass';
30
+ import { collectGpuDrivenMaterialArtifacts } from '../gpu-driven/material-artifacts';
30
31
  import { GpuDrivenProduction } from '../gpu-driven/production-raster';
31
32
  import { inspectStandardLighting } from '../pipeline/standard-lighting/inspection';
32
33
  import { retireAutoExposureGpuResources } from '../pipeline/standard-output/auto-exposure/gpu';
@@ -52,7 +53,11 @@ import {
52
53
  type RenderFeatureGraphCandidate,
53
54
  } from '../record/typed-frame-graph';
54
55
  import { STANDARD_OUTPUT_TRANSFORM_FEATURE_ID } from '../render-contract';
55
- import type { ExtractedFrame, MaterialSnapshot } from '../render-system-extract';
56
+ import type {
57
+ ExtractedFrame,
58
+ MaterialSnapshot,
59
+ RenderableSnapshot,
60
+ } from '../render-system-extract';
56
61
  import type { PersistentGpuDrivenCandidate, PersistentRenderScene } from '../scene/render-scene';
57
62
  import { SHADOW_ATLAS_DEFAULT_LAYERS } from '../shadow-atlas';
58
63
  import { createTemporalFrameTransaction } from '../temporal/frame';
@@ -271,7 +276,7 @@ export function createRenderSystemRecovery(
271
276
  instancesBgShared: new WeakMap(),
272
277
  materialBgShared: new Map(),
273
278
  materialBgAssemblyCache: new Map(),
274
- singletonMaterialCache: new Map(),
279
+ shadowMaterialBindGroups: new WeakMap(),
275
280
  postProcessBgCache: new WeakMap(),
276
281
  probeBlendBuffers: new Map(),
277
282
  probeBlendRecordBufferCapacity: 0,
@@ -280,7 +285,11 @@ export function createRenderSystemRecovery(
280
285
  };
281
286
 
282
287
  const publishRecoveryGraphCandidate = (candidate: RecoveryGraphCandidate): void => {
283
- candidate.recoveryReadiness.assertPreparedCache();
288
+ if (candidate.recoveryReadiness.assertFirstRecoveryFrame) {
289
+ candidate.recoveryReadiness.assertFirstRecoveryFrame();
290
+ } else {
291
+ candidate.recoveryReadiness.assertPreparedCache();
292
+ }
284
293
  const previousFeatureHost = internals.featureHost;
285
294
  // The caller enters this method only after the active generation swap and
286
295
  // after resetForRecover() has shed every lost-device owner. Replace the
@@ -445,11 +454,40 @@ export function createRenderSystemRecovery(
445
454
  runtime.internals.device,
446
455
  gpuDrivenShaderFactory,
447
456
  );
448
- const standardPbrArtifact = runtime.internals.getMaterialShaderArtifact?.(
449
- 'forgeax::default-standard-pbr',
457
+ const shadowProjection = persistentRenderScene.shadowCasterProjection();
458
+ // The retained scene owns prepared draw receipts. The extraction seed
459
+ // precedes GPU admission and must not stand in for that projection.
460
+ const preparedSnapshots = new Map(
461
+ candidateGpuDrivenScene.state.slots.map((slot) => [
462
+ `${slot.snapshot.worldId}:${slot.snapshot.entityKey}`,
463
+ slot.snapshot,
464
+ ]),
450
465
  );
451
- const standardPbrSkinArtifact =
452
- runtime.internals.getMaterialShaderArtifact?.('forgeax::pbr-skin');
466
+ const artifactRows = (renderables: readonly RenderableSnapshot[]) =>
467
+ renderables.map((source, renderableIndex) => ({
468
+ source: {
469
+ ...source,
470
+ gpuDrivenDraws:
471
+ preparedSnapshots.get(`${source.worldId}:${source.entityKey}`)?.gpuDrivenDraws ??
472
+ source.gpuDrivenDraws ??
473
+ [],
474
+ },
475
+ renderableIndex,
476
+ }));
477
+ const { materialArtifacts, shadowMaterialArtifacts, firstArtifact, firstSkinArtifact } =
478
+ collectGpuDrivenMaterialArtifacts({
479
+ rows: artifactRows(seed.frame.renderables),
480
+ shadowRows: artifactRows(shadowProjection?.renderables ?? []),
481
+ dispatch: seed.frame.dispatch,
482
+ shadowDispatch: shadowProjection?.dispatch ?? seed.frame.dispatch,
483
+ resolve: runtime.internals.getMaterialShaderArtifact,
484
+ clustered:
485
+ seed.frame.lights.point.length +
486
+ seed.frame.lights.spot.length +
487
+ seed.frame.lights.rect.length >
488
+ 0 || candidateFrameState.installedPipelineConfig?.ssao?.enabled === true,
489
+ reflectionFallback: candidateFrameState.reflectionFallbackDemand === true,
490
+ });
453
491
  const prepared = candidateGpuDrivenProduction.prepare({
454
492
  scene: candidateGpuDrivenScene.state,
455
493
  camera,
@@ -461,10 +499,15 @@ export function createRenderSystemRecovery(
461
499
  ),
462
500
  viewBindGroupLayout: runtime.pipelineState.viewBindGroupLayout,
463
501
  meshResidencyEpoch: runtime.internals.gpuStore.meshResidencyEpoch,
464
- hdrp: false,
465
- ...(standardPbrArtifact === undefined ? {} : { standardPbrArtifact }),
466
- ...(standardPbrSkinArtifact === undefined ? {} : { standardPbrSkinArtifact }),
467
- standardPbrPipelineState: runtime.pipelineState,
502
+
503
+ ...(firstArtifact === undefined ? {} : { materialArtifact: firstArtifact }),
504
+ ...(firstSkinArtifact === undefined ? {} : { materialSkinArtifact: firstSkinArtifact }),
505
+ ...(materialArtifacts.size === 0 ? {} : { materialArtifacts }),
506
+ ...(shadowMaterialArtifacts.size === 0 ? {} : { shadowMaterialArtifacts }),
507
+ materialPipelineState: runtime.pipelineState,
508
+ ...(runtime.internals.getMaterialShaderPipelineEntry === undefined
509
+ ? {}
510
+ : { materialPipelineFactory: runtime.internals.getMaterialShaderPipelineEntry }),
468
511
  });
469
512
  if (!prepared.ok) return failed('candidate GPU-driven preparation failed', prepared.error);
470
513
  preparedGpuDriven = prepared.value;