@forgeax/engine-render 0.1.20 → 0.1.23

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 (645) hide show
  1. package/README.md +365 -29
  2. package/dist/assembly/backend-contract.d.ts +13 -0
  3. package/dist/assembly/backend-contract.d.ts.map +1 -1
  4. package/dist/assembly/device-feature-admission.d.ts +18 -0
  5. package/dist/assembly/device-feature-admission.d.ts.map +1 -0
  6. package/dist/assembly/directional-shadow-inspection.d.ts +38 -0
  7. package/dist/assembly/directional-shadow-inspection.d.ts.map +1 -0
  8. package/dist/assembly/factory.d.ts +30 -19
  9. package/dist/assembly/factory.d.ts.map +1 -1
  10. package/dist/assembly/host-contract.d.ts +19 -0
  11. package/dist/assembly/host-contract.d.ts.map +1 -1
  12. package/dist/assembly/render-target-host.d.ts +46 -0
  13. package/dist/assembly/render-target-host.d.ts.map +1 -0
  14. package/dist/assets/render-asset-port.d.ts.map +1 -1
  15. package/dist/authoring.mjs +4 -1
  16. package/dist/authoring.mjs.map +1 -1
  17. package/dist/capture/cube-views.d.ts +21 -0
  18. package/dist/capture/cube-views.d.ts.map +1 -0
  19. package/dist/capture/scheduler.d.ts +54 -0
  20. package/dist/capture/scheduler.d.ts.map +1 -0
  21. package/dist/{chunk-PCHBPYML.mjs → chunk-4L3P6DT5.mjs} +2 -2
  22. package/dist/chunk-4L3P6DT5.mjs.map +1 -0
  23. package/dist/{chunk-VFPLTKCU.mjs → chunk-4NPUASZR.mjs} +15 -4
  24. package/dist/chunk-4NPUASZR.mjs.map +1 -0
  25. package/dist/chunk-DIYW3M5D.mjs +5085 -0
  26. package/dist/chunk-DIYW3M5D.mjs.map +1 -0
  27. package/dist/chunk-FBC4R44J.mjs +1003 -0
  28. package/dist/chunk-FBC4R44J.mjs.map +1 -0
  29. package/dist/{chunk-CDTWTHZR.mjs → chunk-FF7K3FSO.mjs} +474 -168
  30. package/dist/chunk-FF7K3FSO.mjs.map +1 -0
  31. package/dist/chunk-HZUPSYW7.mjs +1104 -0
  32. package/dist/chunk-HZUPSYW7.mjs.map +1 -0
  33. package/dist/{chunk-TBQJOK2L.mjs → chunk-QODA5UKU.mjs} +321 -269
  34. package/dist/chunk-QODA5UKU.mjs.map +1 -0
  35. package/dist/chunk-YALPS44A.mjs +296 -0
  36. package/dist/chunk-YALPS44A.mjs.map +1 -0
  37. package/dist/{chunk-4XINDLAY.mjs → chunk-ZUWKAZ2I.mjs} +1963 -2178
  38. package/dist/chunk-ZUWKAZ2I.mjs.map +1 -0
  39. package/dist/cluster-binner.d.ts +5 -0
  40. package/dist/cluster-binner.d.ts.map +1 -1
  41. package/dist/components/camera.d.ts +1 -0
  42. package/dist/components/camera.d.ts.map +1 -1
  43. package/dist/components/cube-camera.d.ts +20 -0
  44. package/dist/components/cube-camera.d.ts.map +1 -0
  45. package/dist/components/directional-light.d.ts +11 -2
  46. package/dist/components/directional-light.d.ts.map +1 -1
  47. package/dist/components/directional-shadow-filter.d.ts +25 -0
  48. package/dist/components/directional-shadow-filter.d.ts.map +1 -0
  49. package/dist/components/index.d.ts +5 -0
  50. package/dist/components/index.d.ts.map +1 -1
  51. package/dist/components/light-helpers.d.ts +4 -0
  52. package/dist/components/light-helpers.d.ts.map +1 -1
  53. package/dist/components/light-probe.d.ts +9 -0
  54. package/dist/components/light-probe.d.ts.map +1 -0
  55. package/dist/components/rect-area-light.d.ts +12 -0
  56. package/dist/components/rect-area-light.d.ts.map +1 -0
  57. package/dist/components/reflection-probe.d.ts +17 -0
  58. package/dist/components/reflection-probe.d.ts.map +1 -0
  59. package/dist/components/scene-instance.d.ts +4 -0
  60. package/dist/components/scene-instance.d.ts.map +1 -1
  61. package/dist/components/spot-light.d.ts +3 -0
  62. package/dist/components/spot-light.d.ts.map +1 -1
  63. package/dist/construct-renderer.mjs +14836 -9620
  64. package/dist/construct-renderer.mjs.map +1 -1
  65. package/dist/device/gpu-residency.d.ts +8 -1
  66. package/dist/device/gpu-residency.d.ts.map +1 -1
  67. package/dist/device/lifecycle-transaction.d.ts +2 -0
  68. package/dist/device/lifecycle-transaction.d.ts.map +1 -0
  69. package/dist/environment/frame.d.ts.map +1 -1
  70. package/dist/environment/lifecycle.d.ts +5 -0
  71. package/dist/environment/lifecycle.d.ts.map +1 -1
  72. package/dist/errors/gpu-driven.d.ts +26 -0
  73. package/dist/errors/gpu-driven.d.ts.map +1 -0
  74. package/dist/errors/index.d.ts +1 -0
  75. package/dist/errors/index.d.ts.map +1 -1
  76. package/dist/errors/recover.d.ts +9 -1
  77. package/dist/errors/recover.d.ts.map +1 -1
  78. package/dist/errors/render.d.ts +166 -93
  79. package/dist/errors/render.d.ts.map +1 -1
  80. package/dist/extract/directional-shadow-projection.d.ts +23 -0
  81. package/dist/extract/directional-shadow-projection.d.ts.map +1 -0
  82. package/dist/extract/environment.d.ts +14 -0
  83. package/dist/extract/environment.d.ts.map +1 -1
  84. package/dist/extract/gpu-driven.d.ts +50 -0
  85. package/dist/extract/gpu-driven.d.ts.map +1 -0
  86. package/dist/extract/visibility.d.ts.map +1 -1
  87. package/dist/features/fullscreen.d.ts.map +1 -1
  88. package/dist/features/targets.d.ts.map +1 -1
  89. package/dist/features/types.d.ts +10 -0
  90. package/dist/features/types.d.ts.map +1 -1
  91. package/dist/fullscreen-post-process-pass.d.ts +13 -2
  92. package/dist/fullscreen-post-process-pass.d.ts.map +1 -1
  93. package/dist/gpu-driven/batch-topology.d.ts +34 -0
  94. package/dist/gpu-driven/batch-topology.d.ts.map +1 -1
  95. package/dist/gpu-driven/prepared-draw.d.ts +63 -0
  96. package/dist/gpu-driven/prepared-draw.d.ts.map +1 -0
  97. package/dist/gpu-driven/production-raster.d.ts +97 -2
  98. package/dist/gpu-driven/production-raster.d.ts.map +1 -1
  99. package/dist/gpu-driven/view-gpu.d.ts +64 -1
  100. package/dist/gpu-driven/view-gpu.d.ts.map +1 -1
  101. package/dist/gpu-scene-schema.d.ts +14 -0
  102. package/dist/gpu-scene-schema.d.ts.map +1 -1
  103. package/dist/gpu-scene.d.ts +8 -1
  104. package/dist/gpu-scene.d.ts.map +1 -1
  105. package/dist/gpu-usage.d.ts +0 -1
  106. package/dist/gpu-usage.d.ts.map +1 -1
  107. package/dist/hdrp-buffers.d.ts +21 -19
  108. package/dist/hdrp-buffers.d.ts.map +1 -1
  109. package/dist/ibl/IblPipelineCache.d.ts +4 -0
  110. package/dist/ibl/IblPipelineCache.d.ts.map +1 -1
  111. package/dist/ibl/kernel-cache.d.ts +36 -0
  112. package/dist/ibl/kernel-cache.d.ts.map +1 -0
  113. package/dist/index.d.ts +39 -3
  114. package/dist/index.d.ts.map +1 -1
  115. package/dist/index.mjs +91 -6
  116. package/dist/index.mjs.map +1 -1
  117. package/dist/inspection-types.d.ts +214 -1
  118. package/dist/inspection-types.d.ts.map +1 -1
  119. package/dist/instances-derived-bounds.d.ts +50 -0
  120. package/dist/instances-derived-bounds.d.ts.map +1 -0
  121. package/dist/internal.d.ts +9 -0
  122. package/dist/internal.d.ts.map +1 -1
  123. package/dist/internal.mjs +23 -2
  124. package/dist/internal.mjs.map +1 -1
  125. package/dist/light-buffer-layout.d.ts +58 -140
  126. package/dist/light-buffer-layout.d.ts.map +1 -1
  127. package/dist/materials.d.ts.map +1 -1
  128. package/dist/mesh-material-bindings.d.ts +54 -0
  129. package/dist/mesh-material-bindings.d.ts.map +1 -1
  130. package/dist/pbr-pipeline.d.ts +38 -14
  131. package/dist/pbr-pipeline.d.ts.map +1 -1
  132. package/dist/pipeline/standard-forward-lane.d.ts +2 -1
  133. package/dist/pipeline/standard-forward-lane.d.ts.map +1 -1
  134. package/dist/pipeline/standard-lighting/errors.d.ts +4 -0
  135. package/dist/pipeline/standard-lighting/errors.d.ts.map +1 -0
  136. package/dist/pipeline/standard-lighting/graph.d.ts +24 -0
  137. package/dist/pipeline/standard-lighting/graph.d.ts.map +1 -0
  138. package/dist/pipeline/standard-lighting/inspection.d.ts +38 -0
  139. package/dist/pipeline/standard-lighting/inspection.d.ts.map +1 -0
  140. package/dist/pipeline/standard-lighting/layout.d.ts +28 -0
  141. package/dist/pipeline/standard-lighting/layout.d.ts.map +1 -0
  142. package/dist/pipeline/standard-lighting/light-frame.d.ts +33 -0
  143. package/dist/pipeline/standard-lighting/light-frame.d.ts.map +1 -0
  144. package/dist/pipeline/standard-lighting/membership.d.ts +14 -0
  145. package/dist/pipeline/standard-lighting/membership.d.ts.map +1 -0
  146. package/dist/pipeline/standard-lighting/prepare.d.ts +16 -0
  147. package/dist/pipeline/standard-lighting/prepare.d.ts.map +1 -0
  148. package/dist/pipeline/standard-lighting/topology.d.ts +45 -0
  149. package/dist/pipeline/standard-lighting/topology.d.ts.map +1 -0
  150. package/dist/pipeline/standard-lighting/transport.d.ts +36 -0
  151. package/dist/pipeline/standard-lighting/transport.d.ts.map +1 -0
  152. package/dist/pipeline/standard-pipeline.d.ts +4 -13
  153. package/dist/pipeline/standard-pipeline.d.ts.map +1 -1
  154. package/dist/pipeline/standard-post.d.ts.map +1 -1
  155. package/dist/pipeline/standard-profile.d.ts +5 -26
  156. package/dist/pipeline/standard-profile.d.ts.map +1 -1
  157. package/dist/pipeline-builder.d.ts +2 -0
  158. package/dist/pipeline-builder.d.ts.map +1 -1
  159. package/dist/pipeline-spec.d.ts +40 -7
  160. package/dist/pipeline-spec.d.ts.map +1 -1
  161. package/dist/plugin.d.ts.map +1 -1
  162. package/dist/point-shadow-inspection.d.ts +21 -0
  163. package/dist/point-shadow-inspection.d.ts.map +1 -0
  164. package/dist/prepare/extended-lighting/ltc-resources.d.ts +31 -0
  165. package/dist/prepare/extended-lighting/ltc-resources.d.ts.map +1 -0
  166. package/dist/prepare/extended-lighting/resources.d.ts +72 -0
  167. package/dist/prepare/extended-lighting/resources.d.ts.map +1 -0
  168. package/dist/prepare/extended-lighting/spot-modifiers.d.ts +42 -0
  169. package/dist/prepare/extended-lighting/spot-modifiers.d.ts.map +1 -0
  170. package/dist/prepare/extended-lighting/state.d.ts +24 -0
  171. package/dist/prepare/extended-lighting/state.d.ts.map +1 -0
  172. package/dist/record/frame-lighting.d.ts +33 -36
  173. package/dist/record/frame-lighting.d.ts.map +1 -1
  174. package/dist/record/frame-snapshot.d.ts +78 -24
  175. package/dist/record/frame-snapshot.d.ts.map +1 -1
  176. package/dist/record/frame-targets.d.ts +5 -0
  177. package/dist/record/frame-targets.d.ts.map +1 -1
  178. package/dist/record/frame.d.ts +16 -6
  179. package/dist/record/frame.d.ts.map +1 -1
  180. package/dist/record/gpu-pass-timing/contract.d.ts +96 -0
  181. package/dist/record/gpu-pass-timing/contract.d.ts.map +1 -0
  182. package/dist/record/gpu-pass-timing/errors.d.ts +18 -0
  183. package/dist/record/gpu-pass-timing/errors.d.ts.map +1 -0
  184. package/dist/record/gpu-pass-timing/index.d.ts +8 -0
  185. package/dist/record/gpu-pass-timing/index.d.ts.map +1 -0
  186. package/dist/record/gpu-pass-timing/parser.d.ts +11 -0
  187. package/dist/record/gpu-pass-timing/parser.d.ts.map +1 -0
  188. package/dist/record/gpu-pass-timing/session.d.ts +43 -0
  189. package/dist/record/gpu-pass-timing/session.d.ts.map +1 -0
  190. package/dist/record/gpu-timing.d.ts +20 -3
  191. package/dist/record/gpu-timing.d.ts.map +1 -1
  192. package/dist/record/helpers.d.ts +0 -20
  193. package/dist/record/helpers.d.ts.map +1 -1
  194. package/dist/record/main-pass-geometry.d.ts +6 -1
  195. package/dist/record/main-pass-geometry.d.ts.map +1 -1
  196. package/dist/record/main-pass-material.d.ts +25 -2
  197. package/dist/record/main-pass-material.d.ts.map +1 -1
  198. package/dist/record/main-pass-sprite-draws.d.ts.map +1 -1
  199. package/dist/record/main-pass.d.ts +2 -0
  200. package/dist/record/main-pass.d.ts.map +1 -1
  201. package/dist/record/mesh-ssbo.d.ts.map +1 -1
  202. package/dist/record/render-context.d.ts +98 -6
  203. package/dist/record/render-context.d.ts.map +1 -1
  204. package/dist/record/shadow-pass.d.ts.map +1 -1
  205. package/dist/record/skybox-post-pass.d.ts.map +1 -1
  206. package/dist/record/typed-frame-graph.d.ts +119 -4
  207. package/dist/record/typed-frame-graph.d.ts.map +1 -1
  208. package/dist/record/view-ubo.d.ts +7 -5
  209. package/dist/record/view-ubo.d.ts.map +1 -1
  210. package/dist/reflection/filter.d.ts +22 -0
  211. package/dist/reflection/filter.d.ts.map +1 -0
  212. package/dist/reflection/gpu-table.d.ts +25 -0
  213. package/dist/reflection/gpu-table.d.ts.map +1 -0
  214. package/dist/reflection/inspection.d.ts +10 -0
  215. package/dist/reflection/inspection.d.ts.map +1 -0
  216. package/dist/reflection/projection.d.ts +140 -0
  217. package/dist/reflection/projection.d.ts.map +1 -0
  218. package/dist/reflection/record-owner.d.ts +60 -0
  219. package/dist/reflection/record-owner.d.ts.map +1 -0
  220. package/dist/render-contract.d.ts +62 -14
  221. package/dist/render-contract.d.ts.map +1 -1
  222. package/dist/render-graph-primitives.d.ts +1 -0
  223. package/dist/render-graph-primitives.d.ts.map +1 -1
  224. package/dist/render-pipeline.d.ts +49 -2
  225. package/dist/render-pipeline.d.ts.map +1 -1
  226. package/dist/render-system-extract.d.ts +160 -31
  227. package/dist/render-system-extract.d.ts.map +1 -1
  228. package/dist/render-system.d.ts +28 -2
  229. package/dist/render-system.d.ts.map +1 -1
  230. package/dist/renderer.d.ts +43 -0
  231. package/dist/renderer.d.ts.map +1 -0
  232. package/dist/scene/probe-blend-record.d.ts +22 -0
  233. package/dist/scene/probe-blend-record.d.ts.map +1 -0
  234. package/dist/scene/probe-blend.d.ts +142 -0
  235. package/dist/scene/probe-blend.d.ts.map +1 -0
  236. package/dist/scene/render-scene-types.d.ts +0 -6
  237. package/dist/scene/render-scene-types.d.ts.map +1 -1
  238. package/dist/scene/render-scene.d.ts +117 -9
  239. package/dist/scene/render-scene.d.ts.map +1 -1
  240. package/dist/scene/visibility/bounds.d.ts +20 -0
  241. package/dist/scene/visibility/bounds.d.ts.map +1 -0
  242. package/dist/scene/visibility/budget.d.ts +16 -0
  243. package/dist/scene/visibility/budget.d.ts.map +1 -0
  244. package/dist/scene/visibility/facet.d.ts +73 -0
  245. package/dist/scene/visibility/facet.d.ts.map +1 -0
  246. package/dist/scene/visibility/gpu-frame-timing.d.ts +41 -0
  247. package/dist/scene/visibility/gpu-frame-timing.d.ts.map +1 -0
  248. package/dist/scene/visibility/gpu-lod.d.ts +46 -0
  249. package/dist/scene/visibility/gpu-lod.d.ts.map +1 -0
  250. package/dist/scene/visibility/inspection.d.ts +132 -0
  251. package/dist/scene/visibility/inspection.d.ts.map +1 -0
  252. package/dist/scene/visibility/lod-selector.d.ts +25 -0
  253. package/dist/scene/visibility/lod-selector.d.ts.map +1 -0
  254. package/dist/scene/visibility/occlusion-confidence.d.ts +81 -0
  255. package/dist/scene/visibility/occlusion-confidence.d.ts.map +1 -0
  256. package/dist/scene/visibility/occlusion-pass.d.ts +57 -0
  257. package/dist/scene/visibility/occlusion-pass.d.ts.map +1 -0
  258. package/dist/scene/visibility/occlusion-query-pool.d.ts +57 -0
  259. package/dist/scene/visibility/occlusion-query-pool.d.ts.map +1 -0
  260. package/dist/scene/visibility/occlusion-runtime.d.ts +96 -0
  261. package/dist/scene/visibility/occlusion-runtime.d.ts.map +1 -0
  262. package/dist/scene/visibility/types.d.ts +34 -0
  263. package/dist/scene/visibility/types.d.ts.map +1 -0
  264. package/dist/shadow-atlas.d.ts +3 -3
  265. package/dist/shadow-atlas.d.ts.map +1 -1
  266. package/dist/ssao-buffers.d.ts +3 -0
  267. package/dist/ssao-buffers.d.ts.map +1 -1
  268. package/dist/ssr/admission.d.ts +122 -0
  269. package/dist/ssr/admission.d.ts.map +1 -0
  270. package/dist/ssr/composition.d.ts +32 -0
  271. package/dist/ssr/composition.d.ts.map +1 -0
  272. package/dist/ssr/errors.d.ts +39 -0
  273. package/dist/ssr/errors.d.ts.map +1 -0
  274. package/dist/ssr/identity.d.ts +13 -0
  275. package/dist/ssr/identity.d.ts.map +1 -0
  276. package/dist/systems/skin-palette-allocator.d.ts +1 -1
  277. package/dist/targets/contracts.d.ts +66 -0
  278. package/dist/targets/contracts.d.ts.map +1 -0
  279. package/dist/targets/graph-projection.d.ts +29 -0
  280. package/dist/targets/graph-projection.d.ts.map +1 -0
  281. package/dist/targets/material-source.d.ts +34 -0
  282. package/dist/targets/material-source.d.ts.map +1 -0
  283. package/dist/targets/owner.d.ts +32 -0
  284. package/dist/targets/owner.d.ts.map +1 -0
  285. package/dist/targets/physical.d.ts +18 -0
  286. package/dist/targets/physical.d.ts.map +1 -0
  287. package/dist/targets/readback.d.ts +39 -0
  288. package/dist/targets/readback.d.ts.map +1 -0
  289. package/dist/temporal/frame-coordinator.d.ts +13 -0
  290. package/dist/temporal/frame-coordinator.d.ts.map +1 -1
  291. package/dist/temporal/frame.d.ts +2 -0
  292. package/dist/temporal/frame.d.ts.map +1 -1
  293. package/dist/temporal/index.mjs +6 -5
  294. package/dist/temporal/view.d.ts +7 -0
  295. package/dist/temporal/view.d.ts.map +1 -1
  296. package/dist/tilemap-chunk-extract-system.d.ts +1 -1
  297. package/dist/typed-render-graph-primitives.d.ts +5 -1
  298. package/dist/typed-render-graph-primitives.d.ts.map +1 -1
  299. package/dist/typed-shadow-passes.d.ts +1 -1
  300. package/dist/typed-shadow-passes.d.ts.map +1 -1
  301. package/dist/volume/passes.d.ts +9 -5
  302. package/dist/volume/passes.d.ts.map +1 -1
  303. package/package.json +20 -20
  304. package/src/__tests__/bloom-exact-zero.unit.test.ts +48 -19
  305. package/src/__tests__/bloom-lifecycle.integration.test.ts +41 -13
  306. package/src/__tests__/camera-target-consumption.unit.test.ts +53 -0
  307. package/src/__tests__/cluster-binner.unit.test.ts +35 -0
  308. package/src/__tests__/cluster-grid-default-surface.unit.test.ts +12 -2
  309. package/src/__tests__/cube-camera-scheduler.unit.test.ts +70 -0
  310. package/src/__tests__/cube-camera-single-submit.perf.test.ts +75 -0
  311. package/src/__tests__/cube-camera-view-matrices.unit.test.ts +41 -0
  312. package/src/__tests__/cube-camera-vocabulary.unit.test.ts +47 -0
  313. package/src/__tests__/cube-camera.integration.test.ts +42 -0
  314. package/src/__tests__/detached-inspection.integration.test.ts +6 -0
  315. package/src/__tests__/device-feature-admission.unit.test.ts +85 -0
  316. package/src/__tests__/direct-light-snapshot.unit.test.ts +62 -6
  317. package/src/__tests__/docs-gate-green.unit.test.ts +38 -0
  318. package/src/__tests__/environment-generation.integration.test.ts +16 -0
  319. package/src/__tests__/evidence-identity.ts +13 -0
  320. package/src/__tests__/evidence-identity.unit.test.ts +24 -0
  321. package/src/__tests__/extended-lighting-recovery.browser.test.ts +14 -0
  322. package/src/__tests__/extended-lighting-recovery.dawn.test.ts +14 -0
  323. package/src/__tests__/extended-lighting-recovery.integration.test.ts +81 -0
  324. package/src/__tests__/extended-lighting-resources.unit.test.ts +51 -0
  325. package/src/__tests__/extended-lighting-zero-feature.integration.test.ts +52 -0
  326. package/src/__tests__/factory-contract.integration.test.ts +288 -29
  327. package/src/__tests__/fog-component.unit.test.ts +67 -0
  328. package/src/__tests__/fog.integration.test.ts +86 -0
  329. package/src/__tests__/frame-observation.contract.test.ts +15 -0
  330. package/src/__tests__/fullscreen-feature-plan.unit.test.ts +37 -0
  331. package/src/__tests__/gpu-driven-batch-topology-pbr.unit.test.ts +146 -0
  332. package/src/__tests__/gpu-driven-indirect-raster-evidence.ts +10 -8
  333. package/src/__tests__/gpu-driven-indirect-raster.dawn.test.ts +18 -1
  334. package/src/__tests__/gpu-driven-production.integration.test.ts +579 -17
  335. package/src/__tests__/gpu-driven-scaling.unit.test.ts +66 -2
  336. package/src/__tests__/gpu-driven-view-gpu-evidence.ts +26 -1
  337. package/src/__tests__/gpu-driven-view-graph.integration.test.ts +101 -6
  338. package/src/__tests__/gpu-driven-view.browser.test.ts +3 -3
  339. package/src/__tests__/gpu-driven-view.dawn.test.ts +3 -3
  340. package/src/__tests__/gpu-driven-view.unit.test.ts +50 -0
  341. package/src/__tests__/gpu-lod-evidence.ts +188 -0
  342. package/src/__tests__/gpu-lod-fallback.integration.test.ts +10 -0
  343. package/src/__tests__/gpu-lod-indirect.integration.test.ts +40 -0
  344. package/src/__tests__/gpu-lod-parity.dawn.test.ts +29 -0
  345. package/src/__tests__/gpu-lod-readiness.integration.test.ts +52 -0
  346. package/src/__tests__/gpu-lod-schema.unit.test.ts +66 -0
  347. package/src/__tests__/gpu-lod-selector.unit.test.ts +28 -0
  348. package/src/__tests__/gpu-lod-silhouette.browser.test.ts +13 -0
  349. package/src/__tests__/gpu-pass-timing-browser-runner.ts +281 -0
  350. package/src/__tests__/gpu-pass-timing-coexistence.integration.test.ts +80 -0
  351. package/src/__tests__/gpu-pass-timing-contract.unit.test.ts +243 -0
  352. package/src/__tests__/gpu-pass-timing-exact-zero.unit.test.ts +131 -0
  353. package/src/__tests__/gpu-pass-timing-lifecycle.integration.test.ts +230 -0
  354. package/src/__tests__/gpu-pass-timing-observation.unit.test.ts +233 -0
  355. package/src/__tests__/gpu-pass-timing-session.unit.test.ts +438 -0
  356. package/src/__tests__/gpu-pass-timing.browser.test.ts +26 -0
  357. package/src/__tests__/gpu-pass-timing.rhi-null.unit.test.ts +125 -0
  358. package/src/__tests__/gpu-resource-store-stride.unit.test.ts +66 -1
  359. package/src/__tests__/gpu-scene.dawn.test.ts +8 -1
  360. package/src/__tests__/gpu-scene.unit.test.ts +49 -3
  361. package/src/__tests__/hdrp-group2-visibility.unit.test.ts +24 -0
  362. package/src/__tests__/instances-culling.integration.test.ts +94 -0
  363. package/src/__tests__/instances-derived-bounds.unit.test.ts +118 -0
  364. package/src/__tests__/light-buffer-layout.unit.test.ts +113 -3
  365. package/src/__tests__/light-inspection.unit.test.ts +55 -0
  366. package/src/__tests__/light-resource-error.unit.test.ts +43 -0
  367. package/src/__tests__/lighting-scene-roundtrip.integration.test.ts +109 -0
  368. package/src/__tests__/lod-bounds.unit.test.ts +42 -0
  369. package/src/__tests__/lod-cpu-lane.integration.test.ts +55 -0
  370. package/src/__tests__/lod-cpu-no-change.perf.test.ts +19 -0
  371. package/src/__tests__/lod-gpu-frame-timing.unit.test.ts +49 -0
  372. package/src/__tests__/lod-multi-view.integration.test.ts +63 -0
  373. package/src/__tests__/lod-occlusion-device-loss.integration.test.ts +27 -0
  374. package/src/__tests__/lod-occlusion-final-decision.integration.test.ts +47 -0
  375. package/src/__tests__/lod-occlusion-inspection.integration.test.ts +217 -0
  376. package/src/__tests__/lod-occlusion-inspection.schema.test-d.ts +14 -0
  377. package/src/__tests__/lod-occlusion-inspection.unit.test.ts +72 -0
  378. package/src/__tests__/lod-occlusion-visual-evidence.ts +91 -0
  379. package/src/__tests__/lod-occlusion.browser.test.ts +15 -0
  380. package/src/__tests__/lod-occlusion.dawn.test.ts +20 -0
  381. package/src/__tests__/lod-selector.profile.test.ts +35 -0
  382. package/src/__tests__/lod-selector.unit.test.ts +68 -0
  383. package/src/__tests__/lod-visibility-identity.unit.test.ts +198 -0
  384. package/src/__tests__/lod-visibility-lifecycle.integration.test.ts +132 -0
  385. package/src/__tests__/ltc-resources.unit.test.ts +32 -0
  386. package/src/__tests__/material-contract-inventory.unit.test.ts +17 -0
  387. package/src/__tests__/material-observation.integration.test.ts +101 -0
  388. package/src/__tests__/occlusion-confidence.unit.test.ts +168 -0
  389. package/src/__tests__/occlusion-invalidation.integration.test.ts +37 -0
  390. package/src/__tests__/occlusion-pass-routing.unit.test.ts +16 -0
  391. package/src/__tests__/occlusion-pass.dawn.test.ts +20 -0
  392. package/src/__tests__/occlusion-pass.integration.test.ts +43 -0
  393. package/src/__tests__/occlusion-pass.rhi-null.test.ts +22 -0
  394. package/src/__tests__/occlusion-query-pool.rhi-null.test.ts +21 -0
  395. package/src/__tests__/occlusion-query-pool.unit.test.ts +95 -0
  396. package/src/__tests__/occlusion-query-ticket.integration.test.ts +47 -0
  397. package/src/__tests__/occlusion-query.dawn.test.ts +16 -0
  398. package/src/__tests__/occlusion-query.evidence.ts +178 -0
  399. package/src/__tests__/occlusion-query.rhi-null.test.ts +31 -0
  400. package/src/__tests__/occlusion-runtime.unit.test.ts +120 -0
  401. package/src/__tests__/pbr-view-layout.unit.test.ts +16 -0
  402. package/src/__tests__/point-shadow-inspection.unit.test.ts +60 -0
  403. package/src/__tests__/prepared-gpu-driven-pbr.integration.test.ts +196 -0
  404. package/src/__tests__/probe-bindings.unit.test.ts +200 -0
  405. package/src/__tests__/probe-blend-numeric.unit.test.ts +67 -0
  406. package/src/__tests__/probe-blend-oracle.unit.test.ts +136 -0
  407. package/src/__tests__/probe-capacity.integration.test.ts +97 -0
  408. package/src/__tests__/probe-recovery.integration.test.ts +104 -0
  409. package/src/__tests__/probe-scene-dirty.integration.test.ts +211 -0
  410. package/src/__tests__/profiler-phase-catalog.test.ts +4 -1
  411. package/src/__tests__/profiler-phase-token.test.ts +1 -0
  412. package/src/__tests__/public-surface.test-d.ts +10 -0
  413. package/src/__tests__/rect-area-boundary.unit.test.ts +24 -0
  414. package/src/__tests__/reflection-fallback-graph.unit.test.ts +67 -0
  415. package/src/__tests__/reflection-fallback-inspection.unit.test.ts +77 -0
  416. package/src/__tests__/reflection-fallback-lifecycle.integration.test.ts +21 -0
  417. package/src/__tests__/reflection-fallback-projection.unit.test.ts +90 -0
  418. package/src/__tests__/reflection-fallback-source.unit.test.ts +32 -0
  419. package/src/__tests__/reflection-probe-authoring.unit.test.ts +71 -0
  420. package/src/__tests__/reflection-probe-filter.unit.test.ts +54 -0
  421. package/src/__tests__/reflection-probe-ibl-topology.unit.test.ts +45 -0
  422. package/src/__tests__/reflection-probe-owner-placement.unit.test.ts +39 -0
  423. package/src/__tests__/reflection-probe-pass-encode.integration.test.ts +101 -0
  424. package/src/__tests__/reflection-probe-performance.perf.test.ts +60 -0
  425. package/src/__tests__/reflection-probe-record-owner.characterization.unit.test.ts +120 -0
  426. package/src/__tests__/reflection-probe-recovery.integration.test.ts +55 -0
  427. package/src/__tests__/reflection-probe-selection.unit.test.ts +46 -0
  428. package/src/__tests__/render-error-code-owner.test-d.ts +19 -3
  429. package/src/__tests__/render-feature-docs.unit.test.ts +12 -7
  430. package/src/__tests__/render-graph-fallback.integration.test.ts +24 -0
  431. package/src/__tests__/render-perf/extended-lighting.bench.test.ts +66 -0
  432. package/src/__tests__/render-scene-projection.unit.test.ts +447 -18
  433. package/src/__tests__/render-target-admission.unit.test.ts +80 -0
  434. package/src/__tests__/render-target-graph-projection.unit.test.ts +102 -0
  435. package/src/__tests__/render-target-inspection.unit.test.ts +52 -0
  436. package/src/__tests__/render-target-material-source.test-d.ts +30 -0
  437. package/src/__tests__/render-target-material-source.unit.test.ts +97 -0
  438. package/src/__tests__/render-target-owner-placement.unit.test.ts +203 -0
  439. package/src/__tests__/render-target-owner.unit.test.ts +122 -0
  440. package/src/__tests__/render-target-probe-soak.perf.test.ts +94 -0
  441. package/src/__tests__/render-target-public-schema.json +107 -0
  442. package/src/__tests__/render-target-public-schema.unit.test.ts +91 -0
  443. package/src/__tests__/render-target-public-surface.test-d.ts +83 -0
  444. package/src/__tests__/render-target-readback.integration.test.ts +90 -0
  445. package/src/__tests__/render-target-recovery.integration.test.ts +85 -0
  446. package/src/__tests__/renderer-factory-material-contract.unit.test.ts +124 -0
  447. package/src/__tests__/renderer-lifecycle.integration.test.ts +14 -0
  448. package/src/__tests__/shader-stage-surface.unit.test.ts +19 -4
  449. package/src/__tests__/skin-motion-regression.unit.test.ts +154 -0
  450. package/src/__tests__/skinned-shadow-caster.test.ts +13 -4
  451. package/src/__tests__/spot-modifier-projection.unit.test.ts +70 -0
  452. package/src/__tests__/ssr-admission-matrix.integration.test.ts +206 -0
  453. package/src/__tests__/ssr-composition.unit.test.ts +46 -0
  454. package/src/__tests__/ssr-fallback-zero-work.bench.test.ts +94 -0
  455. package/src/__tests__/ssr-recovery-errors.unit.test.ts +58 -0
  456. package/src/__tests__/standard-cluster-capability.integration.test.ts +63 -0
  457. package/src/__tests__/standard-cluster-transport.unit.test.ts +121 -0
  458. package/src/__tests__/standard-cluster-variant-resolution.unit.test.ts +299 -0
  459. package/src/__tests__/standard-clustered-pipeline.unit.test.ts +15 -5
  460. package/src/__tests__/standard-lighting-inspection.integration.test.ts +138 -0
  461. package/src/__tests__/standard-lighting-ssot.unit.test.ts +18 -0
  462. package/src/__tests__/standard-lighting-write.unit.test.ts +441 -0
  463. package/src/__tests__/standard-lighting.integration.test.ts +67 -0
  464. package/src/__tests__/standard-pipeline.dawn.test.ts +206 -5
  465. package/src/__tests__/standard-pipeline.integration.test.ts +181 -150
  466. package/src/__tests__/standard-probe-binding.unit.test.ts +25 -0
  467. package/src/__tests__/standard-profile-oracle.unit.test.ts +23 -38
  468. package/src/__tests__/temporal-fallback-generation.integration.test.ts +16 -0
  469. package/src/__tests__/temporal-view.unit.test.ts +3 -3
  470. package/src/__tests__/transmission-prewarm.unit.test.ts +69 -0
  471. package/src/__tests__/typed-pipeline-topology.unit.test.ts +395 -14
  472. package/src/__tests__/urp-pipeline-targets.unit.test.ts +2 -2
  473. package/src/__tests__/visibility-budget.integration.test.ts +140 -0
  474. package/src/__tests__/visibility-budget.unit.test.ts +70 -0
  475. package/src/__tests__/visibility-extract.integration.test.ts +11 -6
  476. package/src/__tests__/visibility-resolver.unit.test.ts +15 -0
  477. package/src/__tests__/volumetric-fog-point-spot-accumulation.integration.test.ts +6 -3
  478. package/src/__tests__/volumetric-fog-stage-readback.dawn.test.ts +31 -28
  479. package/src/assembly/backend-contract.ts +13 -0
  480. package/src/assembly/device-feature-admission.ts +80 -0
  481. package/src/assembly/directional-shadow-inspection.ts +122 -0
  482. package/src/assembly/factory.ts +1411 -366
  483. package/src/assembly/host-contract.ts +35 -0
  484. package/src/assembly/render-target-host.ts +847 -0
  485. package/src/assets/asset-decoders.ts +1 -1
  486. package/src/assets/render-asset-port.ts +7 -1
  487. package/src/capture/cube-views.ts +69 -0
  488. package/src/capture/scheduler.ts +265 -0
  489. package/src/cluster-binner.ts +31 -0
  490. package/src/components/__tests__/lighting-authoring.unit.test.ts +39 -0
  491. package/src/components/__tests__/rect-area-light.unit.test.ts +33 -0
  492. package/src/components/__tests__/schema-contract.unit.test.ts +12 -0
  493. package/src/components/__tests__/schema-parity.unit.test.ts +9 -0
  494. package/src/components/camera.ts +4 -0
  495. package/src/components/cube-camera.ts +52 -0
  496. package/src/components/directional-light.ts +22 -2
  497. package/src/components/directional-shadow-filter.ts +57 -0
  498. package/src/components/index.ts +5 -0
  499. package/src/components/light-helpers.ts +133 -8
  500. package/src/components/light-probe.ts +13 -0
  501. package/src/components/rect-area-light.ts +15 -0
  502. package/src/components/reflection-probe.ts +49 -0
  503. package/src/components/scene-instance.ts +6 -0
  504. package/src/components/spot-light.ts +3 -0
  505. package/src/device/__tests__/extended-lighting-recovery.unit.test.ts +24 -0
  506. package/src/device/gpu-residency.ts +140 -9
  507. package/src/device/lifecycle-transaction.ts +12 -0
  508. package/src/environment/frame.ts +6 -24
  509. package/src/environment/lifecycle.ts +20 -1
  510. package/src/errors/gpu-driven.ts +92 -0
  511. package/src/errors/index.ts +1 -0
  512. package/src/errors/recover.ts +32 -0
  513. package/src/errors/render.ts +341 -143
  514. package/src/extract/camera.ts +3 -3
  515. package/src/extract/directional-shadow-projection.ts +61 -0
  516. package/src/extract/environment.ts +57 -0
  517. package/src/extract/gpu-driven.ts +108 -0
  518. package/src/extract/visibility.ts +2 -1
  519. package/src/features/fullscreen.ts +3 -0
  520. package/src/features/targets.ts +4 -1
  521. package/src/features/types.ts +10 -0
  522. package/src/fullscreen-post-process-pass.ts +43 -2
  523. package/src/gpu-driven/batch-topology.ts +207 -28
  524. package/src/gpu-driven/prepared-draw.ts +208 -0
  525. package/src/gpu-driven/production-raster.ts +953 -43
  526. package/src/gpu-driven/view-gpu.ts +411 -29
  527. package/src/gpu-scene-schema.ts +13 -0
  528. package/src/gpu-scene.ts +140 -64
  529. package/src/gpu-usage.ts +0 -1
  530. package/src/hdrp-buffers.ts +169 -63
  531. package/src/ibl/IblPipelineCache.ts +11 -0
  532. package/src/ibl/kernel-cache.ts +88 -0
  533. package/src/index.ts +222 -0
  534. package/src/inspection-types.ts +276 -1
  535. package/src/instances-derived-bounds.ts +171 -0
  536. package/src/internal.ts +38 -0
  537. package/src/light-buffer-layout.ts +155 -310
  538. package/src/materials.ts +16 -2
  539. package/src/mesh-material-bindings.ts +132 -0
  540. package/src/pbr-pipeline.ts +255 -60
  541. package/src/pipeline/standard-forward-lane.ts +93 -16
  542. package/src/pipeline/standard-lighting/errors.ts +6 -0
  543. package/src/pipeline/standard-lighting/graph.ts +158 -0
  544. package/src/pipeline/standard-lighting/inspection.ts +88 -0
  545. package/src/pipeline/standard-lighting/layout.ts +31 -0
  546. package/src/pipeline/standard-lighting/light-frame.ts +35 -0
  547. package/src/pipeline/standard-lighting/membership.ts +43 -0
  548. package/src/pipeline/standard-lighting/prepare.ts +37 -0
  549. package/src/pipeline/standard-lighting/topology.ts +120 -0
  550. package/src/pipeline/standard-lighting/transport.ts +78 -0
  551. package/src/pipeline/standard-pipeline.ts +124 -193
  552. package/src/pipeline/standard-post.ts +26 -7
  553. package/src/pipeline/standard-profile.ts +17 -47
  554. package/src/pipeline-builder.ts +5 -2
  555. package/src/pipeline-spec.ts +95 -21
  556. package/src/plugin.ts +4 -0
  557. package/src/point-shadow-inspection.ts +55 -0
  558. package/src/prepare/__tests__/extended-lighting-capability.unit.test.ts +56 -0
  559. package/src/prepare/extended-lighting/ltc-resources.ts +136 -0
  560. package/src/prepare/extended-lighting/resources.ts +389 -0
  561. package/src/prepare/extended-lighting/spot-modifiers.ts +194 -0
  562. package/src/prepare/extended-lighting/state.ts +92 -0
  563. package/src/record/__tests__/gpu-timing.unit.test.ts +177 -0
  564. package/src/record/__tests__/temporal-payload.unit.test.ts +64 -1
  565. package/src/record/__tests__/transparent-group2-selection.unit.test.ts +73 -0
  566. package/src/record/__tests__/typed-frame-graph-plan.unit.test.ts +20 -1
  567. package/src/record/__tests__/view-ubo-layout.unit.test.ts +40 -0
  568. package/src/record/frame-lighting.ts +591 -452
  569. package/src/record/frame-snapshot.ts +92 -39
  570. package/src/record/frame-targets.ts +17 -0
  571. package/src/record/frame.ts +662 -158
  572. package/src/record/gpu-pass-timing/contract.ts +180 -0
  573. package/src/record/gpu-pass-timing/errors.ts +34 -0
  574. package/src/record/gpu-pass-timing/index.ts +37 -0
  575. package/src/record/gpu-pass-timing/parser.ts +97 -0
  576. package/src/record/gpu-pass-timing/session.ts +938 -0
  577. package/src/record/gpu-timing.ts +112 -39
  578. package/src/record/helpers.ts +0 -58
  579. package/src/record/main-pass-geometry.ts +324 -119
  580. package/src/record/main-pass-material.ts +103 -10
  581. package/src/record/main-pass-sprite-draws.ts +99 -103
  582. package/src/record/main-pass.ts +71 -15
  583. package/src/record/mesh-ssbo.ts +47 -36
  584. package/src/record/render-context.ts +136 -3
  585. package/src/record/shadow-pass.ts +83 -68
  586. package/src/record/skybox-post-pass.ts +20 -4
  587. package/src/record/typed-frame-graph.ts +1034 -43
  588. package/src/record/view-ubo.ts +72 -47
  589. package/src/reflection/filter.ts +81 -0
  590. package/src/reflection/gpu-table.ts +44 -0
  591. package/src/reflection/inspection.ts +67 -0
  592. package/src/reflection/projection.ts +476 -0
  593. package/src/reflection/record-owner.ts +1283 -0
  594. package/src/render-contract.ts +93 -10
  595. package/src/render-graph-primitives.ts +9 -4
  596. package/src/render-pipeline.ts +122 -2
  597. package/src/render-system-extract.ts +1041 -225
  598. package/src/render-system.ts +1310 -85
  599. package/src/renderer.ts +222 -0
  600. package/src/scene/__tests__/changed-block-summary.candidate.test.ts +36 -0
  601. package/src/scene/probe-blend-record.ts +54 -0
  602. package/src/scene/probe-blend.ts +813 -0
  603. package/src/scene/render-scene-types.ts +0 -7
  604. package/src/scene/render-scene.ts +942 -171
  605. package/src/scene/visibility/bounds.ts +57 -0
  606. package/src/scene/visibility/budget.ts +40 -0
  607. package/src/scene/visibility/facet.ts +400 -0
  608. package/src/scene/visibility/gpu-frame-timing.ts +101 -0
  609. package/src/scene/visibility/gpu-lod.ts +119 -0
  610. package/src/scene/visibility/inspection.ts +313 -0
  611. package/src/scene/visibility/lod-selector.ts +84 -0
  612. package/src/scene/visibility/occlusion-confidence.ts +478 -0
  613. package/src/scene/visibility/occlusion-pass.ts +165 -0
  614. package/src/scene/visibility/occlusion-query-pool.ts +178 -0
  615. package/src/scene/visibility/occlusion-runtime.ts +672 -0
  616. package/src/scene/visibility/types.ts +50 -0
  617. package/src/shadow-atlas.ts +5 -5
  618. package/src/ssao-buffers.ts +9 -2
  619. package/src/ssr/admission.ts +451 -0
  620. package/src/ssr/composition.ts +73 -0
  621. package/src/ssr/errors.ts +76 -0
  622. package/src/ssr/identity.ts +12 -0
  623. package/src/systems/skin-palette-allocator.ts +1 -1
  624. package/src/targets/contracts.ts +182 -0
  625. package/src/targets/graph-projection.ts +169 -0
  626. package/src/targets/material-source.ts +143 -0
  627. package/src/targets/owner.ts +214 -0
  628. package/src/targets/physical.ts +18 -0
  629. package/src/targets/readback.ts +153 -0
  630. package/src/temporal/frame-coordinator.ts +26 -0
  631. package/src/temporal/frame.ts +14 -1
  632. package/src/temporal/view.ts +11 -0
  633. package/src/tilemap-chunk-extract-system.ts +4 -4
  634. package/src/transmission/__tests__/standard-transmission.dawn.test.ts +59 -20
  635. package/src/typed-render-graph-primitives.ts +53 -3
  636. package/src/typed-shadow-passes.ts +46 -40
  637. package/src/volume/passes.ts +61 -58
  638. package/dist/.tsbuildinfo +0 -1
  639. package/dist/chunk-4XINDLAY.mjs.map +0 -1
  640. package/dist/chunk-CDTWTHZR.mjs.map +0 -1
  641. package/dist/chunk-M2MP4ZOU.mjs +0 -73
  642. package/dist/chunk-M2MP4ZOU.mjs.map +0 -1
  643. package/dist/chunk-PCHBPYML.mjs.map +0 -1
  644. package/dist/chunk-TBQJOK2L.mjs.map +0 -1
  645. package/dist/chunk-VFPLTKCU.mjs.map +0 -1
