@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
@@ -17,12 +17,144 @@ export interface ResolvedMeshMaterialBinding {
17
17
  readonly source: MeshMaterialBindingSource;
18
18
  }
19
19
 
20
+ /** Lifecycle values projected from an already prepared resident binding. */
21
+ export type MeshMaterialBindingReadiness = 'ready' | 'pending' | 'failed' | 'last-known-good';
22
+
23
+ /** Structured producer failure retained by the renderer's bounded projection. */
24
+ export interface MeshMaterialBindingPreparationFailure {
25
+ readonly code: string;
26
+ readonly expected: string;
27
+ readonly hint: string;
28
+ readonly detail?: Readonly<Record<string, unknown>>;
29
+ }
30
+
31
+ export interface MeshMaterialBindingSamplerObservation {
32
+ readonly handle: number;
33
+ readonly resident: boolean;
34
+ }
35
+
36
+ export interface MeshMaterialBindingTextureObservation {
37
+ readonly handle: number;
38
+ readonly mipLevelCount: number;
39
+ }
40
+
41
+ /**
42
+ * One material-slot's bounded resident projection. The renderer reports only
43
+ * resources it actually resolved for the slot; Pack/AssetRegistry lifecycle
44
+ * records stay owned by the producer and are never copied here.
45
+ */
46
+ export interface MeshMaterialBindingResidency {
47
+ readonly readiness: MeshMaterialBindingReadiness;
48
+ readonly samplers: readonly MeshMaterialBindingSamplerObservation[];
49
+ readonly textures: readonly MeshMaterialBindingTextureObservation[];
50
+ readonly preparationFailure?: MeshMaterialBindingPreparationFailure;
51
+ }
52
+
20
53
  /** Public read-only observation of the bindings used by the last frame. */
21
54
  export interface MeshMaterialBindingObservation {
22
55
  readonly worldId: number;
23
56
  readonly entityKey: number;
24
57
  readonly bindings: readonly ResolvedMeshMaterialBinding[];
25
58
  readonly diagnostics: readonly MeshMaterialBindingDiagnostic[];
59
+ /** One resident projection per resolved material slot. */
60
+ readonly residency: readonly MeshMaterialBindingResidency[];
61
+ }
62
+
63
+ export interface MeshMaterialBindingSummary {
64
+ readonly total: number;
65
+ readonly ready: number;
66
+ readonly pending: number;
67
+ readonly failed: number;
68
+ readonly lastKnownGood: number;
69
+ readonly textureCount: number;
70
+ readonly samplerCount: number;
71
+ }
72
+
73
+ const EMPTY_RESIDENCY: MeshMaterialBindingResidency = Object.freeze({
74
+ readiness: 'pending',
75
+ samplers: Object.freeze([]),
76
+ textures: Object.freeze([]),
77
+ });
78
+
79
+ /**
80
+ * Build the sole renderer observation projection from the resident seam.
81
+ * Missing facts remain `pending`; they are never guessed from a URL, asset
82
+ * name, or authoring field. Slot cardinality is normalized so aggregation is
83
+ * deterministic even while a preparation candidate is incomplete.
84
+ */
85
+ export function projectMeshMaterialBindingObservation(input: {
86
+ readonly worldId: number;
87
+ readonly entityKey: number;
88
+ readonly bindings: readonly ResolvedMeshMaterialBinding[];
89
+ readonly diagnostics: readonly MeshMaterialBindingDiagnostic[];
90
+ readonly residency?: readonly MeshMaterialBindingResidency[];
91
+ }): MeshMaterialBindingObservation {
92
+ const residency = input.bindings.map((_, index) => {
93
+ const value = input.residency?.[index] ?? EMPTY_RESIDENCY;
94
+ return Object.freeze({
95
+ ...value,
96
+ samplers: Object.freeze(value.samplers.map((sampler) => Object.freeze({ ...sampler }))),
97
+ textures: Object.freeze(value.textures.map((texture) => Object.freeze({ ...texture }))),
98
+ ...(value.preparationFailure === undefined
99
+ ? {}
100
+ : {
101
+ preparationFailure: Object.freeze({
102
+ ...value.preparationFailure,
103
+ ...(value.preparationFailure.detail === undefined
104
+ ? {}
105
+ : { detail: Object.freeze({ ...value.preparationFailure.detail }) }),
106
+ }),
107
+ }),
108
+ });
109
+ });
110
+ return {
111
+ worldId: input.worldId,
112
+ entityKey: input.entityKey,
113
+ bindings: Object.freeze([...input.bindings]),
114
+ diagnostics: Object.freeze([...input.diagnostics]),
115
+ residency: Object.freeze(residency),
116
+ };
117
+ }
118
+
119
+ /** Recompute bounded readiness/resource counts from retained observations. */
120
+ export function summarizeMeshMaterialBindings(
121
+ observations: readonly MeshMaterialBindingObservation[],
122
+ ): MeshMaterialBindingSummary {
123
+ let ready = 0;
124
+ let pending = 0;
125
+ let failed = 0;
126
+ let lastKnownGood = 0;
127
+ let textureCount = 0;
128
+ let samplerCount = 0;
129
+ for (const observation of observations) {
130
+ for (const residency of observation.residency) {
131
+ switch (residency.readiness) {
132
+ case 'ready':
133
+ ready += 1;
134
+ break;
135
+ case 'pending':
136
+ pending += 1;
137
+ break;
138
+ case 'failed':
139
+ failed += 1;
140
+ break;
141
+ case 'last-known-good':
142
+ lastKnownGood += 1;
143
+ break;
144
+ }
145
+ textureCount += residency.textures.length;
146
+ samplerCount += residency.samplers.length;
147
+ }
148
+ }
149
+ return {
150
+ total: ready + pending + failed + lastKnownGood,
151
+ ready,
152
+ pending,
153
+ failed,
154
+ lastKnownGood,
155
+ textureCount,
156
+ samplerCount,
157
+ };
26
158
  }
