@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
@@ -48,6 +48,7 @@ import {
48
48
  GPU_BUFFER_USAGE_UNIFORM,
49
49
  } from './gpu-usage';
50
50
  import { BYTES_PER_LIGHT_SLOT } from './light-buffer-layout';
51
+ import { createPbrSkinMeshBindGroupEntries } from './pbr-pipeline';
51
52
  import {
52
53
  CLUSTER_GRID_STRIDE_U32,
53
54
  DEFAULT_CLUSTER_GRID,
@@ -55,20 +56,12 @@ import {
55
56
  MAX_LIGHTS,
56
57
  } from './pipeline/standard-profile';
57
58
  import { createHdrpBindGroupLayoutDescriptor } from './pipeline-spec';
58
- import { MESH_PER_ENTITY_STRIDE, MESH_UBO_FULL_ARRAY_BYTES } from './record/mesh-ssbo';
59
+ import { MESH_PER_ENTITY_STRIDE } from './record/mesh-ssbo';
59
60
  import type { RenderSystemRuntime } from './record/render-context';
60
61
  import { getOrCreateSsaoFallbackTexture } from './ssao-buffers';
61
62
 
62
63
  export { getOrCreateSsaoFallbackTexture } from './ssao-buffers';
63
64
 
64
- /**
65
- * WebGL2 HDRP downlevel light-list capacity. 128 x 64 B = 8 KiB, below the
66
- * WebGL2 minimum uniform-buffer binding size of 16 KiB. The storage path
67
- * keeps the full MAX_LIGHTS budget; the uniform path uses the same LightSlot
68
- * POD and only changes the transport.
69
- */
70
- export const HDRP_UNIFORM_LIGHT_CAPACITY = 128;
71
-
72
65
  /** Bind-group layout used only by the WebGPU cluster membership producer. */
73
66
  export function createHdrpClusterMembershipBindGroupLayoutDescriptor(): BindGroupLayoutDescriptor {
74
67
  return {
@@ -111,9 +104,9 @@ export function createHdrpClusterMembershipBindGroupLayoutDescriptor(): BindGrou
111
104
  * cluster 4 buffer).
112
105
  */
113
106
  export interface HdrpBuffers {
114
- /** Whether bindings 3..5 carry storage buffers or uniform-buffer fallback data. */
115
- readonly storageBuffer: boolean;
116
- /** light_data -- 256 x 64 B on storage, 128 x 64 B on uniform fallback. */
107
+ /** Device identity that owns every handle in this bundle. */
108
+ readonly device: RenderSystemRuntime['device'];
109
+ /** light_data -- the full 256 x 64 B Standard light budget. */
117
110
  readonly lightDataBuffer: Buffer;
118
111
  readonly lightDataBytes: number;
119
112
  /** cluster_grid SSBO -- gridX*gridY*gridZ * 2 u32, BGL slot 4. */
@@ -145,66 +138,92 @@ const cache = new WeakMap<RenderSystemRuntime, HdrpBuffers>();
145
138
  * pipeline disable (charter P3 explicit failure).
146
139
  *
147
140
  * `grid` defaults to `DEFAULT_CLUSTER_GRID` when undefined (matches the M5
148
- * record-stage default). The buffers are sized at the *first* call's grid; a
149
- * later install with a different grid keeps the existing allocation as long as
150
- * it has enough capacity (gridX*gridY*gridZ <= cached.grid product). Different
151
- * grids that exceed capacity are not currently re-allocated -- M-future.
141
+ * record-stage default). A smaller grid reuses the existing capacity. When a
142
+ * later install requests a larger grid, this owner allocates a complete new
143
+ * bundle, publishes it atomically, and retires the previous bundle after the
144
+ * device queue fence so graph and bind-group caches never observe a partially
145
+ * replaced resource set.
152
146
  */
153
147
  export function getOrCreateHdrpBuffers(
154
148
  runtime: RenderSystemRuntime,
155
149
  grid: { x: number; y: number; z: number } = DEFAULT_CLUSTER_GRID,
156
150
  ): HdrpBuffers | null {
151
+ // Cluster has one code-level transport. Capability failure is handled by
152
+ // Standard transport admission; this owner never creates a second UBO ABI.
153
+ if (runtime.device.caps?.storageBuffer !== true) return null;
154
+ // Contract tests and reduced host adapters may advertise storage buffers
155
+ // without implementing the resource-creation surface. Treat that as a
156
+ // capability miss rather than dereferencing an absent method; callers
157
+ // already route `null` through the structured cluster-transport fallback.
158
+ const deviceSurface = runtime.device as unknown as {
159
+ readonly createBuffer?: unknown;
160
+ readonly createBindGroupLayout?: unknown;
161
+ readonly destroyBuffer?: unknown;
162
+ };
163
+ if (
164
+ typeof deviceSurface.createBuffer !== 'function' ||
165
+ typeof deviceSurface.createBindGroupLayout !== 'function' ||
166
+ typeof deviceSurface.destroyBuffer !== 'function'
167
+ ) {
168
+ return null;
169
+ }
157
170
  const cached = cache.get(runtime);
158
- if (cached !== undefined) return cached;
159
-
171
+ if (cached !== undefined && cached.device === runtime.device) {
172
+ const requestedCells = grid.x * grid.y * grid.z;
173
+ const cachedCells = cached.grid.x * cached.grid.y * cached.grid.z;
174
+ if (requestedCells <= cachedCells) return cached;
175
+ }
160
176
  const device = runtime.device;
161
- const storageBuffer = runtime.device.caps?.storageBuffer === true;
162
177
  const clusterUniformBytes = 32;
163
- const lightDataBytes =
164
- (storageBuffer ? MAX_LIGHTS : HDRP_UNIFORM_LIGHT_CAPACITY) * BYTES_PER_LIGHT_SLOT;
178
+ const lightDataBytes = MAX_LIGHTS * BYTES_PER_LIGHT_SLOT;
165
179
  const clusterCells = grid.x * grid.y * grid.z;
166
- const clusterGridBytes = storageBuffer
167
- ? clusterCells * CLUSTER_GRID_STRIDE_U32 * 4
168
- : clusterUniformBytes;
169
- const lightIndexListBytes = storageBuffer ? LIGHT_INDEX_LIST_CAPACITY * 4 : clusterUniformBytes;
180
+ const clusterGridBytes = clusterCells * CLUSTER_GRID_STRIDE_U32 * 4;
181
+ const lightIndexListBytes = LIGHT_INDEX_LIST_CAPACITY * 4;
170
182
  const lightBoundsBytes = MAX_LIGHTS * 6 * 4;
183
+ const created: Buffer[] = [];
184
+ const releaseCreated = (): void => {
185
+ for (const buffer of created) {
186
+ const result = device.destroyBuffer(buffer);
187
+ if (!result.ok) runtime.errorRegistry.fire(result.error);
188
+ }
189
+ created.length = 0;
190
+ };
191
+ const failAllocation = (error: RhiError): null => {
192
+ runtime.errorRegistry.fire(error);
193
+ releaseCreated();
194
+ return null;
195
+ };
171
196
 
172
197
  const lightData = device.createBuffer({
173
198
  label: 'hdrp-light-data',
174
199
  size: lightDataBytes,
175
- usage:
176
- (storageBuffer ? GPU_BUFFER_USAGE_STORAGE : GPU_BUFFER_USAGE_UNIFORM) |
177
- GPU_BUFFER_USAGE_COPY_DST,
200
+ usage: GPU_BUFFER_USAGE_STORAGE | GPU_BUFFER_USAGE_COPY_DST,
178
201
  mappedAtCreation: false,
179
202
  });
180
203
  if (!lightData.ok) {
181
- runtime.errorRegistry.fire(lightData.error);
182
- return null;
204
+ return failAllocation(lightData.error);
183
205
  }
206
+ created.push(lightData.value);
184
207
  const clusterGrid = device.createBuffer({
185
208
  label: 'hdrp-cluster-grid',
186
209
  size: clusterGridBytes,
187
- usage:
188
- (storageBuffer ? GPU_BUFFER_USAGE_STORAGE : GPU_BUFFER_USAGE_UNIFORM) |
189
- GPU_BUFFER_USAGE_COPY_DST,
210
+ usage: GPU_BUFFER_USAGE_STORAGE | GPU_BUFFER_USAGE_COPY_DST,
190
211
  mappedAtCreation: false,
191
212
  });
192
213
  if (!clusterGrid.ok) {
193
- runtime.errorRegistry.fire(clusterGrid.error);
194
- return null;
214
+ return failAllocation(clusterGrid.error);
195
215
  }
216
+ created.push(clusterGrid.value);
196
217
  const lightIndexList = device.createBuffer({
197
218
  label: 'hdrp-light-index-list',
198
219
  size: lightIndexListBytes,
199
- usage:
200
- (storageBuffer ? GPU_BUFFER_USAGE_STORAGE : GPU_BUFFER_USAGE_UNIFORM) |
201
- GPU_BUFFER_USAGE_COPY_DST,
220
+ usage: GPU_BUFFER_USAGE_STORAGE | GPU_BUFFER_USAGE_COPY_DST,
202
221
  mappedAtCreation: false,
203
222
  });
204
223
  if (!lightIndexList.ok) {
205
- runtime.errorRegistry.fire(lightIndexList.error);
206
- return null;
224
+ return failAllocation(lightIndexList.error);
207
225
  }
226
+ created.push(lightIndexList.value);
208
227
  const clusterUniform = device.createBuffer({
209
228
  label: 'hdrp-cluster-uniform',
210
229
  size: clusterUniformBytes,
@@ -212,36 +231,30 @@ export function getOrCreateHdrpBuffers(
212
231
  mappedAtCreation: false,
213
232
  });
214
233
  if (!clusterUniform.ok) {
215
- runtime.errorRegistry.fire(clusterUniform.error);
216
- return null;
234
+ return failAllocation(clusterUniform.error);
217
235
  }
236
+ created.push(clusterUniform.value);
218
237
  const lightBounds = device.createBuffer({
219
238
  label: 'hdrp-light-bounds',
220
239
  size: lightBoundsBytes,
221
- usage:
222
- (storageBuffer ? GPU_BUFFER_USAGE_STORAGE : GPU_BUFFER_USAGE_UNIFORM) |
223
- GPU_BUFFER_USAGE_COPY_DST,
240
+ usage: GPU_BUFFER_USAGE_STORAGE | GPU_BUFFER_USAGE_COPY_DST,
224
241
  mappedAtCreation: false,
225
242
  });
226
243
  if (!lightBounds.ok) {
227
- runtime.errorRegistry.fire(lightBounds.error);
228
- return null;
244
+ return failAllocation(lightBounds.error);
229
245
  }
246
+ created.push(lightBounds.value);
230
247
 
231
248
  // Create the unified 7-entry BGL layout for group(2)
232
249
  // (plan D-6, feat-20260609-hdrp-cluster-fragment-ggx M3).
233
250
  // The HDRP BGL descriptor is owned by pipeline-spec and shared with the
234
251
  // pipeline dispatcher and its byte-identical tests.
235
- const storageBufferCap = runtime.device.caps?.storageBuffer === true;
236
- const unifiedBglRes = device.createBindGroupLayout(
237
- createHdrpBindGroupLayoutDescriptor(storageBufferCap),
238
- );
252
+ const unifiedBglRes = device.createBindGroupLayout(createHdrpBindGroupLayoutDescriptor());
239
253
  if (!unifiedBglRes.ok) {
240
- runtime.errorRegistry.fire(unifiedBglRes.error);
241
- return null;
254
+ return failAllocation(unifiedBglRes.error);
242
255
  }
243
256
  const buffers: HdrpBuffers = {
244
- storageBuffer,
257
+ device,
245
258
  lightDataBuffer: lightData.value,
246
259
  lightDataBytes,
247
260
  clusterGridBuffer: clusterGrid.value,
@@ -256,16 +269,57 @@ export function getOrCreateHdrpBuffers(
256
269
  unifiedBindGroupLayout: unifiedBglRes.value,
257
270
  };
258
271
  cache.set(runtime, buffers);
272
+ if (cached !== undefined) {
273
+ retireHdrpBuffers(runtime, cached);
274
+ }
259
275
  return buffers;
260
276
  }
261
277
 
278
+ /**
279
+ * Drop the cached bundle before a device recovery or renderer disposal. The
280
+ * bundle carries the old device identity, so retirement fences that device's
281
+ * queue instead of consulting the replacement runtime device.
282
+ */
283
+ export function resetHdrpBuffers(runtime: RenderSystemRuntime): void {
284
+ const cached = cache.get(runtime);
285
+ if (cached === undefined) return;
286
+ cache.delete(runtime);
287
+ retireHdrpBuffers(runtime, cached);
288
+ }
289
+
290
+ function retireHdrpBuffers(runtime: RenderSystemRuntime, buffers: HdrpBuffers): void {
291
+ const device = buffers.device;
292
+ const destroy = (): void => {
293
+ for (const buffer of [
294
+ buffers.lightDataBuffer,
295
+ buffers.clusterGridBuffer,
296
+ buffers.lightIndexListBuffer,
297
+ buffers.clusterUniformBuffer,
298
+ buffers.lightBoundsBuffer,
299
+ ]) {
300
+ const result = device.destroyBuffer(buffer);
301
+ if (!result.ok) runtime.errorRegistry.fire(result.error);
302
+ }
303
+ };
304
+ const queue = device.queue as {
305
+ readonly onSubmittedWorkDone?: () => Promise<undefined>;
306
+ };
307
+ if (typeof queue.onSubmittedWorkDone === 'function') {
308
+ queue.onSubmittedWorkDone().then(destroy, destroy);
309
+ } else {
310
+ // Minimal null/test devices may not expose queue fences; they also have no
311
+ // submitted work that can retain the old bundle, so release synchronously.
312
+ destroy();
313
+ }
314
+ }
315
+
262
316
  /**
263
317
  * Build the 8-float cluster_uniform std140 payload.
264
318
  *
265
319
  * [0] gridX u32 (cast in shader)
266
320
  * [1] gridY u32
267
321
  * [2] gridZ u32
268
- * [3] lightCount u32 (vec4 alignment; capped by the active transport)
322
+ * [3] lightCount u32 (vec4 alignment; capped by MAX_LIGHTS)
269
323
  * [4] near f32
270
324
  * [5] far f32
271
325
  * [6] logFarOverNear f32
@@ -286,7 +340,6 @@ export function packClusterUniform(
286
340
  far: number,
287
341
  ssaoIntensity: number = 0,
288
342
  lightCount: number = 0,
289
- lightCapacity: number = HDRP_UNIFORM_LIGHT_CAPACITY,
290
343
  ): ArrayBuffer {
291
344
  const buf = new ArrayBuffer(32);
292
345
  const u32 = new Uint32Array(buf);
@@ -294,7 +347,7 @@ export function packClusterUniform(
294
347
  u32[0] = grid.x >>> 0;
295
348
  u32[1] = grid.y >>> 0;
296
349
  u32[2] = grid.z >>> 0;
297
- u32[3] = Math.min(Math.max(lightCount, 0), lightCapacity) >>> 0;
350
+ u32[3] = Math.min(Math.max(lightCount, 0), MAX_LIGHTS) >>> 0;
298
351
  f32[4] = near;
299
352
  f32[5] = far;
300
353
  // logFarOverNear: log(far/near) used by the shader for log-z slice mapping.
@@ -318,7 +371,7 @@ export function packClusterUniform(
318
371
  * feat-20260609-hdrp-cluster-fragment-ggx M4 / w19. Called per-frame from the
319
372
  * recordFrame HDRP block after binner+writeBuffer; the resulting BindGroup
320
373
  * lands on `passCtx.hdrpClusterBindGroup` and recordMainPass binds it at
321
- * group(2) when `frameState.isHdrpActive`.
374
+ * group(2) when the prepared Standard topology selects clustered lighting.
322
375
  *
323
376
  * Returns `null` on `device.createBindGroup` failure (a structured RhiError
324
377
  * is fired on `runtime.errorRegistry`); recordMainPass gracefully falls back
@@ -386,7 +439,7 @@ export function createHdrpUnifiedBindGroup(
386
439
  value: {
387
440
  buffer: meshStorageBuffer,
388
441
  offset: 0,
389
- size: hdrpBuffers.storageBuffer ? MESH_PER_ENTITY_STRIDE : MESH_UBO_FULL_ARRAY_BYTES,
442
+ size: MESH_PER_ENTITY_STRIDE,
390
443
  },
391
444
  },
392
445
  },
@@ -435,6 +488,59 @@ export function createHdrpUnifiedBindGroup(
435
488
  return result.value;
436
489
  }
437
490
 
491
+ /** Build the clustered skin group(2) bind group with one shared palette window. */
492
+ export function createHdrpSkinUnifiedBindGroup(
493
+ runtime: RenderSystemRuntime,
494
+ hdrpBuffers: HdrpBuffers,
495
+ layout: BindGroupLayout,
496
+ meshStorageBuffer: Buffer,
497
+ paletteBuffer: Buffer,
498
+ paletteBindingWindowBytes: number,
499
+ ssaoOptions: SsaoBindOptions = { enabled: false },
500
+ ): BindGroup | null {
501
+ const fallback = getOrCreateSsaoFallbackTexture(runtime);
502
+ if (fallback === null) return null;
503
+ const meshSize = MESH_PER_ENTITY_STRIDE;
504
+ const result = runtime.device.createBindGroup({
505
+ label: 'hdrp-skin-unified-bg-group2',
506
+ layout,
507
+ entries: [
508
+ ...createPbrSkinMeshBindGroupEntries(
509
+ meshStorageBuffer,
510
+ meshSize,
511
+ paletteBuffer,
512
+ paletteBindingWindowBytes,
513
+ ),
514
+ { binding: 3, resource: { kind: 'buffer', value: { buffer: hdrpBuffers.lightDataBuffer } } },
515
+ {
516
+ binding: 4,
517
+ resource: { kind: 'buffer', value: { buffer: hdrpBuffers.clusterGridBuffer } },
518
+ },
519
+ {
520
+ binding: 5,
521
+ resource: { kind: 'buffer', value: { buffer: hdrpBuffers.lightIndexListBuffer } },
522
+ },
523
+ {
524
+ binding: 6,
525
+ resource: { kind: 'buffer', value: { buffer: hdrpBuffers.clusterUniformBuffer } },
526
+ },
527
+ {
528
+ binding: 7,
529
+ resource: {
530
+ kind: 'textureView',
531
+ value: ssaoOptions.enabled ? ssaoOptions.ssaoBlurredView : fallback.view,
532
+ },
533
+ },
534
+ { binding: 8, resource: { kind: 'sampler', value: fallback.sampler } },
535
+ ],
536
+ });
537
+ if (!result.ok) {
538
+ runtime.errorRegistry.fire(result.error);
539
+ return null;
540
+ }
541
+ return result.value;
542
+ }
543
+
438
544
  /**
439
545
  * Build the compute-only bind group for ordered cluster membership output.
440
546
  * Its group is intentionally separate from the fragment group: the same
@@ -43,6 +43,14 @@ import {
43
43
  type TextureView,
44
44
  } from '@forgeax/engine-rhi';
45
45
  import type { DeviceScope } from '../device/device-scope';
46
+ import { createIblKernelCache, type IblKernelCache } from './kernel-cache';
47
+
48
+ export {
49
+ createIblKernelCache,
50
+ type IblKernelCache,
51
+ resetIblKernelCaches,
52
+ } from './kernel-cache';
53
+
46
54
  import { GPU_SHADER_STAGE_FRAGMENT, GPU_SHADER_STAGE_VERTEX } from '../gpu-stage';
47
55
  import {
48
56
  GPU_TEXTURE_USAGE_COPY_DST,
@@ -90,6 +98,8 @@ export interface IblPipelineError {
90
98
  * (idempotent).
91
99
  */
92
100
  export interface IblPipelineCache {
101
+ /** Reusable generation-scoped kernel state; per-probe outputs stay elsewhere. */
102
+ readonly probeKernel: IblKernelCache;
93
103
  /** Color format shared by all precompute outputs for this device. */
94
104
  outputFormat?: TextureFormat;
95
105
  /** Equirectangular-to-cubemap pipeline. */
@@ -151,6 +161,7 @@ export function getOrCreateIblCache(scope: DeviceScope): IblPipelineCache {
151
161
  if (existing !== undefined) return existing;
152
162
 
153
163
  const cache: IblPipelineCache = {
164
+ probeKernel: createIblKernelCache(scope.generation),
154
165
  irradianceBakeCount: 0,
155
166
  prefilterBakeCount: 0,
156
167
  brdfLutBakeCount: 0,
@@ -0,0 +1,88 @@
1
+ export const REFLECTION_PROBE_IBL_STAGES = ['raw', 'filtered', 'publish'] as const;
2
+ export type ReflectionProbeIblStage = (typeof REFLECTION_PROBE_IBL_STAGES)[number];
3
+
4
+ export interface IblKernelCache {
5
+ readonly generation: number;
6
+ readonly pipelineIdentity: object;
7
+ readonly samplerIdentity: object;
8
+ readonly brdfLutIdentity: object;
9
+ }
10
+
11
+ const kernelCaches = new Map<number, IblKernelCache>();
12
+
13
+ export function createIblKernelCache(generation: number): IblKernelCache {
14
+ const existing = kernelCaches.get(generation);
15
+ if (existing !== undefined) return existing;
16
+ const created: IblKernelCache = {
17
+ generation,
18
+ pipelineIdentity: {},
19
+ samplerIdentity: {},
20
+ brdfLutIdentity: {},
21
+ };
22
+ kernelCaches.set(generation, created);
23
+ return created;
24
+ }
25
+
26
+ export interface ProbeIblOutput {
27
+ readonly entityKey: number;
28
+ readonly resolution: number;
29
+ readonly deviceGeneration: number;
30
+ readonly raw: object;
31
+ readonly filtered: object;
32
+ readonly rawGeneration: number;
33
+ readonly filteredGeneration: number;
34
+ readonly lkg: boolean;
35
+ }
36
+
37
+ export interface ProbeIblUpdate extends ProbeIblOutput {
38
+ readonly stages: typeof REFLECTION_PROBE_IBL_STAGES;
39
+ readonly nextStage: ReflectionProbeIblStage;
40
+ readonly candidateGeneration: number;
41
+ }
42
+
43
+ export function createProbeIblOutput(input: {
44
+ readonly entityKey: number;
45
+ readonly resolution: number;
46
+ readonly deviceGeneration: number;
47
+ }): ProbeIblOutput {
48
+ return {
49
+ ...input,
50
+ raw: {},
51
+ filtered: {},
52
+ rawGeneration: 0,
53
+ filteredGeneration: 0,
54
+ lkg: true,
55
+ };
56
+ }
57
+
58
+ export function beginProbeIblUpdate(output: ProbeIblOutput): ProbeIblUpdate {
59
+ return {
60
+ ...output,
61
+ stages: REFLECTION_PROBE_IBL_STAGES,
62
+ nextStage: 'raw',
63
+ candidateGeneration: output.filteredGeneration + 1,
64
+ };
65
+ }
66
+
67
+ export function publishProbeIblOutput(
68
+ update: ProbeIblUpdate,
69
+ result: { readonly stage: ReflectionProbeIblStage; readonly ok: boolean },
70
+ ): ProbeIblOutput {
71
+ if (!result.ok || result.stage !== update.nextStage) return update;
72
+ if (result.stage === 'raw') {
73
+ return {
74
+ ...update,
75
+ rawGeneration: update.candidateGeneration,
76
+ };
77
+ }
78
+ if (result.stage === 'filtered') return update;
79
+ return {
80
+ ...update,
81
+ filteredGeneration: update.candidateGeneration,
82
+ lkg: true,
83
+ };
84
+ }
85
+
86
+ export function resetIblKernelCaches(): void {
87
+ kernelCaches.clear();
88
+ }