@@ -40,9 +40,16 @@ import {
40
40
  type SkylightBindGroupResources,
41
41
  type TransmissionBindGroupResources,
42
42
  } from '../ibl/skylight-bind-group';
43
+ import type { PipelineGroup2Contract } from '../pbr-pipeline';
43
44
  import { isStandardPbrMaterialShader } from '../pbr-pipeline';
44
45
  import { deriveTextureExtent } from '../render-data';
45
46
  import type { MaterialSnapshot } from '../render-system-extract';
47
+ import type { RenderTargetTextureSource } from '../targets/contracts';
48
+ import {
49
+ type RenderTargetMaterialSourceBinding,
50
+ resolveRenderTargetMaterialSource,
51
+ } from '../targets/material-source';
52
+ import type { StandardReflectionProbeBinding } from './frame-lighting';
46
53
  import type { BindGroupCounts, MaterialBgAssemblyCacheEntry } from './frame-snapshot';
47
54
  import { extractEntryResourceHandle, getOrCreatePerEntity } from './mesh-ssbo';
48
55
  import {
@@ -51,6 +58,23 @@ import {
51
58
  STANDARD_PBR_UBO_SIZE,
52
59
  } from './render-context';
53
60
 
61
+ /**
62
+ * Resolve the group(2) resource layout from the material shader contract.
63
+ * Standard clustered PBR consumes the unified cluster bind group; every other
64
+ * material consumes the ordinary mesh bind group. Missing ordinary resources
65
+ * remain missing so the caller can skip the draw rather than violate layout
66
+ * compatibility by binding a cluster group.
67
+ */
68
+ export function selectMaterialGroup2(
69
+ clusterGroup: BindGroup | null,
70
+ meshGroup: BindGroup | null,
71
+ group2Contract: PipelineGroup2Contract,
72
+ ): BindGroup | null {
73
+ if (group2Contract === 'cluster') return clusterGroup;
74
+ if (group2Contract === 'mesh') return meshGroup;
75
+ return null;
76
+ }
77
+
54
78
  // Param schemas are immutable runtime contracts: the shader registry installs
55
79
  // them once and material snapshots only retain the same array reference. Keep
56
80
  // the expensive pure derivation on that identity so the per-submesh record
@@ -412,6 +436,28 @@ const DEFAULT_STANDARD_TEXTURE_COORDINATES = new Float32Array([
412
436
  0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1,
413
437
  ]);
414
438
 
439
+ export interface StandardReflectionProbeMaterialProjection {
440
+ readonly probeIndex: number | undefined;
441
+ readonly fallbackToSkylight: boolean;
442
+ }
443
+
444
+ /** Keeps the fallback output as a same-pass, linear-HDR material projection. */
445
+ export function standardPbrFallbackDemand(
446
+ projection: StandardReflectionProbeMaterialProjection,
447
+ ): boolean {
448
+ return projection.probeIndex !== undefined || projection.fallbackToSkylight;
449
+ }
450
+
451
+ /** Projects the selected scene row into the Standard material lane. */
452
+ export function projectReflectionProbeMaterialBinding(
453
+ binding: StandardReflectionProbeBinding,
454
+ ): StandardReflectionProbeMaterialProjection {
455
+ return {
456
+ probeIndex: binding.probeIndex,
457
+ fallbackToSkylight: binding.useSkylight,
458
+ };
459
+ }
460
+
415
461
  /** Derives the logical-content UV scale for an uploaded material texture. */
416
462
  export function materialTextureUvScale(
417
463
  texture: Pick<TextureAsset, 'shape' | 'format'> | undefined,
@@ -433,6 +479,18 @@ function materialTextureForField(
433
479
  return material.textureHandles?.get(field);
434
480
  }
435
481
 
482
+ /** Resolve a renderer-local target source without entering AssetRegistry. */
483
+ export function materialRenderTargetSourceForField(
484
+ material: MaterialSnapshot,
485
+ field: string,
486
+ resolveSource?: RenderSystemRuntime['resolveRenderTargetTextureSource'],
487
+ ): RenderTargetMaterialSourceBinding | undefined {
488
+ const source = material.textureSources?.get(field) as RenderTargetTextureSource | undefined;
489
+ return source === undefined
490
+ ? undefined
491
+ : (resolveSource?.(source) ?? resolveRenderTargetMaterialSource(source));
492
+ }
493
+
436
494
  /**
437
495
  * Appends the engine-owned scale for every built-in material texture binding.
438
496
  * Asset dimensions remain logical; this is the sole record-stage projection
@@ -583,7 +641,15 @@ export function userRegionTextureFieldOrder(
583
641
  export function defaultViewForUserRegionField(
584
642
  field: string,
585
643
  pipelineState: PipelineState,
644
+ schema?: readonly ParamSchemaEntry[],
586
645
  ): TextureView {
646
+ const parameter = schema?.find((entry) => entry.name === field);
647
+ if (parameter?.type === 'texture_cube') {
648
+ // The renderer already owns a valid white cube for the Skylight fallback.
649
+ // Use it until a receipt-promoted RenderTarget source becomes available;
650
+ // binding a 2D view here would invalidate the custom cube material BGL.
651
+ return pipelineState.skylightFallback?.prefilterView ?? pipelineState.defaultWhiteTextureView;
652
+ }
587
653
  if (field === 'normalTexture') return pipelineState.defaultNormalTextureView;
588
654
  if (field === 'baseColorTexture') return pipelineState.fallbackTextureView;
589
655
  return pipelineState.defaultWhiteTextureView;
@@ -603,7 +669,7 @@ export function defaultViewForUserRegionField(
603
669
  * `renderableIndex` per RenderSystem lifetime via the `seenIndices` Set
604
670
  * (the same warn-once anchor pattern used for missing-texture sprites).
605
671
  *
606
- * @param transformWorld The entity's resolved Transform.world mat4 (16 floats column-major).
672
+ * @param transformWorld The entity's resolved GlobalTransform.world mat4 (16 floats column-major).
607
673
  * @param slices The four anchor distances `[left, top, right, bottom]`
608
674
  * (sentinel `bottom < 0` for tile mode is consumed via abs()).
609
675
  * @param renderableIndex The entity index into the validated renderables list.
@@ -885,6 +951,11 @@ export interface PerSubmeshMaterialBgDeps {
885
951
  readonly materialSlice: number;
886
952
  readonly videoHighPerfAvailable: boolean;
887
953
  readonly skylightResources: SkylightBindGroupResources;
954
+ readonly resolveRenderTargetTextureSource?: RenderSystemRuntime['resolveRenderTargetTextureSource'];
955
+ readonly resolveReflectionProbeResources?: (
956
+ materialWorld: World,
957
+ entityKey: number,
958
+ ) => SkylightBindGroupResources | undefined;
888
959
  readonly materialBgShared: Map<string, WeakMap<object, unknown>>;
889
960
  /** Cross-frame final BG reuse keyed by the stable source material handle. */
890
961
  readonly materialBgAssemblyCache: Map<string, MaterialBgAssemblyCacheEntry>;
@@ -932,11 +1003,15 @@ export function buildPerSubmeshMaterialBg(
932
1003
  materialSlice,
933
1004
  videoHighPerfAvailable,
934
1005
  skylightResources,
1006
+ resolveRenderTargetTextureSource,
1007
+ resolveReflectionProbeResources,
935
1008
  materialBgShared,
936
1009
  materialBgAssemblyCache,
937
1010
  transmissionBackdropView,
938
1011
  bindGroupCounts,
939
1012
  } = deps;
1013
+ const effectiveSkylightResources =
1014
+ resolveReflectionProbeResources?.(materialWorld, entityKey) ?? skylightResources;
940
1015
  const smMaterialHandle = submeshMaterial.materialHandle;
941
1016
  const materialCacheKey =
942
1017
  smMaterialHandle === undefined ? undefined : `${materialWorld.identity}:${smMaterialHandle}`;
@@ -955,7 +1030,7 @@ export function buildPerSubmeshMaterialBg(
955
1030
  submeshMaterial,
956
1031
  smMaterialBgl,
957
1032
  pipelineState.materialUniformBuffer.buffer,
958
- skylightResources,
1033
+ effectiveSkylightResources,
959
1034
  store.materialResourceEpoch,
960
1035
  transmissionBackdropView,
961
1036
  )
@@ -1003,11 +1078,25 @@ export function buildPerSubmeshMaterialBg(
1003
1078
  const textureBinding = samplerBinding + 1;
1004
1079
  let smView: TextureView =
1005
1080
  field !== undefined
1006
- ? defaultViewForUserRegionField(field, pipelineState)
1081
+ ? defaultViewForUserRegionField(field, pipelineState, smSchema)
1007
1082
  : pipelineState.defaultWhiteTextureView;
1008
1083
  const smVideoClip =
1009
1084
  field !== undefined ? submeshMaterial.videoTextureFields?.get(field) : undefined;
1010
- if (smVideoClip !== undefined) {
1085
+ const smTargetSource =
1086
+ field === undefined
1087
+ ? undefined
1088
+ : materialRenderTargetSourceForField(
1089
+ submeshMaterial,
1090
+ field,
1091
+ resolveRenderTargetTextureSource,
1092
+ );
1093
+ if (smTargetSource !== undefined) {
1094
+ // The Renderer host resolves the generation-checked physical view. A
1095
+ // candidate is never exposed here; until its matching FrameReceipt
1096
+ // completes, the material remains on the neutral fallback.
1097
+ if (smTargetSource.textureView !== undefined) smView = smTargetSource.textureView;
1098
+ else materialResourcesResident = false;
1099
+ } else if (smVideoClip !== undefined) {
1011
1100
  const view = videoTextureView(
1012
1101
  materialWorld,
1013
1102
  runtime.dynamicTextureStore,
@@ -1049,12 +1138,16 @@ export function buildPerSubmeshMaterialBg(
1049
1138
  // authored UV textures and is not a backdrop sampler.
1050
1139
  const transmissionSampler =
1051
1140
  transmissionBackdropView != null
1052
- ? skylightResources.prefilterSampler
1141
+ ? effectiveSkylightResources.prefilterSampler
1053
1142
  : pipelineState.defaultSampler;
1054
- const smMergedEntries = assembleMaterialWithSkylightEntries(smBaseEntries, skylightResources, {
1055
- sampler: transmissionSampler,
1056
- ...(transmissionBackdropView === undefined ? {} : { backdropView: transmissionBackdropView }),
1057
- } satisfies TransmissionBindGroupResources);
1143
+ const smMergedEntries = assembleMaterialWithSkylightEntries(
1144
+ smBaseEntries,
1145
+ effectiveSkylightResources,
1146
+ {
1147
+ sampler: transmissionSampler,
1148
+ ...(transmissionBackdropView === undefined ? {} : { backdropView: transmissionBackdropView }),
1149
+ } satisfies TransmissionBindGroupResources,
1150
+ );
1058
1151
  const createBindGroup = (): BindGroup => {
1059
1152
  const result = runtime.device.createBindGroup({
1060
1153
  label: 'pbr-material-skylight-bg',
@@ -1086,7 +1179,7 @@ export function buildPerSubmeshMaterialBg(
1086
1179
  materialResourceEpoch: store.materialResourceEpoch,
1087
1180
  materialBgl: smMaterialBgl,
1088
1181
  materialBuffer: pipelineState.materialUniformBuffer.buffer,
1089
- skylightResources,
1182
+ skylightResources: effectiveSkylightResources,
1090
1183
  bindGroup: smBindGroup,
1091
1184
  });
1092
1185
  }
@@ -25,18 +25,24 @@ import {
25
25
  } from '../ibl/skylight-bind-group';
26
26
  import type { InstanceBufferCacheEntry } from '../instance-buffer-cache';
27
27
  import { SPRITE_PREMULTIPLIED_ALPHA_BLEND } from '../materials';
28
- import { SPRITE_PASS_PER_INSTANCE_REGION_VARIANT_SET } from '../pbr-pipeline';
28
+ import {
29
+ isStandardPbrMaterialShader,
30
+ SPRITE_PASS_PER_INSTANCE_REGION_VARIANT_SET,
31
+ } from '../pbr-pipeline';
29
32
  import {
30
33
  buildBeginRenderPassDescriptor,
34
+ standardTopologyVariantSet,
31
35
  variantSetFromVertexLayoutProjection,
32
36
  } from '../pipeline-spec';
33
37
  import type { MaterialSnapshot, SpriteInstancesSnapshot } from '../render-system-extract';
34
38
  import { worldEntityKey } from './frame-snapshot';
39
+ import { resolveGeometryInstancesBindGroup, resolveProbeBlendBuffer } from './main-pass-geometry';
35
40
  import {
36
41
  BUILTIN_USER_REGION_TEXTURE_FIELDS,
37
42
  defaultViewForUserRegionField,
38
43
  entityHasTransparentSubmesh,
39
44
  residentTextureView,
45
+ selectMaterialGroup2,
40
46
  } from './main-pass-material';
41
47
  import {
42
48
  extractEntryResourceHandle,
@@ -208,8 +214,13 @@ export function recordSpritePass(
208
214
  ldrSpriteColorView,
209
215
  geometryDepthView,
210
216
  viewBindGroup,
217
+ meshBindGroup,
218
+ hdrpClusterBindGroup,
219
+ viewBindGroupDynamicOffset = 0,
211
220
  splitLdrSprite,
212
221
  } = c;
222
+ const clusteredLighting = c.standardLighting?.kind === 'clustered';
223
+ const meshGroup2 = clusteredLighting ? hdrpClusterBindGroup : meshBindGroup;
213
224
  // The split pass is also used by the no-tone linear-LDR route. That route
214
225
  // keeps transparent draws in the graph-owned rgba16float attachment, so
215
226
  // sprite shaders must use their linear/HDR fragment entry point even though
@@ -260,7 +271,7 @@ export function recordSpritePass(
260
271
  ) as never,
261
272
  );
262
273
 
263
- spritePass.setBindGroup(0, viewBindGroup as BindGroup, [0]);
274
+ spritePass.setBindGroup(0, viewBindGroup as BindGroup, [viewBindGroupDynamicOffset, 0]);
264
275
 
265
276
  // feat-20260625-refactor-sprite-as-transparent-mesh M3 / w14 (D-7):
266
277
  // sprite PSO resolution migrated from the dedicated boot-time PSO
@@ -376,7 +387,12 @@ export function recordSpritePass(
376
387
  spritePremulBlend,
377
388
  'triangle-list',
378
389
  undefined,
379
- undefined,
390
+ // sprite-lit declares the same Standard capability axes as PBR. The
391
+ // boot artifact is intentionally the direct compatibility variant,
392
+ // so a clustered frame must request its explicit Cluster artifact;
393
+ // otherwise the host binds the unified group(2) while the shader
394
+ // still reads the now-cleared direct-light headers.
395
+ standardTopologyVariantSet(c.standardLighting, runtime.device.caps.storageBuffer, false),
380
396
  'forward',
381
397
  undefined,
382
398
  msaaActive ? 4 : 1,
@@ -416,6 +432,7 @@ export function recordSpritePass(
416
432
  materialSlotIndices,
417
433
  sampleCount,
418
434
  resolveMaterialBindGroup,
435
+ meshGroup2,
419
436
  );
420
437
 
421
438
  if (graphPass === undefined) spritePass.end();
@@ -448,9 +465,9 @@ function recordSpriteTransparentPbrDraws(
448
465
  entityKey: number,
449
466
  materialWorld: World,
450
467
  ) => BindGroup,
468
+ meshGroup2: BindGroup | null,
451
469
  ): void {
452
- const { runtime, pipelineState, frameState, bindGroupCounts, validatedOrdered, meshBindGroup } =
453
- c;
470
+ const { runtime, pipelineState, validatedOrdered } = c;
454
471
  const isHdrTarget =
455
472
  c.tonemapActive || transparentPassColorFormat(c, pipelineState) === 'rgba16float';
456
473
  let lastPbrSubPipelineHandle: typeof pipelineState.unlitPipeline = null;
@@ -484,47 +501,6 @@ function recordSpriteTransparentPbrDraws(
484
501
  spritePass.setIndexBuffer(entry.mesh.indexBuffer.handle, entry.mesh.indexFormat);
485
502
  lastPbrSubIndexBuffer = entry.mesh.indexBuffer;
486
503
  }
487
- spritePass.setBindGroup(2, meshBindGroup as BindGroup, [i * MESH_PER_ENTITY_STRIDE]);
488
- // Identity instance BG (instanceCount=1); reuse the per-entity cache.
489
- const identityInstBg: BindGroup = getOrCreatePerEntity(
490
- frameState.instancesBgPerEntity,
491
- worldEntityKey(entry.source.worldId, entry.source.entityKey),
492
- [pipelineState.identityInstanceBuffer],
493
- 'instances',
494
- () => {
495
- const result = runtime.device.createBindGroup({
496
- label: 'pbr-transparent-sub-instances-bg',
497
- layout: pipelineState.instancesBindGroupLayout,
498
- entries: [
499
- {
500
- binding: 0,
501
- resource: {
502
- kind: 'buffer',
503
- value: { buffer: pipelineState.identityInstanceBuffer },
504
- },
505
- },
506
- ],
507
- });
508
- if (!result.ok) throw result.error;
509
- return result.value;
510
- },
511
- bindGroupCounts,
512
- );
513
- spritePass.setBindGroup(3, identityInstBg);
514
-
515
- const subVariantSet = frameState.isHdrpActive
516
- ? ''
517
- : 'CLUSTER_FORWARD_AVAILABLE=false+STORAGE_BUFFER_AVAILABLE=true';
518
- const projectionVariantSetResult = variantSetFromVertexLayoutProjection(
519
- entry.mesh.layoutProjection,
520
- subVariantSet,
521
- );
522
- if (!projectionVariantSetResult.ok) {
523
- runtime.errorRegistry.fire(projectionVariantSetResult.error);
524
- continue;
525
- }
526
- const projectionVariantSet = projectionVariantSetResult.value;
527
-
528
504
  for (let smIdx = 0; smIdx < entry.mesh.submeshes.length; smIdx++) {
529
505
  const sm = entry.mesh.submeshes[smIdx];
530
506
  if (sm === undefined) continue;
@@ -535,21 +511,41 @@ function recordSpriteTransparentPbrDraws(
535
511
  if (submeshMaterial.transparent !== true) continue;
536
512
  const smShaderId = submeshMaterial.materialShaderId;
537
513
  if (smShaderId === undefined) continue;
538
-
539
- // Bind the per-submesh material BG first (mirrors the geometry pass
540
- // order), then resolve the PSO; a first-frame async-compile miss skips
541
- // only the draw, not the BG (one transient frame, PSO flows in next).
542
- const materialSlot = materialSlotIndices[i]?.[matSlotIdx] ?? materialSlotIndices[i]?.[0] ?? 0;
543
- const subBg = resolveMaterialBindGroup(
544
- materialSlot,
545
- submeshMaterial,
546
- entry.source.entityKey,
547
- entry.world ?? c.world,
514
+ const probeBlendAvailable =
515
+ runtime.device.caps.storageBuffer &&
516
+ entry.source.probeBlendRecord !== undefined &&
517
+ isStandardPbrMaterialShader(smShaderId);
518
+ const probeBinding = probeBlendAvailable
519
+ ? resolveProbeBlendBuffer(
520
+ c,
521
+ entry.source.probeBlendRecord,
522
+ worldEntityKey(entry.source.worldId, entry.source.entityKey),
523
+ )
524
+ : undefined;
525
+ const identityInstBg = resolveGeometryInstancesBindGroup(
526
+ c,
527
+ pipelineState.identityInstanceBuffer,
528
+ probeBinding?.buffer,
548
529
  );
549
- spritePass.setBindGroup(1, subBg, [materialSlot * MATERIAL_PER_ENTITY_STRIDE]);
550
-
551
- const subPipeline =
552
- runtime.getMaterialShaderPipeline?.(
530
+ if (probeBinding === undefined) spritePass.setBindGroup(3, identityInstBg);
531
+ else spritePass.setBindGroup(3, identityInstBg, [probeBinding.offset]);
532
+ const subVariantSet = standardTopologyVariantSet(
533
+ c.standardLighting,
534
+ runtime.device.caps.storageBuffer,
535
+ entry.mesh.layoutProjection.attributes.some((attribute) => attribute.key === 'color'),
536
+ probeBlendAvailable,
537
+ );
538
+ const projectionVariantSetResult = variantSetFromVertexLayoutProjection(
539
+ entry.mesh.layoutProjection,
540
+ subVariantSet,
541
+ );
542
+ if (!projectionVariantSetResult.ok) {
543
+ runtime.errorRegistry.fire(projectionVariantSetResult.error);
544
+ continue;
545
+ }
546
+ const projectionVariantSet = projectionVariantSetResult.value;
547
+ const subPipelineEntry =
548
+ c.runtime.getMaterialShaderPipelineEntry?.(
553
549
  smShaderId,
554
550
  isHdrTarget,
555
551
  submeshMaterial.renderState,
@@ -566,7 +562,25 @@ function recordSpriteTransparentPbrDraws(
566
562
  undefined,
567
563
  entry.mesh.layoutProjection,
568
564
  ) ?? null;
569
- if (subPipeline === null) continue;
565
+ if (subPipelineEntry === null) continue;
566
+ const submeshContract = subPipelineEntry.group2Contract;
567
+ const submeshGroup2 = selectMaterialGroup2(meshGroup2, c.meshBindGroup, submeshContract);
568
+ if (submeshGroup2 === null) continue;
569
+ spritePass.setBindGroup(2, submeshGroup2, [i * MESH_PER_ENTITY_STRIDE]);
570
+
571
+ // Bind the per-submesh material BG first (mirrors the geometry pass
572
+ // order), then resolve the PSO; a first-frame async-compile miss skips
573
+ // only the draw, not the BG (one transient frame, PSO flows in next).
574
+ const materialSlot = materialSlotIndices[i]?.[matSlotIdx] ?? materialSlotIndices[i]?.[0] ?? 0;
575
+ const subBg = resolveMaterialBindGroup(
576
+ materialSlot,
577
+ submeshMaterial,
578
+ entry.source.entityKey,
579
+ entry.world ?? c.world,
580
+ );
581
+ spritePass.setBindGroup(1, subBg, [materialSlot * MATERIAL_PER_ENTITY_STRIDE]);
582
+
583
+ const subPipeline = subPipelineEntry.pipeline;
570
584
 
571
585
  if (lastPbrSubPipelineHandle !== subPipeline) {
572
586
  spritePass.setPipeline(subPipeline);
@@ -818,21 +832,15 @@ function recordSpriteEntityDraws(
818
832
  );
819
833
  spriteInstanceCount = spriteInst.instanceCount;
820
834
  spriteInstanceBuffer = pipelineState.identityInstanceBuffer;
821
- const spriteInstBgResult = runtime.device.createBindGroup({
822
- label: 'sprite-pass-instances-bg',
823
- layout: pipelineState.instancesBindGroupLayout,
824
- entries: [
825
- {
826
- binding: 0,
827
- resource: {
828
- kind: 'buffer',
829
- value: { buffer: spriteInstanceBuffer },
830
- },
831
- },
832
- ],
833
- });
834
- if (!spriteInstBgResult.ok) throw spriteInstBgResult.error;
835
- spritePass.setBindGroup(3, spriteInstBgResult.value as BindGroup);
835
+ // Sprite shaders do not declare the Standard PBR Probe ABI. A
836
+ // retained scene record must therefore not change their group(3)
837
+ // bind-group shape.
838
+ const spriteInstBg = resolveGeometryInstancesBindGroup(
839
+ c,
840
+ spriteInstanceBuffer,
841
+ undefined,
842
+ );
843
+ spritePass.setBindGroup(3, spriteInstBg);
836
844
  spritePass.drawIndexed(spriteEntry.mesh.indexCount, spriteInstanceCount, 0, 0, 0);
837
845
  continue;
838
846
  }
@@ -930,34 +938,22 @@ function recordSpriteEntityDraws(
930
938
  spriteInstanceBuffer = _si.buffer;
931
939
  spriteInstanceCount = _si.count;
932
940
 
933
- // M3 / w12: LDR sprite split pass per-entity instances BG cache.
934
- // Same pattern as #7.
935
- const spriteInstancesBg: BindGroup = getOrCreatePerEntity(
936
- frameState.instancesBgPerEntity,
937
- worldEntityKey(spriteEntry.source.worldId, spriteEntry.source.entityKey),
938
- [spriteInstanceBuffer],
939
- 'instances',
940
- () => {
941
- const result = runtime.device.createBindGroup({
942
- label: 'sprite-pass-instances-bg',
943
- layout: pipelineState.instancesBindGroupLayout,
944
- entries: [
945
- {
946
- binding: 0,
947
- resource: {
948
- kind: 'buffer',
949
- value: { buffer: spriteInstanceBuffer },
950
- },
951
- },
952
- ],
953
- });
954
- if (!result.ok) throw result.error;
955
- return result.value;
956
- },
957
- bindGroupCounts,
958
- );
941
+ // sprite-lit's clustered variant declares the unified Standard group(2)
942
+ // contract, while the regular sprite variants keep the direct mesh
943
+ // contract. Select the resource from the same capability axis used to
944
+ // request the pipeline; binding the ordinary mesh group to the clustered
945
+ // sprite-lit pipeline is rejected by WebGPU before the draw is recorded.
946
+ const spriteGroup2 =
947
+ entityShaderId === 'forgeax::sprite-lit' && c.standardLighting?.kind === 'clustered'
948
+ ? c.hdrpClusterBindGroup
949
+ : meshBindGroup;
950
+
951
+ // M3 / w12: LDR sprite split pass per-entity instances BG cache. Sprite
952
+ // shaders do not declare the Standard PBR Probe ABI, so retained probe
953
+ // records stay out of this bind-group path.
954
+ const spriteInstancesBg = resolveGeometryInstancesBindGroup(c, spriteInstanceBuffer, undefined);
959
955
 
960
- spritePass.setBindGroup(2, meshBindGroup as BindGroup, [i * MESH_PER_ENTITY_STRIDE]);
956
+ spritePass.setBindGroup(2, spriteGroup2 as BindGroup, [i * MESH_PER_ENTITY_STRIDE]);
961
957
 
962
958
  // Per-entity sprite material bind group: same standard PBR user-region
963
959
  // layout as in the geometry pass sprite branch + Skylight merged entries
@@ -9,10 +9,13 @@ import {
9
9
  import type { Handle, PassKind, PassSelector } from '@forgeax/engine-types';
10
10
  import { createHdrpUnifiedBindGroup, getOrCreateHdrpBuffers } from '../hdrp-buffers';
11
11
  import { getOrCreateIblCache } from '../ibl/IblPipelineCache';
12
- import { buildBeginRenderPassDescriptor } from '../pipeline-spec';
12
+ import type { SkylightBindGroupResources } from '../ibl/skylight-bind-group';
13
+ import { buildBeginRenderPassDescriptor, standardTopologyBindGroupReady } from '../pipeline-spec';
13
14
  import { POINTS_LINES_MATERIAL_SHADER_ID } from '../points-lines/record';
15
+ import type { ReflectionProbeSelectionResult } from '../reflection/projection';
14
16
  import type { RenderRecordPhase } from '../render-contract';
15
17
  import type { MaterialSnapshot } from '../render-system-extract';
18
+ import { resolveReflectionProbeBinding } from './frame-lighting';
16
19
  import { recordGeometryDraws } from './main-pass-geometry';
17
20
  import {
18
21
  applyMaterialTextureUvScales,
@@ -31,6 +34,12 @@ import {
31
34
  buildMatchedRenderableIndices,
32
35
  } from './shadow-pass';
33
36
 
37
+ export function standardReflectionProbeIndex(
38
+ selection: ReflectionProbeSelectionResult,
39
+ ): number | undefined {
40
+ return resolveReflectionProbeBinding(selection).probeIndex;
41
+ }
42
+
34
43
  const ZERO_SKYLIGHT_PAYLOAD = new Float32Array([0, 0, 0, 0, 0, 0, 0, 1]);
35
44
 
36
45
  export type MainPassOptions = {
@@ -114,6 +123,7 @@ export function recordMainPass(
114
123
  geometryDepthView,
115
124
  validatedOrdered,
116
125
  viewBindGroup,
126
+ viewBindGroupDynamicOffset = 0,
117
127
  meshBindGroup,
118
128
  frameState,
119
129
  bindGroupCounts,
@@ -161,14 +171,26 @@ export function recordMainPass(
161
171
  // copyExternalImageToTexture path (w16) is the sole route. The branch exists
162
172
  // so the AC-09 two-path reserved hook is code-review-verifiable, not a TODO.
163
173
  const videoHighPerfAvailable = probeVideoHighPerfUpload(runtime.device);
164
- // feat-20260609-hdrp-cluster-fragment-ggx M4 / w16: HDRP active swaps the
174
+ // The prepared Standard topology is the frame authority. Do not infer the
175
+ // shader lane from a resource that may be absent after a failed rebuild: a
176
+ // clustered frame with no unified group must fail closed, never fall back to
177
+ // a direct-lighting shader with an incompatible group(2) contract.
178
+ const clusteredLighting = c.standardLighting?.kind === 'clustered';
179
+ // A clustered topology still needs the unified group for every actual
180
+ // material draw. A camera-only/clear frame has no group(2) consumer yet;
181
+ // treating that harmless absence as a frame error would make the full
182
+ // clustered ABI incompatible with valid zero-renderable frames.
183
+ const clusteredBindGroupMissing =
184
+ validatedOrdered.length > 0 &&
185
+ !standardTopologyBindGroupReady(c.standardLighting, hdrpClusterBindGroup);
186
+ // Standard clustered lighting swaps the
165
187
  // group(2) bindGroup for the unified 7-entry layout (mesh SSBO at binding 0
166
188
  // + cluster 4 buffer at bindings 3..6). The dynamic offset
167
189
  // (`i * MESH_PER_ENTITY_STRIDE`) stays valid because the unified BGL binds
168
190
  // the SAME mesh SSBO at binding 0; the cluster-forward shader reads the
169
191
  // cluster bindings off the rest of the layout. Plan D-1 (URP path zero
170
- // change) is preserved — when `!isHdrpActive` the URP `meshBindGroup`
171
- // path runs verbatim.
192
+ // change) is preserved — when clustered lighting is not selected the
193
+ // ordinary mesh bind group path runs verbatim.
172
194
  // feat-20260612-hdrp-ssao wiring fix: when the HDRP forward pass resolved a
173
195
  // real `ssaoBlurred` view (stashed on ctx by the pass execute closure), build
174
196
  // the unified group(2) bind group with that view at binding 7 so fs_main reads
@@ -178,11 +200,7 @@ export function recordMainPass(
178
200
  // Built per frame (the SSAO target is a graph transient, so no cross-frame
179
201
  // cache); HDRP-only and SSAO-only, so URP and SSAO-off paths are untouched.
180
202
  let hdrpSsaoBindGroup: BindGroup | null = null;
181
- if (
182
- frameState.isHdrpActive &&
183
- hdrpClusterBindGroup !== null &&
184
- c.hdrpSsaoBlurredView !== undefined
185
- ) {
203
+ if (clusteredLighting && hdrpClusterBindGroup !== null && c.hdrpSsaoBlurredView !== undefined) {
186
204
  const hdrpBuffers = getOrCreateHdrpBuffers(
187
205
  runtime,
188
206
  frameState.installedPipelineConfig?.clusterGrid,
@@ -196,10 +214,9 @@ export function recordMainPass(
196
214
  );
197
215
  }
198
216
  }
199
- const meshGroup2: BindGroup | null =
200
- frameState.isHdrpActive && hdrpClusterBindGroup !== null
201
- ? (hdrpSsaoBindGroup ?? hdrpClusterBindGroup)
202
- : meshBindGroup;
217
+ const meshGroup2: BindGroup | null = clusteredLighting
218
+ ? (hdrpSsaoBindGroup ?? hdrpClusterBindGroup)
219
+ : meshBindGroup;
203
220
  // ── Geometry (main colour) pass ──────────────────────────────────
204
221
  // D-2: tracks whether the geometry pass was explicitly ended inside
205
222
  // the `if (validatedOrdered.length > 0)` block (sprite split path),
@@ -273,7 +290,17 @@ export function recordMainPass(
273
290
  })),
274
291
  };
275
292
 
276
- if (validatedOrdered.length > 0) {
293
+ if (clusteredBindGroupMissing) {
294
+ runtime.errorRegistry.fire(
295
+ new RhiError({
296
+ code: 'webgpu-runtime-error',
297
+ expected: 'clustered Standard frame has a unified group(2) BindGroup',
298
+ hint: 'repair the clustered buffer/layout admission before retrying the frame; direct URP fallback is unsafe',
299
+ }),
300
+ );
301
+ }
302
+
303
+ if (validatedOrdered.length > 0 && !clusteredBindGroupMissing) {
277
304
  // feat-20260518-pbr-direct-lighting-mvp M5 / w22.10 (D-4 + D-9 +
278
305
  // AC-07 std140): per-entity material slice grew from 32 B (legacy
279
306
  // baseColor:vec4 + metallic + roughness + 8B padding) to 48 B
@@ -432,6 +459,35 @@ export function recordMainPass(
432
459
  materialSlice: MATERIAL_SLICE,
433
460
  videoHighPerfAvailable,
434
461
  skylightResources,
462
+ resolveRenderTargetTextureSource: runtime.resolveRenderTargetTextureSource,
463
+ resolveReflectionProbeResources: (materialWorld, entityKey) => {
464
+ const reflectionProbes = c.reflectionProbes;
465
+ if (reflectionProbes === undefined) return undefined;
466
+ const selection = reflectionProbes.selections.get(`${materialWorld.identity}:${entityKey}`);
467
+ if (selection === undefined) return undefined;
468
+ const binding = resolveReflectionProbeBinding(selection, reflectionProbes.table);
469
+ if (binding.useSkylight || binding.probeIndex === undefined) return undefined;
470
+ const row = reflectionProbes.table.rows.find(
471
+ (candidate) => candidate.index === binding.probeIndex,
472
+ );
473
+ if (
474
+ row?.filteredView === undefined ||
475
+ row.sampler === undefined ||
476
+ row.uniformBuffer === undefined
477
+ ) {
478
+ return undefined;
479
+ }
480
+ const probeResources: SkylightBindGroupResources = {
481
+ irradianceView: skylightResources.irradianceView,
482
+ irradianceSampler: skylightResources.irradianceSampler,
483
+ prefilterView: row.filteredView,
484
+ prefilterSampler: row.sampler,
485
+ brdfLutView: skylightResources.brdfLutView,
486
+ brdfLutSampler: skylightResources.brdfLutSampler,
487
+ intensityBuffer: row.uniformBuffer,
488
+ };
489
+ return probeResources;
490
+ },
435
491
  materialBgShared: frameState.materialBgShared,
436
492
  materialBgAssemblyCache: c.materialBgAssemblyCache,
437
493
  bindGroupCounts,
@@ -614,7 +670,7 @@ export function recordMainPass(
614
670
  buildPerSubmeshMaterialBg(material, entityKey, materialWorld))
615
671
  : buildPerSubmeshMaterialBg(material, entityKey, materialWorld);
616
672
 
617
- pass.setBindGroup(0, viewBindGroup as BindGroup, [0]);
673
+ pass.setBindGroup(0, viewBindGroup as BindGroup, [viewBindGroupDynamicOffset, 0]);
618
674
 
619
675
  // Track which (mesh-vertex-buffer, mesh-index-buffer, pipeline) combo
620
676
  // was last bound so consecutive entities sharing the same combo skip