27
159
 
28
160
  export type ResolveMeshMaterialBindingsResult =
@@ -25,11 +25,11 @@ import type {
25
25
  BindGroup,
26
26
  BindGroupEntry,
27
27
  BindGroupLayout,
28
- BindGroupLayoutDescriptor,
29
28
  Buffer,
30
29
  PipelineLayout,
31
30
  RhiDevice,
32
31
  Sampler,
32
+ TextureFormat,
33
33
  TextureView,
34
34
  } from '@forgeax/engine-rhi';
35
35
  import { DEFAULT_STANDARD_PBR_PARAM_SCHEMA, type ShaderCatalog } from '@forgeax/engine-shader';
@@ -72,6 +72,10 @@ export interface PbrPipelineLayoutBundle {
72
72
  readonly meshArrayBgl: BindGroupLayout;
73
73
  /** Per-instance storage BindGroupLayout (slot 3). */
74
74
  readonly instancesBgl: BindGroupLayout;
75
+ /** Probe-enabled slot-3 BGL; aliases `instancesBgl` when probes are unavailable. */
76
+ readonly probeInstancesBgl: BindGroupLayout;
77
+ /** Same pipeline layout with the probe-enabled slot-3 BGL, when supported. */
78
+ readonly probePipelineLayout: PipelineLayout | null;
75
79
  /**
76
80
  * Same 4 layouts in slot order. Useful for assertion sites that check the
77
81
  * pipeline-layout `bindGroupLayouts` array shape (t57 (a) + (d)).
@@ -84,6 +88,14 @@ export interface PbrPipelineLayoutBundle {
84
88
  ];
85
89
  }
86
90
 
91
+ /** Derives the Standard PBR attachment list without allocating a closed path. */
92
+ export function standardPbrColorFormats(
93
+ baseFormat: TextureFormat,
94
+ fallbackDemand: boolean,
95
+ ): readonly TextureFormat[] {
96
+ return fallbackDemand ? [baseFormat, 'rgba16float'] : [baseFormat];
97
+ }
98
+
87
99
  // ─── Base entries (round-4 SSOT) ────────────────────────────────────────────
88
100
 
89
101
  /**
@@ -325,14 +337,21 @@ export const INJECTION_KIND_LENGTHS = {
325
337
  */
326
338
  export interface PbrCaps {
327
339
  readonly storageBuffer: boolean;
340
+ /**
341
+ * Whether the selected material variant declares the optional extended
342
+ * lighting view resources. The default keeps the historical helper shape
343
+ * for callers that build the canonical full PBR layout; the renderer passes
344
+ * the device/variant decision explicitly.
345
+ */
346
+ readonly extendedLighting?: boolean;
347
+ /** Selects the optional binding(1) ProbeBlendRecord lane. */
348
+ readonly probeBlend?: boolean;
328
349
  /** Whether the device can carry the optional SpotLight projector texture. */
329
350
  readonly projectorAvailable?: boolean;
330
351
  }
331
352
 
332
353
  /**
333
354
  * The view BGL entry list. binding 0 = view UBO (vertex + fragment);
334
- * binding 1 = pointLights (storage or uniform, per caps);
335
- * binding 2 = spotLights (storage or uniform, per caps);
336
355
  * binding 3 = directional shadowMap atlas (texture_depth_2d, vertex+fragment).
337
356
  * feat-20260613-csm-cascaded-shadow-maps: this is the CSM atlas — N
338
357
  * cascades tiled into one 2D depth texture, sampled via per-cascade UV
@@ -372,27 +391,18 @@ export interface PbrCaps {
372
391
  * layout and consumed only by the dedicated points-lines shader).
373
392
  * Isolated here so M4 round-4 tests can recreate the layout.
374
393
  *
375
- * feat-20260526-pbr-uniform-fallback-no-storage-buffer M3 / w9:
376
- * caps.storageBuffer===false switches bindings 1+2 from
377
- * 'read-only-storage' to 'uniform'.
394
+ * Local lights are not part of the view group. Standard material variants
395
+ * consume the one Cluster payload in group(2), while this group retains only
396
+ * camera and shadow resources.
378
397
  */
379
398
  export function buildPbrViewBglEntries(caps: PbrCaps): GPUBindGroupLayoutEntry[] {
380
- const lightBufType: GPUBufferBindingType = caps.storageBuffer ? 'read-only-storage' : 'uniform';
381
399
  const entries: GPUBindGroupLayoutEntry[] = [
382
400
  {
383
401
  binding: 0,
384
402
  visibility: GPU_SHADER_STAGE_VERTEX | GPU_SHADER_STAGE_FRAGMENT,
385
- buffer: { type: 'uniform' },
386
- },
387
- {
388
- binding: 1,
389
- visibility: GPU_SHADER_STAGE_FRAGMENT,
390
- buffer: { type: lightBufType },
391
- },
392
- {
393
- binding: 2,
394
- visibility: GPU_SHADER_STAGE_FRAGMENT,
395
- buffer: { type: lightBufType },
403
+ // View captures use the same bind group with a per-face view slot.
404
+ // Keeping this dynamic is also valid for the display slot at offset 0.
405
+ buffer: { type: 'uniform', hasDynamicOffset: true },
396
406
  },
397
407
  {
398
408
  binding: 3,
@@ -420,9 +430,9 @@ export function buildPbrViewBglEntries(caps: PbrCaps): GPUBindGroupLayoutEntry[]
420
430
  // shadow-casting point light slot (shadowAtlasLayer in [0, 4)). Each
421
431
  // lane stores `(near, far, 1/(far-near), 0)` so the fragment-shader
422
432
  // depth-ref reconstruction (lighting-punctual.wgsl evalPointShadowed)
423
- // can avoid sampling LightSlot for the URP path. HDRP rides the same
424
- // constants on `LightSlot.kind_and_pad.zw` so binding 6 is unused on
425
- // HDRP shaders even though the BGL declares it (charter P4 single SSOT
433
+ // can avoid sampling DirectLightSlot for the URP path. The shared
434
+ // DirectLightSlot metadata remains the identity owner, so binding 6 is
435
+ // unused on HDRP shaders even though the BGL declares it (charter P4 single SSOT
426
436
  // BGL across pipelines; the HDRP variant simply doesn't reference the
427
437
  // binding in WGSL, which is allowed).
428
438
  {
@@ -472,12 +482,41 @@ export function buildPbrViewBglEntries(caps: PbrCaps): GPUBindGroupLayoutEntry[]
472
482
  texture: { sampleType: 'depth', viewDimension: '2d' },
473
483
  },
474
484
  ];
475
- // The projector is optional, but when present it is a sampled texture in
476
- // the fragment stage. Keep it out of the low-limit view layout so the
477
- // remaining HDRP PBR ABI stays within WebGPU's minimum 16 sampled textures.
478
- // The corresponding PROJECTOR_AVAILABLE shader variant is selected from
479
- // the same device capability bit and returns a white modulation.
480
- if (caps.projectorAvailable !== false) {
485
+ const extendedLighting = caps.extendedLighting ?? true;
486
+ if (extendedLighting) {
487
+ entries.push(
488
+ {
489
+ binding: 9,
490
+ visibility: GPU_SHADER_STAGE_FRAGMENT,
491
+ sampler: { type: 'filtering' },
492
+ },
493
+ {
494
+ binding: 11,
495
+ visibility: GPU_SHADER_STAGE_FRAGMENT,
496
+ texture: { sampleType: 'float', viewDimension: '2d-array' },
497
+ },
498
+ {
499
+ binding: 12,
500
+ visibility: GPU_SHADER_STAGE_FRAGMENT,
501
+ texture: { sampleType: 'float', viewDimension: '2d-array' },
502
+ },
503
+ {
504
+ binding: 13,
505
+ visibility: GPU_SHADER_STAGE_FRAGMENT,
506
+ texture: { sampleType: 'float', viewDimension: '2d' },
507
+ },
508
+ {
509
+ binding: 14,
510
+ visibility: GPU_SHADER_STAGE_FRAGMENT,
511
+ texture: { sampleType: 'float', viewDimension: '2d' },
512
+ },
513
+ {
514
+ binding: 15,
515
+ visibility: GPU_SHADER_STAGE_FRAGMENT,
516
+ buffer: { type: 'uniform' },
517
+ },
518
+ );
519
+ } else if (caps.projectorAvailable !== false) {
481
520
  entries.push(
482
521
  {
483
522
  binding: 11,
@@ -506,8 +545,8 @@ export function buildPbrViewBglEntries(caps: PbrCaps): GPUBindGroupLayoutEntry[]
506
545
  * material, mesh-array, instances]`; the material BGL is derived from the
507
546
  * standard material schema and engine injection chain.
508
547
  *
509
- * `caps.storageBuffer===false` switches every storage-buffer BGL entry
510
- * (view bindings 1+2, mesh-array, instances) to `uniform`.
548
+ * `caps.storageBuffer===false` switches the mesh-array and instances entries
549
+ * to `uniform`; local-light resources are never part of this view group.
511
550
  *
512
551
  * Throws on each `createBindGroupLayout` / `createPipelineLayout` Result
513
552
  * failure -- the engine bootstrap path (createRenderer) wraps the call in
@@ -543,9 +582,27 @@ export function buildPbrPipelineLayouts(
543
582
 
544
583
  // instances BGL.
545
584
  const instancesBglRes = device.createBindGroupLayout(
546
- buildBindGroupLayoutDescriptor(BGL_ONLY_SPEC_STUB, { kind: 'pbr-instances', caps }),
585
+ buildBindGroupLayoutDescriptor(BGL_ONLY_SPEC_STUB, {
586
+ kind: 'pbr-instances',
587
+ caps: { ...caps, probeBlend: false },
588
+ }),
547
589
  );
548
590
  if (!instancesBglRes.ok) throw instancesBglRes.error;
591
+ // ProbeBlendRecord is a storage-buffer-only ABI extension. A uniform
592
+ // fallback cannot afford the extra fragment-stage uniform binding on
593
+ // WebGL2/GLES, so do not even construct the probe BGL on that capability
594
+ // route. The record stage gates the matching variant and bind group with
595
+ // the same storage capability; aliasing the ordinary BGL keeps the bundle
596
+ // total and makes an accidental probe request fail closed at layout select.
597
+ const probeInstancesBglRes = caps.storageBuffer
598
+ ? device.createBindGroupLayout(
599
+ buildBindGroupLayoutDescriptor(BGL_ONLY_SPEC_STUB, {
600
+ kind: 'pbr-instances',
601
+ caps: { ...caps, probeBlend: true },
602
+ }),
603
+ )
604
+ : { ok: true as const, value: instancesBglRes.value };
605
+ if (!probeInstancesBglRes.ok) throw probeInstancesBglRes.error;
549
606
 
550
607
  // Pipeline layout (4 slots).
551
608
  const layouts: readonly [BindGroupLayout, BindGroupLayout, BindGroupLayout, BindGroupLayout] = [
@@ -559,6 +616,21 @@ export function buildPbrPipelineLayouts(
559
616
  bindGroupLayouts: layouts,
560
617
  });
561
618
  if (!pipelineLayoutRes.ok) throw pipelineLayoutRes.error;
619
+ const probeLayouts: readonly [
620
+ BindGroupLayout,
621
+ BindGroupLayout,
622
+ BindGroupLayout,
623
+ BindGroupLayout,
624
+ ] = [viewBglRes.value, materialBglRes.value, meshArrayBglRes.value, probeInstancesBglRes.value];
625
+ let probePipelineLayout: PipelineLayout | null = null;
626
+ if (caps.storageBuffer) {
627
+ const probePipelineLayoutRes = device.createPipelineLayout({
628
+ label: 'pbr-probe-pl',
629
+ bindGroupLayouts: probeLayouts,
630
+ });
631
+ if (!probePipelineLayoutRes.ok) throw probePipelineLayoutRes.error;
632
+ probePipelineLayout = probePipelineLayoutRes.value;
633
+ }
562
634
 
563
635
  return {
564
636
  pipelineLayout: pipelineLayoutRes.value,
@@ -566,6 +638,8 @@ export function buildPbrPipelineLayouts(
566
638
  materialBgl: materialBglRes.value,
567
639
  meshArrayBgl: meshArrayBglRes.value,
568
640
  instancesBgl: instancesBglRes.value,
641
+ probeInstancesBgl: probeInstancesBglRes.value,
642
+ probePipelineLayout,
569
643
  bindGroupLayouts: layouts,
570
644
  };
571
645
  }
@@ -600,6 +674,22 @@ export function isSkinnedShadowCasterVariant(
600
674
  );
601
675
  }
602
676
 
677
+ export type PipelineGroup2Contract = 'mesh' | 'skin' | 'cluster' | 'skin-cluster';
678
+
679
+ /** Resolve group(2) from the composed WGSL artifact used to build the PSO. */
680
+ export function resolvePipelineGroup2Contract(source: string): PipelineGroup2Contract {
681
+ const withoutComments = source.replace(/\/\*[\s\S]*?\*\//gu, '').replace(/\/\/.*$/gmu, '');
682
+ const bindings = [
683
+ ...withoutComments.matchAll(/@group\s*\(\s*2\s*\)\s*@binding\s*\(\s*(\d+)\s*\)/gu),
684
+ ].map((match) => Number(match[1]));
685
+ const hasSkinBindings = bindings.includes(1) || bindings.includes(2);
686
+ const hasClusterBindings = bindings.some((binding) => binding >= 3);
687
+ if (hasSkinBindings && hasClusterBindings) return 'skin-cluster';
688
+ if (hasSkinBindings) return 'skin';
689
+ if (hasClusterBindings) return 'cluster';
690
+ return 'mesh';
691
+ }
692
+
603
693
  /** Returns true for the engine-shipped standard-PBR material shader family. */
604
694
  export function isStandardPbrMaterialShader(shaderId: string | undefined): boolean {
605
695
  return (
@@ -631,9 +721,10 @@ export function isStandardPbrMaterialShader(shaderId: string | undefined): boole
631
721
 
632
722
  /**
633
723
  * Build the PBR skin pipeline layout (4 slots `[view, material,
634
- * mesh-array(2-entry), instances]`). View / material / instances BGLs are
724
+ * mesh-array(3-entry), instances]`). View / material / instances BGLs are
635
725
  * shared with the standard-PBR layout (passed in via `pbr` bundle); the only
636
- * new BGL is the 2-entry mesh-array slot for `meshes` + `palette`.
726
+ * new BGL is the 3-entry mesh-array slot for `meshes` + current/previous
727
+ * `palette` buffers.
637
728
  *
638
729
  * Throws on each `createBindGroupLayout` / `createPipelineLayout` Result
639
730
  * failure -- the engine bootstrap path wraps the call in `runShimSyncStep`
@@ -644,8 +735,9 @@ export function buildPbrSkinLayouts(
644
735
  caps: PbrCaps,
645
736
  pbr: PbrPipelineLayoutBundle,
646
737
  ): PbrPipelineLayoutBundle {
647
- // 2-entry mesh-array BGL: binding 0 meshes + binding 1 palette. Both
648
- // dynamic-offset (palette window per-entity, like meshes window).
738
+ // 3-entry mesh-array BGL: binding 0 meshes + binding 1 current palette
739
+ // + binding 2 previous palette. All use dynamic offsets for the same
740
+ // per-entity window contract.
649
741
  const skinMeshArrayBglRes = device.createBindGroupLayout(
650
742
  buildBindGroupLayoutDescriptor(BGL_ONLY_SPEC_STUB, {
651
743
  kind: 'pbr-skin-mesh-array',
@@ -665,6 +757,21 @@ export function buildPbrSkinLayouts(
665
757
  bindGroupLayouts: layouts,
666
758
  });
667
759
  if (!pipelineLayoutRes.ok) throw pipelineLayoutRes.error;
760
+ const probeLayouts: readonly [
761
+ BindGroupLayout,
762
+ BindGroupLayout,
763
+ BindGroupLayout,
764
+ BindGroupLayout,
765
+ ] = [pbr.viewBgl, pbr.materialBgl, skinMeshArrayBglRes.value, pbr.probeInstancesBgl];
766
+ let probePipelineLayout: PipelineLayout | null = null;
767
+ if (caps.storageBuffer) {
768
+ const probePipelineLayoutRes = device.createPipelineLayout({
769
+ label: 'pbr-skin-probe-pl',
770
+ bindGroupLayouts: probeLayouts,
771
+ });
772
+ if (!probePipelineLayoutRes.ok) throw probePipelineLayoutRes.error;
773
+ probePipelineLayout = probePipelineLayoutRes.value;
774
+ }
668
775
 
669
776
  return {
670
777
  pipelineLayout: pipelineLayoutRes.value,
@@ -672,10 +779,46 @@ export function buildPbrSkinLayouts(
672
779
  materialBgl: pbr.materialBgl,
673
780
  meshArrayBgl: skinMeshArrayBglRes.value,
674
781
  instancesBgl: pbr.instancesBgl,
782
+ probeInstancesBgl: pbr.probeInstancesBgl,
783
+ probePipelineLayout,
675
784
  bindGroupLayouts: layouts,
676
785
  };
677
786
  }
678
787
 
788
+ /** Project the canonical group(2) resources for a PBR skin draw. */
789
+ export function createPbrSkinMeshBindGroupEntries(
790
+ meshBuffer: Buffer,
791
+ meshSize: number,
792
+ paletteBuffer: Buffer,
793
+ paletteWindowBytes: number,
794
+ ): BindGroupEntry[] {
795
+ return [
796
+ {
797
+ binding: 0,
798
+ resource: { kind: 'buffer', value: { buffer: meshBuffer, offset: 0, size: meshSize } },
799
+ },
800
+ ...[1, 2].map((binding) => ({
801
+ binding,
802
+ resource: {
803
+ kind: 'buffer' as const,
804
+ value: {
805
+ buffer: paletteBuffer,
806
+ offset: 0,
807
+ size: paletteWindowBytes,
808
+ },
809
+ },
810
+ })),
811
+ ];
812
+ }
813
+
814
+ /** Project all dynamic offsets for the canonical PBR skin group(2) shape. */
815
+ export function pbrSkinMeshDynamicOffsets(
816
+ meshOffset: number,
817
+ paletteOffset: number,
818
+ ): readonly [number, number, number] {
819
+ return [meshOffset, paletteOffset, paletteOffset];
820
+ }
821
+
679
822
  // ─── Unlit material BGL factory ─────────────────────────────────────────────
680
823
 
681
824
  /**
@@ -763,7 +906,7 @@ export type { BindGroup };
763
906
  // existing behaviour (plan-strategy D-4 "pbr / unlit / sprite-atlas
764
907
  // behaviour unchanged" / requirements Edge Cases).
765
908
  //
766
- // Variant set string format mirrors the existing `URP_PBR_VARIANT_SET` /
909
+ // Variant set string format mirrors the Standard boot variant /
767
910
  // HDRP variant set string idiom in `pipeline-spec.ts` (`+`-separated kv
768
911
  // pairs); the record stage threads this string through the per-shader
769
912
  // pipeline-cache key + lazy-build `getMaterialShaderPipeline` lookup.
@@ -806,13 +949,14 @@ export const SPRITE_PASS_PER_INSTANCE_REGION_VARIANT_SET = '';
806
949
  * - `'unlit-material'` — 7 entries: base PBR material only (no inject)
807
950
  * - `'hdrp-7-slot'` — 7 entries (binding 0 + 3..8): HDRP cluster + SSAO group(2) BGL
808
951
  * 2. Caps-driven literal shapes (no shader):
809
- * - `'pbr-view'` — 12 entries: view UBO + lights + shadow bindings,
810
- * projector texture/sampler (11/12), and the Points/Lines UBO (10)
952
+ * - `'pbr-view'` — camera/shadow bindings, optional projector
953
+ * texture/sampler (11/12), and the Points/Lines UBO (10). Local lights
954
+ * are carried exclusively by the Standard Cluster group(2).
811
955
  * (directional 3/4, point 5/6, cascade 7, spot atlas 8; the former
812
956
  * spot lightViewProj matrices moved into the View UBO)
813
957
  * - `'pbr-mesh-array'` — 1 entry: per-entity mesh SSBO (dynamic-offset)
814
958
  * - `'pbr-instances'` — 1 entry: per-instance SSBO (no dynamic-offset)
815
- * - `'pbr-skin-mesh-array'` — 2 entries: meshes + skin palette
959
+ * - `'pbr-skin-mesh-array'` — 3 entries: meshes + current/previous palette
816
960
  * 3. Attachment-driven (fullscreen post-process):
817
961
  * - `'fullscreen-post'` — 2 entries: input texture + sampler. The texture
818
962
  * `sampleType` is derived from `spec.attachments` (plan §R3 fix):
@@ -855,17 +999,20 @@ export interface BindGroupLayoutDescriptorOutput {
855
999
  }
856
1000
 
857
1001
  /** Build the canonical HDRP group(2) bind-group layout. */
858
- export function createHdrpBindGroupLayoutDescriptor(
859
- storageBuffer: boolean = true,
860
- ): BindGroupLayoutDescriptor {
861
- const meshBufType: GPUBufferBindingType = storageBuffer ? 'read-only-storage' : 'uniform';
862
- const clusterBufType: GPUBufferBindingType = storageBuffer ? 'read-only-storage' : 'uniform';
1002
+ export function createHdrpBindGroupLayoutDescriptor(): BindGroupLayoutDescriptorOutput {
1003
+ const meshBufType: GPUBufferBindingType = 'read-only-storage';
1004
+ const clusterBufType: GPUBufferBindingType = 'read-only-storage';
863
1005
  return {
864
1006
  label: 'hdrp-unified-bgl-group2',
865
1007
  entries: [
866
1008
  {
867
1009
  binding: 0,
868
- visibility: GPU_SHADER_STAGE_VERTEX,
1010
+ // Standard fragment lighting (transmission/refraction and clustered
1011
+ // evaluation) reads the same mesh transform window as the vertex
1012
+ // stage. Keep this visibility in the HDRP descriptor aligned with
1013
+ // the URP mesh-array descriptor; restricting it to vertex makes the
1014
+ // HDRP pipeline invalid when fs_main accesses `meshes[0]`.
1015
+ visibility: GPU_SHADER_STAGE_VERTEX | GPU_SHADER_STAGE_FRAGMENT,
869
1016
  buffer: { type: meshBufType, hasDynamicOffset: true },
870
1017
  },
871
1018
  // Bindings 1 and 2 stay absent for the URP physical isolation gap.
@@ -903,6 +1050,33 @@ export function createHdrpBindGroupLayoutDescriptor(
903
1050
  };
904
1051
  }
905
1052
 
1053
+ /** Build the HDRP group(2) layout for the clustered skin variant. */
1054
+ export function createHdrpSkinBindGroupLayoutDescriptor(): BindGroupLayoutDescriptorOutput {
1055
+ const base = createHdrpBindGroupLayoutDescriptor();
1056
+ const baseEntries = base.entries;
1057
+ if (baseEntries === undefined || baseEntries[0] === undefined) {
1058
+ throw new Error('HDRP base group(2) layout must declare mesh binding 0');
1059
+ }
1060
+ const paletteType: GPUBufferBindingType = 'read-only-storage';
1061
+ return {
1062
+ label: 'hdrp-skin-unified-bgl-group2',
1063
+ entries: [
1064
+ baseEntries[0],
1065
+ {
1066
+ binding: 1,
1067
+ visibility: GPU_SHADER_STAGE_VERTEX,
1068
+ buffer: { type: paletteType, hasDynamicOffset: true },
1069
+ },
1070
+ {
1071
+ binding: 2,
1072
+ visibility: GPU_SHADER_STAGE_VERTEX,
1073
+ buffer: { type: paletteType, hasDynamicOffset: true },
1074
+ },
1075
+ ...baseEntries.slice(1),
1076
+ ],
1077
+ };
1078
+ }
1079
+
906
1080
  /**
907
1081
  * Build a `GPUBindGroupLayoutDescriptor` from a PipelineSpec, dispatching on
908
1082
  * `options.kind` to one of 9 closed BGL shapes (D-13 round-2).
@@ -1004,19 +1178,35 @@ export function buildBindGroupLayoutDescriptor(
1004
1178
  const meshBufType: GPUBufferBindingType = caps.storageBuffer
1005
1179
  ? 'read-only-storage'
1006
1180
  : 'uniform';
1181
+ const entries: GPUBindGroupLayoutEntry[] = [
1182
+ {
1183
+ binding: 0,
1184
+ visibility: GPU_SHADER_STAGE_VERTEX,
1185
+ buffer: { type: meshBufType, hasDynamicOffset: false },
1186
+ },
1187
+ ...(caps.probeBlend === true
1188
+ ? [
1189
+ {
1190
+ // Per-object fragment lane; the record is always exactly 160B.
1191
+ binding: 1,
1192
+ visibility: GPU_SHADER_STAGE_FRAGMENT,
1193
+ buffer: { type: meshBufType, hasDynamicOffset: true },
1194
+ },
1195
+ ]
1196
+ : []),
1197
+ ];
1007
1198
  return {
1008
- label: 'pbr-instances-bgl',
1009
- entries: [
1010
- {
1011
- binding: 0,
1012
- // Standard transmission reads the same per-instance transform in
1013
- // fs_main to convert glTF unit-space thickness into world metres.
1014
- // Keep one shared instances BGL and widen its visibility instead
1015
- // of introducing a second transform upload or six new varyings.
1016
- visibility: GPU_SHADER_STAGE_VERTEX | GPU_SHADER_STAGE_FRAGMENT,
1017
- buffer: { type: meshBufType, hasDynamicOffset: false },
1018
- },
1019
- ],
1199
+ label: caps.probeBlend === true ? 'pbr-probe-instances-bgl' : 'pbr-instances-bgl',
1200
+ entries: entries.map((entry) =>
1201
+ entry.binding === 0
1202
+ ? {
1203
+ ...entry,
1204
+ // Standard transmission reads the same per-instance transform in
1205
+ // fs_main to convert glTF unit-space thickness into world metres.
1206
+ visibility: GPU_SHADER_STAGE_VERTEX | GPU_SHADER_STAGE_FRAGMENT,
1207
+ }
1208
+ : entry,
1209
+ ),
1020
1210
  };
1021
1211
  }
1022
1212
  case 'pbr-skin-mesh-array': {
@@ -1037,6 +1227,11 @@ export function buildBindGroupLayoutDescriptor(
1037
1227
  visibility: GPU_SHADER_STAGE_VERTEX,
1038
1228
  buffer: { type: meshBufType, hasDynamicOffset: true },
1039
1229
  },
1230
+ {
1231
+ binding: 2,
1232
+ visibility: GPU_SHADER_STAGE_VERTEX,
1233
+ buffer: { type: meshBufType, hasDynamicOffset: true },
1234
+ },
1040
1235
  ],
1041
1236
  };
1042
1237
  }
@@ -1068,10 +1263,10 @@ export function buildBindGroupLayoutDescriptor(
1068
1263
  };
1069
1264
  }
1070
1265
  case 'hdrp-7-slot': {
1071
- // HDRP unified BGL for group(2): 9 entries (binding 0 + 3..8). The
1072
- // shape depends on caps.storageBuffer for the cluster-buffer fallback.
1073
- const caps = options.caps ?? { storageBuffer: true };
1074
- const desc = createHdrpBindGroupLayoutDescriptor(caps.storageBuffer);
1266
+ // Standard unified BGL for group(2): 9 entries (binding 0 + 3..8).
1267
+ // Cluster variants are admitted only when storage buffers are present;
1268
+ // there is no uniform-backed cluster shape.
1269
+ const desc = createHdrpBindGroupLayoutDescriptor();
1075
1270
  return {
1076
1271
  label: desc.label ?? 'hdrp-unified-bgl-group2',
1077
1272
  entries: [...(desc.entries ?? [])],