@forgeax/engine-render 0.1.19 → 0.1.21

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 (452) hide show
  1. package/README.md +215 -0
  2. package/dist/.tsbuildinfo +1 -1
  3. package/dist/assembly/device-feature-admission.d.ts +18 -0
  4. package/dist/assembly/device-feature-admission.d.ts.map +1 -0
  5. package/dist/assembly/directional-shadow-inspection.d.ts +38 -0
  6. package/dist/assembly/directional-shadow-inspection.d.ts.map +1 -0
  7. package/dist/assembly/factory.d.ts +34 -20
  8. package/dist/assembly/factory.d.ts.map +1 -1
  9. package/dist/assembly/host-contract.d.ts +9 -0
  10. package/dist/assembly/host-contract.d.ts.map +1 -1
  11. package/dist/assembly/render-target-host.d.ts +46 -0
  12. package/dist/assembly/render-target-host.d.ts.map +1 -0
  13. package/dist/assets/render-asset-port.d.ts.map +1 -1
  14. package/dist/authoring.mjs +3 -0
  15. package/dist/authoring.mjs.map +1 -1
  16. package/dist/capture/cube-views.d.ts +21 -0
  17. package/dist/capture/cube-views.d.ts.map +1 -0
  18. package/dist/capture/scheduler.d.ts +54 -0
  19. package/dist/capture/scheduler.d.ts.map +1 -0
  20. package/dist/{chunk-RJRUS55L.mjs → chunk-5YADUCA7.mjs} +1896 -1624
  21. package/dist/chunk-5YADUCA7.mjs.map +1 -0
  22. package/dist/{chunk-LOSO4CTV.mjs → chunk-6OPXDQ2E.mjs} +423 -46
  23. package/dist/chunk-6OPXDQ2E.mjs.map +1 -0
  24. package/dist/{chunk-IPXCABEP.mjs → chunk-BXBQQKFQ.mjs} +3 -9
  25. package/dist/chunk-BXBQQKFQ.mjs.map +1 -0
  26. package/dist/chunk-FS2KNUQH.mjs +1294 -0
  27. package/dist/chunk-FS2KNUQH.mjs.map +1 -0
  28. package/dist/components/camera.d.ts +1 -0
  29. package/dist/components/camera.d.ts.map +1 -1
  30. package/dist/components/cube-camera.d.ts +20 -0
  31. package/dist/components/cube-camera.d.ts.map +1 -0
  32. package/dist/components/directional-light.d.ts +11 -2
  33. package/dist/components/directional-light.d.ts.map +1 -1
  34. package/dist/components/directional-shadow-filter.d.ts +25 -0
  35. package/dist/components/directional-shadow-filter.d.ts.map +1 -0
  36. package/dist/components/index.d.ts +2 -0
  37. package/dist/components/index.d.ts.map +1 -1
  38. package/dist/components/light-helpers.d.ts.map +1 -1
  39. package/dist/components/reflection-probe.d.ts +17 -0
  40. package/dist/components/reflection-probe.d.ts.map +1 -0
  41. package/dist/components/spot-light.d.ts +12 -0
  42. package/dist/components/spot-light.d.ts.map +1 -1
  43. package/dist/construct-renderer.mjs +8552 -1612
  44. package/dist/construct-renderer.mjs.map +1 -1
  45. package/dist/device/gpu-residency.d.ts +19 -2
  46. package/dist/device/gpu-residency.d.ts.map +1 -1
  47. package/dist/environment/frame.d.ts.map +1 -1
  48. package/dist/environment/lifecycle.d.ts +5 -0
  49. package/dist/environment/lifecycle.d.ts.map +1 -1
  50. package/dist/errors/render.d.ts +209 -93
  51. package/dist/errors/render.d.ts.map +1 -1
  52. package/dist/extract/directional-shadow-projection.d.ts +23 -0
  53. package/dist/extract/directional-shadow-projection.d.ts.map +1 -0
  54. package/dist/extract/environment.d.ts +14 -0
  55. package/dist/extract/environment.d.ts.map +1 -1
  56. package/dist/extract/visibility.d.ts.map +1 -1
  57. package/dist/features/fullscreen.d.ts.map +1 -1
  58. package/dist/features/targets.d.ts.map +1 -1
  59. package/dist/features/types.d.ts +10 -0
  60. package/dist/features/types.d.ts.map +1 -1
  61. package/dist/fullscreen-post-process-pass.d.ts +13 -2
  62. package/dist/fullscreen-post-process-pass.d.ts.map +1 -1
  63. package/dist/gpu-driven/batch-topology.d.ts.map +1 -1
  64. package/dist/gpu-driven/production-raster.d.ts +0 -1
  65. package/dist/gpu-driven/production-raster.d.ts.map +1 -1
  66. package/dist/gpu-scene.d.ts.map +1 -1
  67. package/dist/gpu-usage.d.ts +2 -0
  68. package/dist/gpu-usage.d.ts.map +1 -1
  69. package/dist/hdrp-buffers.d.ts +19 -17
  70. package/dist/hdrp-buffers.d.ts.map +1 -1
  71. package/dist/ibl/IblPipelineCache.d.ts +4 -0
  72. package/dist/ibl/IblPipelineCache.d.ts.map +1 -1
  73. package/dist/ibl/kernel-cache.d.ts +36 -0
  74. package/dist/ibl/kernel-cache.d.ts.map +1 -0
  75. package/dist/index.d.ts +35 -4
  76. package/dist/index.d.ts.map +1 -1
  77. package/dist/index.mjs +4 -4
  78. package/dist/index.mjs.map +1 -1
  79. package/dist/inspection-types.d.ts +51 -0
  80. package/dist/inspection-types.d.ts.map +1 -1
  81. package/dist/instances-derived-bounds.d.ts +50 -0
  82. package/dist/instances-derived-bounds.d.ts.map +1 -0
  83. package/dist/internal.mjs +1 -1
  84. package/dist/light-buffer-layout.d.ts +30 -13
  85. package/dist/light-buffer-layout.d.ts.map +1 -1
  86. package/dist/mesh-material-bindings.d.ts +54 -0
  87. package/dist/mesh-material-bindings.d.ts.map +1 -1
  88. package/dist/pbr-pipeline.d.ts +20 -7
  89. package/dist/pbr-pipeline.d.ts.map +1 -1
  90. package/dist/pipeline/standard-forward-lane.d.ts +2 -1
  91. package/dist/pipeline/standard-forward-lane.d.ts.map +1 -1
  92. package/dist/pipeline/standard-lighting/errors.d.ts +4 -0
  93. package/dist/pipeline/standard-lighting/errors.d.ts.map +1 -0
  94. package/dist/pipeline/standard-lighting/graph.d.ts +24 -0
  95. package/dist/pipeline/standard-lighting/graph.d.ts.map +1 -0
  96. package/dist/pipeline/standard-lighting/inspection.d.ts +38 -0
  97. package/dist/pipeline/standard-lighting/inspection.d.ts.map +1 -0
  98. package/dist/pipeline/standard-lighting/layout.d.ts +28 -0
  99. package/dist/pipeline/standard-lighting/layout.d.ts.map +1 -0
  100. package/dist/pipeline/standard-lighting/light-frame.d.ts +33 -0
  101. package/dist/pipeline/standard-lighting/light-frame.d.ts.map +1 -0
  102. package/dist/pipeline/standard-lighting/membership.d.ts +14 -0
  103. package/dist/pipeline/standard-lighting/membership.d.ts.map +1 -0
  104. package/dist/pipeline/standard-lighting/prepare.d.ts +16 -0
  105. package/dist/pipeline/standard-lighting/prepare.d.ts.map +1 -0
  106. package/dist/pipeline/standard-lighting/topology.d.ts +45 -0
  107. package/dist/pipeline/standard-lighting/topology.d.ts.map +1 -0
  108. package/dist/pipeline/standard-lighting/transport.d.ts +36 -0
  109. package/dist/pipeline/standard-lighting/transport.d.ts.map +1 -0
  110. package/dist/pipeline/standard-pipeline.d.ts +4 -13
  111. package/dist/pipeline/standard-pipeline.d.ts.map +1 -1
  112. package/dist/pipeline/standard-post.d.ts.map +1 -1
  113. package/dist/pipeline/standard-profile.d.ts +12 -20
  114. package/dist/pipeline/standard-profile.d.ts.map +1 -1
  115. package/dist/pipeline-spec.d.ts +40 -7
  116. package/dist/pipeline-spec.d.ts.map +1 -1
  117. package/dist/point-shadow-inspection.d.ts +21 -0
  118. package/dist/point-shadow-inspection.d.ts.map +1 -0
  119. package/dist/record/frame-lighting.d.ts +29 -32
  120. package/dist/record/frame-lighting.d.ts.map +1 -1
  121. package/dist/record/frame-snapshot.d.ts +65 -15
  122. package/dist/record/frame-snapshot.d.ts.map +1 -1
  123. package/dist/record/frame-targets.d.ts +5 -0
  124. package/dist/record/frame-targets.d.ts.map +1 -1
  125. package/dist/record/frame.d.ts +12 -5
  126. package/dist/record/frame.d.ts.map +1 -1
  127. package/dist/record/gpu-pass-timing/contract.d.ts +96 -0
  128. package/dist/record/gpu-pass-timing/contract.d.ts.map +1 -0
  129. package/dist/record/gpu-pass-timing/errors.d.ts +18 -0
  130. package/dist/record/gpu-pass-timing/errors.d.ts.map +1 -0
  131. package/dist/record/gpu-pass-timing/index.d.ts +8 -0
  132. package/dist/record/gpu-pass-timing/index.d.ts.map +1 -0
  133. package/dist/record/gpu-pass-timing/parser.d.ts +11 -0
  134. package/dist/record/gpu-pass-timing/parser.d.ts.map +1 -0
  135. package/dist/record/gpu-pass-timing/session.d.ts +43 -0
  136. package/dist/record/gpu-pass-timing/session.d.ts.map +1 -0
  137. package/dist/record/gpu-timing.d.ts +37 -0
  138. package/dist/record/gpu-timing.d.ts.map +1 -0
  139. package/dist/record/main-pass-geometry.d.ts.map +1 -1
  140. package/dist/record/main-pass-material.d.ts +23 -2
  141. package/dist/record/main-pass-material.d.ts.map +1 -1
  142. package/dist/record/main-pass-sprite-draws.d.ts.map +1 -1
  143. package/dist/record/main-pass.d.ts +2 -0
  144. package/dist/record/main-pass.d.ts.map +1 -1
  145. package/dist/record/render-context.d.ts +48 -3
  146. package/dist/record/render-context.d.ts.map +1 -1
  147. package/dist/record/shadow-pass.d.ts.map +1 -1
  148. package/dist/record/skybox-post-pass.d.ts.map +1 -1
  149. package/dist/record/typed-frame-graph.d.ts +81 -5
  150. package/dist/record/typed-frame-graph.d.ts.map +1 -1
  151. package/dist/record/view-ubo.d.ts +7 -4
  152. package/dist/record/view-ubo.d.ts.map +1 -1
  153. package/dist/reflection/filter.d.ts +22 -0
  154. package/dist/reflection/filter.d.ts.map +1 -0
  155. package/dist/reflection/gpu-table.d.ts +25 -0
  156. package/dist/reflection/gpu-table.d.ts.map +1 -0
  157. package/dist/reflection/projection.d.ts +91 -0
  158. package/dist/reflection/projection.d.ts.map +1 -0
  159. package/dist/render-contract.d.ts +114 -7
  160. package/dist/render-contract.d.ts.map +1 -1
  161. package/dist/render-data.d.ts +10 -6
  162. package/dist/render-data.d.ts.map +1 -1
  163. package/dist/render-graph-primitives.d.ts +1 -0
  164. package/dist/render-graph-primitives.d.ts.map +1 -1
  165. package/dist/render-pipeline.d.ts +78 -2
  166. package/dist/render-pipeline.d.ts.map +1 -1
  167. package/dist/render-system-extract.d.ts +113 -20
  168. package/dist/render-system-extract.d.ts.map +1 -1
  169. package/dist/render-system.d.ts +24 -3
  170. package/dist/render-system.d.ts.map +1 -1
  171. package/dist/renderer-inspect.d.ts +29 -0
  172. package/dist/renderer-inspect.d.ts.map +1 -0
  173. package/dist/renderer.d.ts +43 -0
  174. package/dist/renderer.d.ts.map +1 -0
  175. package/dist/scene/render-scene.d.ts +14 -0
  176. package/dist/scene/render-scene.d.ts.map +1 -1
  177. package/dist/shadow-atlas.d.ts +3 -3
  178. package/dist/shadow-atlas.d.ts.map +1 -1
  179. package/dist/ssao-buffers.d.ts +3 -0
  180. package/dist/ssao-buffers.d.ts.map +1 -1
  181. package/dist/targets/contracts.d.ts +66 -0
  182. package/dist/targets/contracts.d.ts.map +1 -0
  183. package/dist/targets/graph-projection.d.ts +29 -0
  184. package/dist/targets/graph-projection.d.ts.map +1 -0
  185. package/dist/targets/material-source.d.ts +34 -0
  186. package/dist/targets/material-source.d.ts.map +1 -0
  187. package/dist/targets/owner.d.ts +32 -0
  188. package/dist/targets/owner.d.ts.map +1 -0
  189. package/dist/targets/physical.d.ts +18 -0
  190. package/dist/targets/physical.d.ts.map +1 -0
  191. package/dist/targets/readback.d.ts +39 -0
  192. package/dist/targets/readback.d.ts.map +1 -0
  193. package/dist/temporal/frame.d.ts +44 -0
  194. package/dist/temporal/frame.d.ts.map +1 -0
  195. package/dist/temporal/index.mjs +3 -3
  196. package/dist/typed-render-graph-primitives.d.ts +6 -1
  197. package/dist/typed-render-graph-primitives.d.ts.map +1 -1
  198. package/dist/typed-shadow-atlas.d.ts +10 -0
  199. package/dist/typed-shadow-atlas.d.ts.map +1 -0
  200. package/dist/typed-shadow-passes.d.ts +1 -1
  201. package/dist/typed-shadow-passes.d.ts.map +1 -1
  202. package/dist/volume/capability.d.ts +57 -0
  203. package/dist/volume/capability.d.ts.map +1 -0
  204. package/dist/volume/component.d.ts +61 -0
  205. package/dist/volume/component.d.ts.map +1 -0
  206. package/dist/volume/extract.d.ts +11 -0
  207. package/dist/volume/extract.d.ts.map +1 -0
  208. package/dist/volume/inspection.d.ts +38 -0
  209. package/dist/volume/inspection.d.ts.map +1 -0
  210. package/dist/volume/passes.d.ts +38 -0
  211. package/dist/volume/passes.d.ts.map +1 -0
  212. package/dist/volume/recovery.d.ts +38 -0
  213. package/dist/volume/recovery.d.ts.map +1 -0
  214. package/dist/volume/resources.d.ts +57 -0
  215. package/dist/volume/resources.d.ts.map +1 -0
  216. package/dist/volume/temporal.d.ts +35 -0
  217. package/dist/volume/temporal.d.ts.map +1 -0
  218. package/package.json +20 -20
  219. package/src/__tests__/bloom-exact-zero.unit.test.ts +48 -19
  220. package/src/__tests__/bloom-lifecycle.integration.test.ts +41 -13
  221. package/src/__tests__/camera-target-consumption.unit.test.ts +53 -0
  222. package/src/__tests__/cluster-binner.unit.test.ts +35 -0
  223. package/src/__tests__/cluster-grid-default-surface.unit.test.ts +7 -2
  224. package/src/__tests__/cube-camera-scheduler.unit.test.ts +70 -0
  225. package/src/__tests__/cube-camera-single-submit.perf.test.ts +75 -0
  226. package/src/__tests__/cube-camera-view-matrices.unit.test.ts +41 -0
  227. package/src/__tests__/cube-camera-vocabulary.unit.test.ts +47 -0
  228. package/src/__tests__/cube-camera.integration.test.ts +42 -0
  229. package/src/__tests__/device-feature-admission.unit.test.ts +73 -0
  230. package/src/__tests__/direct-light-snapshot.unit.test.ts +3 -3
  231. package/src/__tests__/docs-gate-green.unit.test.ts +38 -0
  232. package/src/__tests__/factory-contract.integration.test.ts +255 -29
  233. package/src/__tests__/fog-component.unit.test.ts +67 -0
  234. package/src/__tests__/fog.integration.test.ts +86 -0
  235. package/src/__tests__/fullscreen-feature-plan.unit.test.ts +37 -0
  236. package/src/__tests__/gpu-driven-indirect-raster-evidence.ts +10 -9
  237. package/src/__tests__/gpu-driven-indirect-raster.dawn.test.ts +17 -1
  238. package/src/__tests__/gpu-driven-production.integration.test.ts +16 -17
  239. package/src/__tests__/gpu-driven-view-graph.integration.test.ts +12 -4
  240. package/src/__tests__/gpu-pass-timing-browser-runner.ts +281 -0
  241. package/src/__tests__/gpu-pass-timing-coexistence.integration.test.ts +80 -0
  242. package/src/__tests__/gpu-pass-timing-contract.unit.test.ts +243 -0
  243. package/src/__tests__/gpu-pass-timing-exact-zero.unit.test.ts +131 -0
  244. package/src/__tests__/gpu-pass-timing-lifecycle.integration.test.ts +230 -0
  245. package/src/__tests__/gpu-pass-timing-observation.unit.test.ts +233 -0
  246. package/src/__tests__/gpu-pass-timing-session.unit.test.ts +438 -0
  247. package/src/__tests__/gpu-pass-timing.browser.test.ts +26 -0
  248. package/src/__tests__/gpu-pass-timing.rhi-null.unit.test.ts +125 -0
  249. package/src/__tests__/hdrp-group2-visibility.unit.test.ts +24 -0
  250. package/src/__tests__/instances-culling.integration.test.ts +94 -0
  251. package/src/__tests__/instances-derived-bounds.unit.test.ts +118 -0
  252. package/src/__tests__/ktx2-basis-gpu-consumer.dawn.test.ts +14 -14
  253. package/src/__tests__/material-observation.integration.test.ts +101 -0
  254. package/src/__tests__/mesh-buffer-usage-surface.unit.test.ts +1 -1
  255. package/src/__tests__/pbr-view-layout.unit.test.ts +16 -0
  256. package/src/__tests__/point-shadow-inspection.unit.test.ts +60 -0
  257. package/src/__tests__/public-surface.test-d.ts +10 -0
  258. package/src/__tests__/reflection-probe-authoring.unit.test.ts +71 -0
  259. package/src/__tests__/reflection-probe-filter.unit.test.ts +54 -0
  260. package/src/__tests__/reflection-probe-ibl-topology.unit.test.ts +45 -0
  261. package/src/__tests__/reflection-probe-pass-encode.integration.test.ts +101 -0
  262. package/src/__tests__/reflection-probe-performance.perf.test.ts +60 -0
  263. package/src/__tests__/reflection-probe-recovery.integration.test.ts +55 -0
  264. package/src/__tests__/reflection-probe-selection.unit.test.ts +46 -0
  265. package/src/__tests__/render-error-code-owner.test-d.ts +23 -3
  266. package/src/__tests__/render-feature-docs.unit.test.ts +1 -1
  267. package/src/__tests__/render-target-admission.unit.test.ts +80 -0
  268. package/src/__tests__/render-target-graph-projection.unit.test.ts +102 -0
  269. package/src/__tests__/render-target-inspection.unit.test.ts +52 -0
  270. package/src/__tests__/render-target-material-source.test-d.ts +30 -0
  271. package/src/__tests__/render-target-material-source.unit.test.ts +97 -0
  272. package/src/__tests__/render-target-owner-placement.unit.test.ts +203 -0
  273. package/src/__tests__/render-target-owner.unit.test.ts +122 -0
  274. package/src/__tests__/render-target-probe-soak.perf.test.ts +94 -0
  275. package/src/__tests__/render-target-public-schema.json +107 -0
  276. package/src/__tests__/render-target-public-schema.unit.test.ts +91 -0
  277. package/src/__tests__/render-target-public-surface.test-d.ts +83 -0
  278. package/src/__tests__/render-target-readback.integration.test.ts +90 -0
  279. package/src/__tests__/render-target-recovery.integration.test.ts +85 -0
  280. package/src/__tests__/renderer-factory-material-contract.unit.test.ts +76 -0
  281. package/src/__tests__/renderer-frame-transaction.integration.test.ts +1 -1
  282. package/src/__tests__/renderer-lifecycle.integration.test.ts +14 -0
  283. package/src/__tests__/shader-stage-surface.unit.test.ts +19 -4
  284. package/src/__tests__/skin-motion-regression.unit.test.ts +132 -0
  285. package/src/__tests__/skinned-shadow-caster.test.ts +32 -2
  286. package/src/__tests__/standard-cluster-capability.integration.test.ts +63 -0
  287. package/src/__tests__/standard-cluster-transport.unit.test.ts +121 -0
  288. package/src/__tests__/standard-cluster-variant-resolution.unit.test.ts +232 -0
  289. package/src/__tests__/standard-clustered-pipeline.unit.test.ts +8 -5
  290. package/src/__tests__/standard-lighting-inspection.integration.test.ts +138 -0
  291. package/src/__tests__/standard-lighting-ssot.unit.test.ts +18 -0
  292. package/src/__tests__/standard-lighting-write.unit.test.ts +377 -0
  293. package/src/__tests__/standard-lighting.integration.test.ts +67 -0
  294. package/src/__tests__/standard-pipeline.dawn.test.ts +206 -5
  295. package/src/__tests__/standard-pipeline.integration.test.ts +181 -150
  296. package/src/__tests__/standard-probe-binding.unit.test.ts +25 -0
  297. package/src/__tests__/standard-profile-oracle.unit.test.ts +23 -36
  298. package/src/__tests__/typed-pipeline-topology.unit.test.ts +395 -14
  299. package/src/__tests__/urp-pipeline-targets.unit.test.ts +2 -2
  300. package/src/__tests__/visibility-resolver.unit.test.ts +15 -0
  301. package/src/__tests__/volume-optics-oracle.unit.test.ts +85 -0
  302. package/src/__tests__/volumetric-fog-budget-recovery.integration.test.ts +655 -0
  303. package/src/__tests__/volumetric-fog-component.unit.test.ts +71 -0
  304. package/src/__tests__/volumetric-fog-composite-stage-readback.dawn.test.ts +376 -0
  305. package/src/__tests__/volumetric-fog-errors.unit.test.ts +51 -0
  306. package/src/__tests__/volumetric-fog-inspection.unit.test.ts +77 -0
  307. package/src/__tests__/volumetric-fog-light-capability.unit.test.ts +19 -0
  308. package/src/__tests__/volumetric-fog-light-consumers.integration.test.ts +18 -0
  309. package/src/__tests__/volumetric-fog-light-errors.unit.test.ts +17 -0
  310. package/src/__tests__/volumetric-fog-light-topology.unit.test.ts +21 -0
  311. package/src/__tests__/volumetric-fog-light-transaction.integration.test.ts +53 -0
  312. package/src/__tests__/volumetric-fog-m9-watcher.integration.test.ts +27 -0
  313. package/src/__tests__/volumetric-fog-point-light-owner.integration.test.ts +44 -0
  314. package/src/__tests__/volumetric-fog-point-spot-accumulation.integration.test.ts +49 -0
  315. package/src/__tests__/volumetric-fog-point-spot-contract.unit.test.ts +28 -0
  316. package/src/__tests__/volumetric-fog-point-spot-lkg.integration.test.ts +65 -0
  317. package/src/__tests__/volumetric-fog-point-spot-selection.integration.test.ts +49 -0
  318. package/src/__tests__/volumetric-fog-point-spot-temporal.unit.test.ts +55 -0
  319. package/src/__tests__/volumetric-fog-projector-contract.unit.test.ts +22 -0
  320. package/src/__tests__/volumetric-fog-projector-inspection.unit.test.ts +12 -0
  321. package/src/__tests__/volumetric-fog-projector-surface-volume.integration.test.ts +11 -0
  322. package/src/__tests__/volumetric-fog-projector-transaction.integration.test.ts +26 -0
  323. package/src/__tests__/volumetric-fog-recovery.integration.test.ts +47 -0
  324. package/src/__tests__/volumetric-fog-selected-light-resolution.integration.test.ts +63 -0
  325. package/src/__tests__/volumetric-fog-spot-closure.integration.test.ts +26 -0
  326. package/src/__tests__/volumetric-fog-spot-contract.test-d.ts +21 -0
  327. package/src/__tests__/volumetric-fog-spot-contract.unit.test.ts +27 -0
  328. package/src/__tests__/volumetric-fog-spot-frame-optics.integration.test.ts +14 -0
  329. package/src/__tests__/volumetric-fog-spot-optics.integration.test.ts +29 -0
  330. package/src/__tests__/volumetric-fog-stage-readback.dawn.test.ts +550 -0
  331. package/src/__tests__/volumetric-fog-temporal-selected-light.unit.test.ts +33 -0
  332. package/src/__tests__/volumetric-fog-temporal.unit.test.ts +45 -0
  333. package/src/__tests__/volumetric-fog-topology.unit.test.ts +237 -0
  334. package/src/__tests__/volumetric-fog-transparent.integration.test.ts +27 -0
  335. package/src/assembly/device-feature-admission.ts +73 -0
  336. package/src/assembly/directional-shadow-inspection.ts +122 -0
  337. package/src/assembly/factory.ts +1093 -246
  338. package/src/assembly/host-contract.ts +25 -0
  339. package/src/assembly/render-target-host.ts +847 -0
  340. package/src/assets/asset-decoders.ts +1 -1
  341. package/src/assets/render-asset-port.ts +7 -1
  342. package/src/capture/cube-views.ts +69 -0
  343. package/src/capture/scheduler.ts +265 -0
  344. package/src/components/__tests__/schema-contract.unit.test.ts +12 -0
  345. package/src/components/__tests__/schema-parity.unit.test.ts +9 -0
  346. package/src/components/camera.ts +4 -0
  347. package/src/components/cube-camera.ts +52 -0
  348. package/src/components/directional-light.ts +22 -2
  349. package/src/components/directional-shadow-filter.ts +57 -0
  350. package/src/components/index.ts +2 -0
  351. package/src/components/light-helpers.ts +85 -7
  352. package/src/components/reflection-probe.ts +49 -0
  353. package/src/components/spot-light.ts +22 -3
  354. package/src/device/gpu-residency.ts +168 -58
  355. package/src/environment/frame.ts +6 -24
  356. package/src/environment/lifecycle.ts +12 -0
  357. package/src/errors/render.ts +405 -143
  358. package/src/extract/directional-shadow-projection.ts +61 -0
  359. package/src/extract/environment.ts +57 -0
  360. package/src/extract/visibility.ts +25 -1
  361. package/src/features/fullscreen.ts +3 -0
  362. package/src/features/targets.ts +4 -1
  363. package/src/features/types.ts +10 -0
  364. package/src/fullscreen-post-process-pass.ts +43 -2
  365. package/src/gpu-driven/batch-topology.ts +1 -0
  366. package/src/gpu-driven/production-raster.ts +1 -3
  367. package/src/gpu-scene.ts +8 -1
  368. package/src/gpu-usage.ts +2 -0
  369. package/src/hdrp-buffers.ts +165 -59
  370. package/src/ibl/IblPipelineCache.ts +11 -0
  371. package/src/ibl/kernel-cache.ts +88 -0
  372. package/src/index.ts +186 -1
  373. package/src/inspection-types.ts +56 -0
  374. package/src/instances-derived-bounds.ts +171 -0
  375. package/src/light-buffer-layout.ts +74 -26
  376. package/src/mesh-material-bindings.ts +132 -0
  377. package/src/pbr-pipeline.ts +139 -27
  378. package/src/pipeline/standard-forward-lane.ts +65 -15
  379. package/src/pipeline/standard-lighting/errors.ts +6 -0
  380. package/src/pipeline/standard-lighting/graph.ts +157 -0
  381. package/src/pipeline/standard-lighting/inspection.ts +88 -0
  382. package/src/pipeline/standard-lighting/layout.ts +31 -0
  383. package/src/pipeline/standard-lighting/light-frame.ts +34 -0
  384. package/src/pipeline/standard-lighting/membership.ts +43 -0
  385. package/src/pipeline/standard-lighting/prepare.ts +37 -0
  386. package/src/pipeline/standard-lighting/topology.ts +120 -0
  387. package/src/pipeline/standard-lighting/transport.ts +77 -0
  388. package/src/pipeline/standard-pipeline.ts +141 -192
  389. package/src/pipeline/standard-post.ts +26 -7
  390. package/src/pipeline/standard-profile.ts +23 -30
  391. package/src/pipeline-spec.ts +84 -21
  392. package/src/point-shadow-inspection.ts +55 -0
  393. package/src/record/__tests__/temporal-payload.unit.test.ts +42 -1
  394. package/src/record/__tests__/transparent-group2-selection.unit.test.ts +73 -0
  395. package/src/record/__tests__/view-ubo-layout.unit.test.ts +40 -0
  396. package/src/record/frame-lighting.ts +470 -516
  397. package/src/record/frame-snapshot.ts +76 -28
  398. package/src/record/frame-targets.ts +23 -2
  399. package/src/record/frame.ts +1169 -79
  400. package/src/record/gpu-pass-timing/contract.ts +180 -0
  401. package/src/record/gpu-pass-timing/errors.ts +34 -0
  402. package/src/record/gpu-pass-timing/index.ts +37 -0
  403. package/src/record/gpu-pass-timing/parser.ts +97 -0
  404. package/src/record/gpu-pass-timing/session.ts +938 -0
  405. package/src/record/gpu-timing.ts +233 -0
  406. package/src/record/main-pass-geometry.ts +120 -80
  407. package/src/record/main-pass-material.ts +101 -11
  408. package/src/record/main-pass-sprite-draws.ts +54 -25
  409. package/src/record/main-pass.ts +71 -15
  410. package/src/record/render-context.ts +77 -0
  411. package/src/record/shadow-pass.ts +104 -66
  412. package/src/record/skybox-post-pass.ts +20 -4
  413. package/src/record/typed-frame-graph.ts +1016 -32
  414. package/src/record/view-ubo.ts +63 -28
  415. package/src/reflection/filter.ts +81 -0
  416. package/src/reflection/gpu-table.ts +44 -0
  417. package/src/reflection/projection.ts +281 -0
  418. package/src/render-contract.ts +147 -4
  419. package/src/render-data.ts +50 -22
  420. package/src/render-graph-primitives.ts +9 -4
  421. package/src/render-pipeline.ts +161 -2
  422. package/src/render-system-extract.ts +886 -103
  423. package/src/render-system.ts +1174 -66
  424. package/src/renderer-inspect.ts +66 -0
  425. package/src/renderer.ts +222 -0
  426. package/src/scene/render-scene.ts +117 -9
  427. package/src/shadow-atlas.ts +5 -5
  428. package/src/ssao-buffers.ts +9 -2
  429. package/src/targets/contracts.ts +182 -0
  430. package/src/targets/graph-projection.ts +169 -0
  431. package/src/targets/material-source.ts +143 -0
  432. package/src/targets/owner.ts +214 -0
  433. package/src/targets/physical.ts +18 -0
  434. package/src/targets/readback.ts +153 -0
  435. package/src/temporal/frame.ts +128 -0
  436. package/src/transmission/__tests__/standard-transmission.dawn.test.ts +61 -23
  437. package/src/typed-render-graph-primitives.ts +34 -2
  438. package/src/typed-shadow-atlas.ts +17 -0
  439. package/src/typed-shadow-passes.ts +47 -40
  440. package/src/volume/capability.ts +173 -0
  441. package/src/volume/component.ts +110 -0
  442. package/src/volume/extract.ts +21 -0
  443. package/src/volume/inspection.ts +78 -0
  444. package/src/volume/passes.ts +686 -0
  445. package/src/volume/recovery.ts +86 -0
  446. package/src/volume/resources.ts +236 -0
  447. package/src/volume/temporal.ts +89 -0
  448. package/dist/chunk-IPXCABEP.mjs.map +0 -1
  449. package/dist/chunk-LOSO4CTV.mjs.map +0 -1
  450. package/dist/chunk-RJRUS55L.mjs.map +0 -1
  451. package/dist/chunk-YTQ5C7YQ.mjs +0 -584
  452. package/dist/chunk-YTQ5C7YQ.mjs.map +0 -1
@@ -11,6 +11,7 @@ import type {
11
11
  PipelineLayout,
12
12
  Result,
13
13
  RhiCanvasContext,
14
+ RhiCommandEncoder,
14
15
  RhiDevice,
15
16
  RenderPipeline as RhiRenderPipeline,
16
17
  Sampler,
@@ -41,10 +42,20 @@ import {
41
42
  import type { SkylightFallback } from '../ibl/skylight-bind-group';
42
43
  import type { BloomInspection } from '../inspection-types';
43
44
  import type { HealthListenerRegistry, RhiErrorListenerRegistry } from '../lifecycle';
45
+ import type { PipelineGroup2Contract } from '../pbr-pipeline';
46
+ import type { StandardTopologyInputValue } from '../pipeline/standard-lighting/topology';
44
47
  import type { StandardProfile } from '../pipeline/standard-profile';
45
48
  import type { PipelineBuilderShaderModuleFactory } from '../pipeline-builder';
46
49
  import type { PointsLinesInspection } from '../points-lines/inspection';
47
50
  import type { PointsLinesRecordPlan } from '../points-lines/record';
51
+ import type { ReflectionProbeTable } from '../reflection/gpu-table';
52
+ import type { ReflectionProbeSelectionResult } from '../reflection/projection';
53
+ import type { GpuPassTimingReason } from './gpu-pass-timing/errors';
54
+ import type {
55
+ GpuPassTimingCapture,
56
+ GpuPassTimingFrameIdentity,
57
+ GpuPassTimingSession,
58
+ } from './gpu-pass-timing/session';
48
59
 
49
60
  export interface PointsLinesRecordSubmission {
50
61
  readonly plan: PointsLinesRecordPlan;
@@ -53,10 +64,23 @@ export interface PointsLinesRecordSubmission {
53
64
  readonly layoutProjection: VertexLayoutProjection;
54
65
  }
55
66
 
67
+ export interface ReflectionProbeRecordState {
68
+ readonly table: ReflectionProbeTable;
69
+ readonly selections: ReadonlyMap<string, ReflectionProbeSelectionResult>;
70
+ readonly graph: import('./typed-frame-graph').ReflectionProbeGraphState;
71
+ readonly completeSubmission: (submitted: boolean, completed?: Promise<unknown>) => void;
72
+ }
73
+
74
+ export interface MaterialShaderPipelineEntry {
75
+ readonly pipeline: RhiRenderPipeline;
76
+ readonly group2Contract: PipelineGroup2Contract;
77
+ }
78
+
56
79
  import type {
57
80
  RenderDebugOverlay,
58
81
  RenderPipelineContext,
59
82
  RenderRecordPhase,
83
+ VolumetricFogShaderSources,
60
84
  } from '../render-contract';
61
85
  import type {
62
86
  DispatchEntry,
@@ -65,6 +89,8 @@ import type {
65
89
  SkylightSnapshot,
66
90
  } from '../render-system-extract';
67
91
  import type { SkinPaletteAllocator } from '../systems/skin-palette-allocator';
92
+ import type { RenderTarget } from '../targets/contracts';
93
+ import type { RenderTargetPhysical } from '../targets/physical';
68
94
  import type {
69
95
  BindGroupCounts,
70
96
  BloomFrameReceipts,
@@ -101,6 +127,23 @@ export interface RenderSystemRuntime {
101
127
  shaderModuleMode?: RenderFeatureShaderModuleMode,
102
128
  layoutKindOverride?: 'pbr' | 'pbr-skin',
103
129
  ) => RhiRenderPipeline | null;
130
+ readonly getMaterialShaderPipelineEntry?: (
131
+ materialShaderId: string,
132
+ isHdr: boolean,
133
+ renderState?: MaterialRenderState,
134
+ topology?: PrimitiveTopology,
135
+ indexFormat?: 'uint16' | 'uint32',
136
+ variantSet?: string,
137
+ passKind?: PassKind,
138
+ meshAttributes?: VertexAttributeMap,
139
+ sampleCount?: number,
140
+ colorFormatOverride?: GPUTextureFormat,
141
+ shaderUvSetCount?: number,
142
+ depthFormatOverride?: GPUTextureFormat | null,
143
+ vertexLayout?: string,
144
+ vertexLayoutProjection?: VertexLayoutProjection,
145
+ shaderModuleMode?: RenderFeatureShaderModuleMode,
146
+ ) => MaterialShaderPipelineEntry | null;
104
147
  readonly getMaterialShaderBindingContract?: (
105
148
  materialShaderId: string,
106
149
  ) => 'group-0' | 'group-0-resource' | 'view-only' | 'view-and-scene-depth' | 'render-material';
@@ -115,10 +158,15 @@ export interface RenderSystemRuntime {
115
158
  id: string,
116
159
  bgl: BindGroupLayout,
117
160
  colorFormat: GPUTextureFormat,
161
+ entry?: import('../fullscreen-post-process-pass').PostProcessShaderEntry,
118
162
  ) => RhiRenderPipeline | null;
119
163
  readonly clearPostProcessPipelineCache?: (id: string) => void;
120
164
  readonly invalidateShaderModule?: (label: string) => void;
121
165
  readonly dynamicTextureStore?: DynamicTextureStore | undefined;
166
+ /** Resolves a render-target source to the active generation-owned GPU view. */
167
+ readonly resolveRenderTargetTextureSource?: (
168
+ source: import('../targets/contracts').RenderTargetTextureSource,
169
+ ) => import('../targets/material-source').RenderTargetMaterialSourceBinding | undefined;
122
170
  }
123
171
 
124
172
  /** Renderer-owned bridge from retained Points/Lines facts into main geometry. */
@@ -230,12 +278,16 @@ export interface BloomPersistentBundle {
230
278
  }
231
279
 
232
280
  export interface PipelineState {
281
+ /** Device that owns every opaque handle in this pipeline state. */
282
+ readonly device: RhiDevice;
233
283
  readonly meshes: ReadonlyMap<number, MeshGpuHandles>;
234
284
  readonly format: TextureFormat;
235
285
  readonly colorAttachmentFormat: TextureFormat;
236
286
  /** Surface route committed by configureSurface for inspection provenance. */
237
287
  readonly surfaceProfile?: 'dual-view' | 'raw-only';
238
288
  readonly viewBindGroupLayout: BindGroupLayout;
289
+ /** Device capability gate for the optional SpotLight projector binding. */
290
+ readonly projectorAvailable?: boolean;
239
291
  readonly materialBindGroupLayout: BindGroupLayout;
240
292
  readonly meshBindGroupLayout: BindGroupLayout;
241
293
  readonly viewUniformBuffer: Buffer;
@@ -260,6 +312,8 @@ export interface PipelineState {
260
312
  readonly hdrpClusterMembershipBindGroupLayout: BindGroupLayout | null;
261
313
  readonly pbrSkinPipelineLayout: PipelineLayout | null;
262
314
  readonly pbrSkinMeshBindGroupLayout: BindGroupLayout | null;
315
+ readonly hdrpSkinPipelineLayout: PipelineLayout | null;
316
+ readonly hdrpSkinMeshBindGroupLayout: BindGroupLayout | null;
263
317
  readonly skinPaletteAllocator: SkinPaletteAllocator | null;
264
318
  readonly defaultWhiteTextureView: TextureView;
265
319
  readonly defaultNormalTextureView: TextureView;
@@ -277,6 +331,12 @@ export interface RenderSystemInternals extends RenderSystemRuntime {
277
331
  readonly standardPipeline: RenderFrameState['activePipeline'];
278
332
  readonly featureHost?: RenderFeatureHost | undefined;
279
333
  readonly shaderModuleFactory?: PipelineBuilderShaderModuleFactory;
334
+ readonly createShaderModule?: (
335
+ device: import('@forgeax/engine-rhi').RhiDevice,
336
+ descriptor: { readonly code: string; readonly label?: string },
337
+ ) => Promise<
338
+ Result<import('@forgeax/engine-rhi').ShaderModule, import('@forgeax/engine-rhi').RhiError>
339
+ >;
280
340
  /** Optional handle-first factory for feature-owned generated shader programs. */
281
341
  readonly immediateShaderModuleFactory?: PipelineBuilderShaderModuleFactory;
282
342
  readonly profiler?: Profiler | undefined;
@@ -302,6 +362,18 @@ export interface RenderSystemInternals extends RenderSystemRuntime {
302
362
  label: string,
303
363
  ) => RhiRenderPipeline | null)
304
364
  | undefined;
365
+ gpuPassTimingSession?: GpuPassTimingSession | undefined;
366
+ gpuPassTimingCapture?: GpuPassTimingCapture | undefined;
367
+ gpuPassTimingSubmittedWork?: Promise<void> | undefined;
368
+ gpuPassTimingFrameIdentity?: GpuPassTimingFrameIdentity | undefined;
369
+ gpuPassTimingBeginReason?: GpuPassTimingReason | undefined;
370
+ readonly getRenderTargetPhysical?: (target: RenderTarget) => RenderTargetPhysical | undefined;
371
+ readonly encodeRenderTargetReadbacks?: (
372
+ encoder: RhiCommandEncoder,
373
+ faces?: readonly number[],
374
+ ) => void;
375
+ /** Composed renderer utility sources installed atomically at build-ready. */
376
+ volumetricFogShaders?: VolumetricFogShaderSources | undefined;
305
377
  }
306
378
 
307
379
  export interface _StandardForwardSceneView {
@@ -313,6 +385,8 @@ export interface _StandardForwardSceneView {
313
385
  readonly validated: readonly ValidatedRenderable[];
314
386
  readonly validatedOrdered: readonly ValidatedRenderable[];
315
387
  readonly viewBindGroup: BindGroup | null;
388
+ /** Dynamic View-UBO slot used by auxiliary cube/probe face cameras. */
389
+ readonly viewBindGroupDynamicOffset?: number;
316
390
  readonly meshBindGroup: BindGroup | null;
317
391
  readonly frameState: RenderFrameState;
318
392
  readonly dispatchCounts: DispatchCounts;
@@ -335,6 +409,8 @@ export interface _StandardForwardSceneView {
335
409
  readonly dispatch: readonly DispatchEntry[];
336
410
  readonly hdrpClusterBindGroup: BindGroup | null;
337
411
  readonly hdrpClusterMembershipBindGroup: BindGroup | null;
412
+ /** Prepared Standard lighting declaration accepted by this graph frame. */
413
+ readonly standardLighting?: StandardTopologyInputValue;
338
414
  readonly foldDispatchPlan: FoldDispatchPlan | null;
339
415
  readonly materialSlotIndices: readonly (readonly number[])[];
340
416
  readonly materialSlots: readonly MaterialSnapshot[];
@@ -342,6 +418,7 @@ export interface _StandardForwardSceneView {
342
418
  readonly materialSlotCount: number;
343
419
  readonly pointsLines: PointsLinesRecordOwner | undefined;
344
420
  readonly materialBgAssemblyCache: Map<string, MaterialBgAssemblyCacheEntry>;
421
+ readonly reflectionProbes?: ReflectionProbeRecordState;
345
422
  materialUboPayloadCache?: {
346
423
  readonly materialSlots: readonly MaterialSnapshot[];
347
424
  readonly materialSlotCount: number;
@@ -7,7 +7,7 @@ import {
7
7
  type RhiQueue,
8
8
  type RhiRenderPassEncoder,
9
9
  } from '@forgeax/engine-rhi';
10
- import type { PassSelector } from '@forgeax/engine-types';
10
+ import type { MaterialRenderState, PassSelector } from '@forgeax/engine-types';
11
11
  import { GpuBuffer } from '../gpu-resource';
12
12
  import {
13
13
  GPU_BUFFER_USAGE_COPY_DST,
@@ -18,6 +18,8 @@ import { assembleMaterialWithSkylightEntries } from '../ibl/skylight-bind-group'
18
18
  import type { InstanceBufferCacheEntry } from '../instance-buffer-cache';
19
19
  import {
20
20
  buildPbrMaterialUserRegionEntries,
21
+ createPbrSkinMeshBindGroupEntries,
22
+ pbrSkinMeshDynamicOffsets,
21
23
  SHADOW_CASTER_SHADER_ID,
22
24
  shadowCasterVariantSet,
23
25
  } from '../pbr-pipeline';
@@ -81,6 +83,7 @@ function ensureTypedShadowViewBg(
81
83
  const { runtime, frameState, pipelineState } = c;
82
84
  const shadowSampler = pipelineState.perPassResources.shadowSampler;
83
85
  if (shadowSampler === null) return null;
86
+ const projectorAvailable = pipelineState.projectorAvailable !== false;
84
87
  try {
85
88
  return getOrCreateFromChain(
86
89
  frameState.viewBindGroupCache,
@@ -94,6 +97,9 @@ function ensureTypedShadowViewBg(
94
97
  pipelineState.shadowParamsBuffer,
95
98
  pipelineState.shadowCasterCascadeBuffer,
96
99
  pipelineState.shadowFallbackTextureView,
100
+ ...(projectorAvailable
101
+ ? [pipelineState.defaultWhiteTextureView, pipelineState.defaultSampler]
102
+ : []),
97
103
  pipelineState.pointsLinesViewBuffer ?? pipelineState.viewUniformBuffer,
98
104
  ],
99
105
  variant,
@@ -165,6 +171,21 @@ function ensureTypedShadowViewBg(
165
171
  },
166
172
  },
167
173
  },
174
+ ...(projectorAvailable
175
+ ? [
176
+ {
177
+ binding: 11,
178
+ resource: {
179
+ kind: 'textureView' as const,
180
+ value: pipelineState.defaultWhiteTextureView,
181
+ },
182
+ },
183
+ {
184
+ binding: 12,
185
+ resource: { kind: 'sampler' as const, value: pipelineState.defaultSampler },
186
+ },
187
+ ]
188
+ : []),
168
189
  ],
169
190
  });
170
191
  if (!created.ok) throw created.error;
@@ -181,11 +202,26 @@ function ensureTypedShadowViewBg(
181
202
  }
182
203
  }
183
204
 
184
- function shadowShaderMap(c: _InternalRenderPipelineContext): ReadonlyMap<number, string> {
185
- const shaders = new Map<number, string>();
205
+ interface ShadowDispatch {
206
+ readonly materialShaderId: string;
207
+ readonly renderState: MaterialRenderState | undefined;
208
+ }
209
+
210
+ type ShadowDispatchMap = ReadonlyMap<number, ReadonlyMap<number, ShadowDispatch>>;
211
+
212
+ function shadowShaderMap(c: _InternalRenderPipelineContext): ShadowDispatchMap {
213
+ const shaders = new Map<number, Map<number, ShadowDispatch>>();
186
214
  for (const entry of c.dispatch) {
187
215
  if (entry.tags.LightMode === 'ShadowCaster' && entry.materialShaderId !== undefined) {
188
- shaders.set(entry.renderableIndex, entry.materialShaderId);
216
+ let byMaterial = shaders.get(entry.renderableIndex);
217
+ if (byMaterial === undefined) {
218
+ byMaterial = new Map<number, ShadowDispatch>();
219
+ shaders.set(entry.renderableIndex, byMaterial);
220
+ }
221
+ byMaterial.set(entry.materialHandle, {
222
+ materialShaderId: entry.materialShaderId,
223
+ renderState: entry.renderState,
224
+ });
189
225
  }
190
226
  }
191
227
  return shaders;
@@ -256,27 +292,12 @@ function skinnedShadowMeshBindGroup(
256
292
  const created = c.runtime.device.createBindGroup({
257
293
  label: 'shadow-pbr-skin-mesh-bg',
258
294
  layout,
259
- entries: [
260
- {
261
- binding: 0,
262
- resource: {
263
- kind: 'buffer',
264
- value: {
265
- buffer: c.pipelineState.meshStorageBuffer.buffer,
266
- size: c.runtime.device.caps.storageBuffer
267
- ? MESH_SSBO_BYTES
268
- : MESH_UBO_FULL_ARRAY_BYTES,
269
- },
270
- },
271
- },
272
- {
273
- binding: 1,
274
- resource: {
275
- kind: 'buffer',
276
- value: { buffer: skin.buffer, size: allocator.bindingWindowBytes },
277
- },
278
- },
279
- ],
295
+ entries: createPbrSkinMeshBindGroupEntries(
296
+ c.pipelineState.meshStorageBuffer.buffer,
297
+ c.runtime.device.caps.storageBuffer ? MESH_SSBO_BYTES : MESH_UBO_FULL_ARRAY_BYTES,
298
+ skin.buffer,
299
+ allocator.bindingWindowBytes,
300
+ ),
280
301
  });
281
302
  if (!created.ok) throw created.error;
282
303
  return created.value;
@@ -304,7 +325,7 @@ export function encodeDirectionalShadowPass(
304
325
  c.frameState.directionalShadowCacheRecorded = true;
305
326
  pass.setViewport(viewport.x, viewport.y, viewport.w, viewport.h, 0, 1);
306
327
  pass.setPipeline(pipeline);
307
- pass.setBindGroup(0, viewBg, [0]);
328
+ pass.setBindGroup(0, viewBg, [0, 0]);
308
329
  pass.setBindGroup(1, materialBg, [0]);
309
330
  recordShadowCasterDraws(
310
331
  c,
@@ -334,7 +355,7 @@ export function encodePointShadowPass(
334
355
  const materialBg = ensureSpotShadowMaterialBg(c);
335
356
  if (pipeline === null || viewBg === null || materialBg === null) return;
336
357
  pass.setPipeline(pipeline);
337
- pass.setBindGroup(0, viewBg, [0]);
358
+ pass.setBindGroup(0, viewBg, [0, 0]);
338
359
  pass.setBindGroup(1, materialBg, [0]);
339
360
  recordShadowCasterDraws(
340
361
  c,
@@ -382,7 +403,7 @@ export function encodeSpotShadowPass(
382
403
  1,
383
404
  );
384
405
  pass.setPipeline(pipeline);
385
- pass.setBindGroup(0, viewBg, [0]);
406
+ pass.setBindGroup(0, viewBg, [0, 0]);
386
407
  pass.setBindGroup(1, materialBg, [0]);
387
408
  // Reuse the shared caster recorder. The compact spot-only loop used to
388
409
  // depend on instance bindings created by a directional pass, so a scene
@@ -488,8 +509,8 @@ export function buildMatchedMaterialHandlesByRenderable(
488
509
  * groups (@group 0/1) are already set by the caller; this loop owns @group
489
510
  * 2/3 + the vertex/index/pipeline de-dup state. Receives the explicit
490
511
  * `_InternalRenderPipelineContext` (`c`) plus the caller-resolved shadow
491
- * pipeline, mesh bind group, pass-selector match set, and per-renderable
492
- * custom-caster shader map so no cross-function mutable state is introduced.
512
+ * pipeline, mesh bind group, pass-selector match set, and per-material
513
+ * ShadowCaster dispatch map so no cross-function mutable state is introduced.
493
514
  */
494
515
  function recordShadowCasterDraws(
495
516
  c: _InternalRenderPipelineContext,
@@ -497,7 +518,7 @@ function recordShadowCasterDraws(
497
518
  shadowPipeline: RenderPipeline,
498
519
  shadowMeshBindGroup: BindGroup,
499
520
  matchedIndices: Set<number> | null,
500
- shadowShaderByRenderableIdx: ReadonlyMap<number, string>,
521
+ shadowDispatchByRenderableIdx: ShadowDispatchMap,
501
522
  ): void {
502
523
  const { runtime, pipelineState, validatedOrdered } = c;
503
524
  // M-3 / w12: vertexBuffer/indexBuffer state locals migrate to GpuBuffer
@@ -520,41 +541,14 @@ function recordShadowCasterDraws(
520
541
  // feat-20260609 M2: skip entities that don't match the pass selector.
521
542
  if (matchedIndices !== null && !matchedIndices.has(entry.renderableIndex)) continue;
522
543
 
523
- // bug-20260619-csm RC-3 (AC-10, D-3): resolve the per-entity shadow
524
- // PSO from its ShadowCaster shader id. Default casters keep the
525
- // vertex-only `forgeax::default-shadow-caster` PSO bound above; a
526
- // material with a custom ShadowCaster shader (cutout alpha-test) gets
527
- // its own fragment-carrying PSO so `discard` runs in the depth pass.
528
- const entryShadowShaderId = shadowShaderByRenderableIdx.get(entry.renderableIndex);
529
- let entryShadowPipeline = shadowPipeline;
530
544
  if (entry.source.skin !== undefined) {
531
545
  const skinPipeline = skinnedShadowPipeline(c, entry);
532
546
  if (skinPipeline === null) continue;
533
- entryShadowPipeline = skinPipeline;
534
- } else if (
535
- entryShadowShaderId !== undefined &&
536
- entryShadowShaderId !== SHADOW_CASTER_SHADER_ID
537
- ) {
538
- // Custom ShadowCaster PSO; same cache path as the default above
539
- // (passKind 'shadow-caster'). On a cache miss (async build in
540
- // flight / build failure) fall back to the default PSO so the
541
- // caster still writes depth rather than dropping its draw.
542
- entryShadowPipeline =
543
- runtime.getMaterialShaderPipeline?.(
544
- entryShadowShaderId,
545
- false, // isHdr — shadow depth pass is always LDR
546
- undefined, // renderState
547
- 'triangle-list', // topology — shadow PSO targets triangle-list
548
- undefined, // indexFormat
549
- undefined, // variantSet — shadow caster has no variant axes
550
- 'shadow-caster', // passKind
551
- ) ?? shadowPipeline;
552
- }
553
- if (entryShadowPipeline !== shadowLastPipeline && entryShadowPipeline !== null) {
554
- shadowPass.setPipeline(entryShadowPipeline);
555
- shadowLastPipeline = entryShadowPipeline;
547
+ if (skinPipeline !== shadowLastPipeline) {
548
+ shadowPass.setPipeline(skinPipeline);
549
+ shadowLastPipeline = skinPipeline;
550
+ }
556
551
  }
557
-
558
552
  // feat-20260604-mesh-topology-debug-draw M5 / w14 (AC-09, D-A6): the
559
553
  // shadow caster PSO is triangle-list; it only projects triangle faces.
560
554
  // line-list / line-strip / point-list meshes have no surface to cast a
@@ -587,10 +581,11 @@ function recordShadowCasterDraws(
587
581
  if (entry.source.skin !== undefined) {
588
582
  const skinMeshBindGroup = skinnedShadowMeshBindGroup(c, entry);
589
583
  if (skinMeshBindGroup === null) continue;
590
- shadowPass.setBindGroup(2, skinMeshBindGroup, [
591
- i * MESH_PER_ENTITY_STRIDE,
592
- entry.source.skin.byteOffset,
593
- ]);
584
+ shadowPass.setBindGroup(
585
+ 2,
586
+ skinMeshBindGroup,
587
+ pbrSkinMeshDynamicOffsets(i * MESH_PER_ENTITY_STRIDE, entry.source.skin.byteOffset),
588
+ );
594
589
  } else {
595
590
  shadowPass.setBindGroup(2, shadowMeshBindGroup, [i * MESH_PER_ENTITY_STRIDE]);
596
591
  }
@@ -599,6 +594,7 @@ function recordShadowCasterDraws(
599
594
  let shadowInstanceBuffer: Buffer = pipelineState.identityInstanceBuffer;
600
595
  let shadowInstanceCount = 1;
601
596
  const shadowInst = entry.source.instances;
597
+ if (shadowInst?.instanceCount === 0) continue;
602
598
  if (shadowInst !== undefined) {
603
599
  const uniformFallback = runtime.device.caps.storageBuffer === false;
604
600
  // Over-cap uniform fallback can't fit the per-instance window — bind
@@ -708,6 +704,48 @@ function recordShadowCasterDraws(
708
704
  if (sm.topology !== 'triangle-list' && sm.topology !== 'triangle-strip') {
709
705
  continue;
710
706
  }
707
+
708
+ // Resolve the ShadowCaster PSO for the material bound to this submesh.
709
+ // Built-in materials normally use the shared vertex-only caster, but an
710
+ // authored `cullMode:'none'`/`frontFace` must still reach that PSO so
711
+ // two-sided casters (such as the Three.js teapot) populate the atlas
712
+ // from both faces. Custom ShadowCaster shaders retain their own path.
713
+ const submeshMaterial = entry.source.materials[sm.materialSlot] ?? entry.source.material;
714
+ const shadowDispatch = shadowDispatchByRenderableIdx
715
+ .get(entry.renderableIndex)
716
+ ?.get(submeshMaterial.materialHandle ?? 0);
717
+ const entryShadowShaderId = shadowDispatch?.materialShaderId;
718
+ const entryShadowRenderState = shadowDispatch?.renderState;
719
+ // A skinned caster's pipeline was selected above together with its
720
+ // two-binding mesh/palette group. Keep that pairing for every submesh;
721
+ // resetting to the static shadow pipeline here would bind the skin
722
+ // group against `pbr-pl` and Dawn rejects the draw at submit time.
723
+ let entryShadowPipeline =
724
+ entry.source.skin !== undefined ? shadowLastPipeline : shadowPipeline;
725
+ if (
726
+ entry.source.skin === undefined &&
727
+ entryShadowShaderId !== undefined &&
728
+ (entryShadowShaderId !== 'forgeax::default-shadow-caster' ||
729
+ entryShadowRenderState !== undefined)
730
+ ) {
731
+ // On a cache miss (async build in flight / build failure), fall back
732
+ // to the default PSO so the caster still writes depth rather than
733
+ // dropping its draw.
734
+ entryShadowPipeline =
735
+ runtime.getMaterialShaderPipeline?.(
736
+ entryShadowShaderId,
737
+ false, // isHdr — shadow depth pass is always LDR
738
+ entryShadowRenderState,
739
+ 'triangle-list', // topology — shadow PSO targets triangle-list
740
+ undefined, // indexFormat
741
+ undefined, // variantSet — shadow caster has no variant axes
742
+ 'shadow-caster', // passKind
743
+ ) ?? shadowPipeline;
744
+ }
745
+ if (entryShadowPipeline !== shadowLastPipeline && entryShadowPipeline !== null) {
746
+ shadowPass.setPipeline(entryShadowPipeline);
747
+ shadowLastPipeline = entryShadowPipeline;
748
+ }
711
749
  if (entry.mesh.indexed) {
712
750
  shadowPass.drawIndexed(sm.indexCount, shadowInstanceCount, sm.indexOffset, 0, 0);
713
751
  } else {
@@ -2,6 +2,8 @@ import type { ResolveContext } from '@forgeax/engine-render-graph';
2
2
  import { RhiError, type RhiRenderPassEncoder, type TextureView } from '@forgeax/engine-rhi';
3
3
  import { toShared } from '@forgeax/engine-types';
4
4
  import { buildBeginRenderPassDescriptor } from '../pipeline-spec';
5
+ import { FXAA_POST_PROCESS_ID } from '../render-contract';
6
+ import { resolveOutputDither } from '../render-pipeline';
5
7
  import type { BloomFrameReceipts } from './frame-snapshot';
6
8
  import { getOrCreateFromChain } from './mesh-ssbo';
7
9
  import type { _InternalRenderPipelineContext } from './render-context';
@@ -579,19 +581,29 @@ export function recordFxaaPass(
579
581
  fxaaActive &&
580
582
  pipelineState.perPassResources.fxaaPipeline !== null &&
581
583
  pipelineState.perPassResources.fxaaBindGroupLayout !== null &&
582
- pipelineState.perPassResources.fxaaSampler !== null
584
+ pipelineState.perPassResources.fxaaSampler !== null &&
585
+ runtime.getPostProcessParamsBuffer !== undefined
583
586
  ) {
584
587
  const inputView = resolve.resolve('ldrColor') as TextureView | undefined;
585
588
  if (inputView === undefined) return;
586
589
 
587
- // Compose the 2-entry FXAA BindGroup (input texture + sampler). The
590
+ const fxaaParams = runtime.getPostProcessParamsBuffer(FXAA_POST_PROCESS_ID);
591
+ if (fxaaParams === undefined) return;
592
+ const params = new Float32Array(4);
593
+ params[0] = resolveOutputDither(c.frameState.installedPipelineConfig) ? 1 : 0;
594
+ const paramsWrite = runtime.device.queue.writeBuffer(fxaaParams, 0, params);
595
+ if (!paramsWrite.ok) throw paramsWrite.error;
596
+
597
+ // Compose the 3-entry FXAA BindGroup (input texture + sampler + params).
588
598
  // graph view identity changes when the graph reallocates on resize, so
589
- // the identity-keyed cache rebuilds against the live target.
599
+ // the identity-keyed cache rebuilds against the live target. The params
600
+ // buffer is also a key so a device recovery cannot retain a bind group
601
+ // pointing at the retired resource.
590
602
  const fxaaBglLayout = pipelineState.perPassResources.fxaaBindGroupLayout;
591
603
  const fxaaSampler = pipelineState.perPassResources.fxaaSampler;
592
604
  const fxaaBg = getOrCreateFromChain(
593
605
  c.frameState.postProcessBgCache,
594
- [inputView],
606
+ [inputView, fxaaParams],
595
607
  'fxaa',
596
608
  () => {
597
609
  const fxaaBgRes = runtime.device.createBindGroup({
@@ -609,6 +621,10 @@ export function recordFxaaPass(
609
621
  binding: 1,
610
622
  resource: { kind: 'sampler', value: fxaaSampler },
611
623
  },
624
+ {
625
+ binding: 2,
626
+ resource: { kind: 'buffer', value: { buffer: fxaaParams } },
627
+ },
612
628
  ],
613
629
  });
614
630
  if (!fxaaBgRes.ok) throw fxaaBgRes.error;