@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,19 +17,36 @@ import {
17
17
  GPU_BUFFER_USAGE_STORAGE,
18
18
  GPU_BUFFER_USAGE_UNIFORM,
19
19
  } from '../gpu-usage';
20
+ import { createHdrpSkinUnifiedBindGroup, getOrCreateHdrpBuffers } from '../hdrp-buffers';
20
21
  import type { InstanceBufferCacheEntry } from '../instance-buffer-cache';
21
22
  import { SPRITE_PREMULTIPLIED_ALPHA_BLEND } from '../materials';
22
- import { SKIN_MATERIAL_SHADER_ID } from '../pbr-pipeline';
23
- import { renderStateHash, variantSetFromVertexLayoutProjection } from '../pipeline-spec';
23
+ import {
24
+ createPbrSkinMeshBindGroupEntries,
25
+ isStandardPbrMaterialShader,
26
+ pbrSkinMeshDynamicOffsets,
27
+ SKIN_MATERIAL_SHADER_ID,
28
+ } from '../pbr-pipeline';
29
+ import {
30
+ renderStateHash,
31
+ standardStorageVariantSet,
32
+ standardTopologyVariantSet,
33
+ variantSetFromVertexLayoutProjection,
34
+ } from '../pipeline-spec';
24
35
  import type { PointsLinesRecordPlan } from '../points-lines/record';
25
36
  import { POINTS_LINES_MATERIAL_SHADER_ID } from '../points-lines/record';
26
37
  import type { RenderRecordPhase } from '../render-contract';
27
38
  import type { MaterialSnapshot } from '../render-system-extract';
39
+ import {
40
+ PROBE_BLEND_RECORD_BYTE_SIZE,
41
+ PROBE_BLEND_RECORD_STRIDE,
42
+ probeBlendRecordOffset,
43
+ } from '../scene/probe-blend-record';
28
44
  import { worldEntityKey } from './frame-snapshot';
29
45
  import {
30
46
  geometryRenderStateForTopology,
31
47
  isEntityFullyTransparent,
32
48
  selectGeometryPipeline,
49
+ selectMaterialGroup2,
33
50
  } from './main-pass-material';
34
51
  import {
35
52
  getOrCreateFromChain,
@@ -40,19 +57,22 @@ import {
40
57
  MESH_UBO_FULL_ARRAY_BYTES,
41
58
  packInstanceStorageBuffer,
42
59
  } from './mesh-ssbo';
43
- import type { _InternalRenderPipelineContext } from './render-context';
60
+ import type { _InternalRenderPipelineContext, MaterialShaderPipelineEntry } from './render-context';
44
61
  import { MATERIAL_PER_ENTITY_STRIDE } from './render-context';
45
62
  import { POINTS_LINES_VIEW_SLOT_STRIDE, writePointsLinesViewUbo } from './view-ubo';
46
63
 
47
64
  type GeometryInstanceDraw = {
48
65
  readonly instanceBuffer: Buffer;
49
66
  readonly instanceBindGroup: BindGroup;
67
+ /** -1 means the no-probe layout and therefore no dynamic offset. */
68
+ readonly probeOffset: number;
50
69
  readonly instanceCount: number;
51
70
  };
52
71
 
53
72
  type GeometryBindingState = {
54
73
  pipeline: RenderPipeline | null;
55
74
  instancesBuffer: Buffer | null;
75
+ probeOffset: number;
56
76
  };
57
77
 
58
78
  type MaterialPipelineLookup = {
@@ -66,7 +86,8 @@ type MaterialPipelineLookup = {
66
86
  readonly layoutProjection: import('@forgeax/engine-geometry').VertexLayoutProjection;
67
87
  readonly sampleCount: number;
68
88
  readonly colorFormatOverride: GPUTextureFormat | undefined;
69
- readonly handle: RenderPipeline | null;
89
+ readonly additionalColorFormats: readonly GPUTextureFormat[] | undefined;
90
+ readonly handle: MaterialShaderPipelineEntry | null;
70
91
  };
71
92
 
72
93
  type GeometryRecordProfileSegment = 'material-bind-groups' | 'pipeline-selection' | 'draw-submit';
@@ -127,9 +148,17 @@ function submitSubmeshDraws(
127
148
  state.pipeline = pipeline;
128
149
  }
129
150
  for (const instanceDraw of instanceDraws) {
130
- if (instanceDraw.instanceBuffer !== state.instancesBuffer) {
131
- pass.setBindGroup(3, instanceDraw.instanceBindGroup);
151
+ if (
152
+ instanceDraw.instanceBuffer !== state.instancesBuffer ||
153
+ instanceDraw.probeOffset !== state.probeOffset
154
+ ) {
155
+ if (instanceDraw.probeOffset < 0) {
156
+ pass.setBindGroup(3, instanceDraw.instanceBindGroup);
157
+ } else {
158
+ pass.setBindGroup(3, instanceDraw.instanceBindGroup, [instanceDraw.probeOffset]);
159
+ }
132
160
  state.instancesBuffer = instanceDraw.instanceBuffer;
161
+ state.probeOffset = instanceDraw.probeOffset;
133
162
  }
134
163
  if (indexed) {
135
164
  pass.drawIndexed(indexCount, instanceDraw.instanceCount, indexOffset, 0, 0);
@@ -197,8 +226,13 @@ export function recordGeometryDraws(
197
226
  validatedOrdered,
198
227
  splitLdrSprite,
199
228
  viewBindGroup,
229
+ viewBindGroupDynamicOffset = 0,
200
230
  } = c;
201
231
  const colorFormatOverride = c.transparentColorFormat as GPUTextureFormat | undefined;
232
+ // The prepared Standard topology is the frame authority. A bind-group
233
+ // identity is only a resource result; using it to infer the shader lane
234
+ // would silently fall back to URP when the clustered resource is missing.
235
+ const clusteredLighting = c.standardLighting?.kind === 'clustered';
202
236
  // A no-tone frame may still render into the graph-owned rgba16float target
203
237
  // (the linear-LDR route). Shader variants must follow the attachment's
204
238
  // numeric domain rather than the camera's tone-map switch, otherwise the
@@ -210,19 +244,20 @@ export function recordGeometryDraws(
210
244
  const bindingState: GeometryBindingState = {
211
245
  pipeline: null,
212
246
  instancesBuffer: null,
247
+ probeOffset: -1,
213
248
  };
214
249
  const identityInstanceBuffer = pipelineState.identityInstanceBuffer;
215
250
  const identityInstanceDraws: readonly GeometryInstanceDraw[] = [
216
251
  {
217
252
  instanceBuffer: identityInstanceBuffer,
218
- instanceBindGroup: resolveGeometryInstancesBindGroup(c, identityInstanceBuffer),
253
+ instanceBindGroup: resolveGeometryInstancesBindGroup(c, identityInstanceBuffer, undefined),
254
+ probeOffset: -1,
219
255
  instanceCount: 1,
220
256
  },
221
257
  ];
222
258
  const profilePhase = c.profilePhase;
223
259
  const materialGroup1DynamicOffsets = new Uint32Array(1);
224
260
  const meshGroup2DynamicOffsets = [0];
225
- const skinGroup2DynamicOffsets = [0, 0];
226
261
  let lastStencilReference: number | null = null;
227
262
  // feat-20260625-refactor-sprite-as-transparent-mesh M3 / w14 (D-7):
228
263
  // sprite PSO selection no longer maintains a dedicated tag — the
@@ -238,6 +273,9 @@ export function recordGeometryDraws(
238
273
  // renderer's authoritative cache still owns lifetime/invalidation, while
239
274
  // this frame-local table removes the hot call/lookup overhead.
240
275
  const materialPipelineLookupCache = new Map<string, Map<string, MaterialPipelineLookup[]>>();
276
+ const recordOcclusionCandidate = (draw: () => void): void => {
277
+ draw();
278
+ };
241
279
  const resolveMaterialPipeline = (
242
280
  materialShaderId: string,
243
281
  renderState: MaterialSnapshot['renderState'],
@@ -246,7 +284,20 @@ export function recordGeometryDraws(
246
284
  variantSet: string | undefined,
247
285
  colorFormat: GPUTextureFormat | undefined,
248
286
  layoutProjection: import('@forgeax/engine-geometry').VertexLayoutProjection,
249
- ): RenderPipeline | null => {
287
+ ): MaterialShaderPipelineEntry | null => {
288
+ // The fallback MRT is an extension of the built-in Standard PBR output
289
+ // contract only. The render pass may carry a second attachment whenever
290
+ // another renderable needs S_fallback, but shaders such as unlit, sprite,
291
+ // and the skin PBR variant still expose only @location(0). Passing that
292
+ // attachment into their PSO would make WebGPU reject the pipeline before
293
+ // the first draw ("Color target has no corresponding fragment stage
294
+ // output"). Keep the graph attachment shared while deriving pipeline
295
+ // targets from the shader's actual output contract.
296
+ const reflectionFallbackFormats =
297
+ materialShaderId === 'forgeax::default-standard-pbr' &&
298
+ c.reflectionFallbackColorFormat !== undefined
299
+ ? [c.reflectionFallbackColorFormat]
300
+ : undefined;
250
301
  const renderStateKey = renderStateHash(renderState);
251
302
  const shaderLookupCache = materialPipelineLookupCache.get(materialShaderId);
252
303
  const cachedLookups = shaderLookupCache?.get(renderStateKey);
@@ -261,7 +312,8 @@ export function recordGeometryDraws(
261
312
  cached.passKind === passKind &&
262
313
  cached.layoutProjection.digest === layoutProjection.digest &&
263
314
  cached.sampleCount === sampleCount &&
264
- cached.colorFormatOverride === colorFormat
315
+ cached.colorFormatOverride === colorFormat &&
316
+ cached.additionalColorFormats?.join(',') === reflectionFallbackFormats?.join(',')
265
317
  ) {
266
318
  return cached.handle;
267
319
  }
@@ -277,14 +329,20 @@ export function recordGeometryDraws(
277
329
  return null;
278
330
  }
279
331
  const resolvedVariantSet = resolvedVariantSetResult.value;
332
+ const fallbackVariantSet =
333
+ materialShaderId !== 'forgeax::default-standard-pbr'
334
+ ? resolvedVariantSet
335
+ : c.reflectionFallbackColorFormat !== undefined && resolvedVariantSet === ''
336
+ ? ''
337
+ : `${resolvedVariantSet === undefined || resolvedVariantSet === '' ? '' : `${resolvedVariantSet}+`}REFLECTION_FALLBACK_AVAILABLE=${c.reflectionFallbackColorFormat !== undefined}`;
280
338
  const resolvePipeline = () =>
281
- runtime.getMaterialShaderPipeline?.(
339
+ runtime.getMaterialShaderPipelineEntry?.(
282
340
  materialShaderId,
283
341
  isHdrTarget,
284
342
  renderState,
285
343
  topology,
286
344
  indexFormat,
287
- resolvedVariantSet,
345
+ fallbackVariantSet,
288
346
  passKind,
289
347
  undefined,
290
348
  sampleCount,
@@ -293,6 +351,9 @@ export function recordGeometryDraws(
293
351
  undefined,
294
352
  undefined,
295
353
  layoutProjection,
354
+ undefined,
355
+ undefined,
356
+ reflectionFallbackFormats,
296
357
  ) ?? null;
297
358
  const handle =
298
359
  profilePhase === undefined
@@ -317,6 +378,7 @@ export function recordGeometryDraws(
317
378
  layoutProjection,
318
379
  sampleCount,
319
380
  colorFormatOverride: colorFormat,
381
+ additionalColorFormats: reflectionFallbackFormats,
320
382
  handle,
321
383
  };
322
384
  if (shaderLookupCache === undefined) {
@@ -340,13 +402,18 @@ export function recordGeometryDraws(
340
402
  // Points/Lines share the Standard geometry pass. Their retained source
341
403
  // is prepared once by the renderer owner, while this loop remains the
342
404
  // sole pass/draw submission owner and preserves the authored topology.
343
- const pointsLinesSubmission = c.pointsLines?.prepare(entry, frameState.isHdrpActive);
405
+ const pointsLinesSubmission = c.pointsLines?.prepare(entry, clusteredLighting);
344
406
  if (entry.source.pointsLines !== undefined && pointsLinesSubmission?.plan.drawCount !== 1)
345
407
  continue;
346
408
 
347
409
  if (
348
410
  passKind === 'forward' &&
349
- c.gpuDrivenEntityKeys.has(worldEntityKey(entry.source.worldId, entry.source.entityKey))
411
+ c.gpuDrivenEntityKeys.has(
412
+ worldEntityKey(
413
+ c.gpuDrivenWorldKeys?.[entry.source.worldId] ?? entry.source.worldId,
414
+ entry.source.entityKey,
415
+ ),
416
+ )
350
417
  ) {
351
418
  continue;
352
419
  }
@@ -399,7 +466,7 @@ export function recordGeometryDraws(
399
466
  entry.source.entityKey,
400
467
  entry.world ?? c.world,
401
468
  );
402
- const pointsLinesPipeline = resolveMaterialPipeline(
469
+ const pointsLinesPipelineEntry = resolveMaterialPipeline(
403
470
  POINTS_LINES_MATERIAL_SHADER_ID,
404
471
  {
405
472
  ...pointsLinesMaterial.renderState,
@@ -411,7 +478,8 @@ export function recordGeometryDraws(
411
478
  colorFormatOverride,
412
479
  pointsLinesSubmission.layoutProjection,
413
480
  );
414
- if (pointsLinesPipeline === null) continue;
481
+ if (pointsLinesPipelineEntry === null) continue;
482
+ const pointsLinesPipeline = pointsLinesPipelineEntry.pipeline;
415
483
  if (pipelineState.pointsLinesViewBuffer === undefined) continue;
416
484
  writePointsLinesViewUbo(
417
485
  runtime.device.queue,
@@ -426,9 +494,9 @@ export function recordGeometryDraws(
426
494
  pass.setBindGroup(
427
495
  0,
428
496
  viewBindGroup as BindGroup,
429
- new Uint32Array([i * POINTS_LINES_VIEW_SLOT_STRIDE]),
497
+ new Uint32Array([0, i * POINTS_LINES_VIEW_SLOT_STRIDE]),
430
498
  0,
431
- 1,
499
+ 2,
432
500
  );
433
501
  pass.setPipeline(pointsLinesPipeline);
434
502
  pass.setVertexBuffer(0, pointsLinesSubmission.vertexBuffer);
@@ -438,13 +506,12 @@ export function recordGeometryDraws(
438
506
  const pointsLinesMeshGroup = meshBindGroup ?? meshGroup2;
439
507
  if (pointsLinesMeshGroup === null) continue;
440
508
  pass.setBindGroup(2, pointsLinesMeshGroup, meshGroup2DynamicOffsets);
441
- pass.setBindGroup(
442
- 3,
509
+ const pointsLinesInstancesBg =
443
510
  identityInstanceDraws[0]?.instanceBindGroup ??
444
- resolveGeometryInstancesBindGroup(c, identityInstanceBuffer),
445
- );
446
- recordPointsLinesDraw(pass, pointsLinesSubmission.plan);
447
- pass.setBindGroup(0, viewBindGroup as BindGroup, [0]);
511
+ resolveGeometryInstancesBindGroup(c, identityInstanceBuffer, undefined);
512
+ pass.setBindGroup(3, pointsLinesInstancesBg);
513
+ recordOcclusionCandidate(() => recordPointsLinesDraw(pass, pointsLinesSubmission.plan));
514
+ pass.setBindGroup(0, viewBindGroup as BindGroup, [viewBindGroupDynamicOffset, 0]);
448
515
  continue;
449
516
  }
450
517
 
@@ -471,14 +538,15 @@ export function recordGeometryDraws(
471
538
  // length instead.
472
539
  if (pipelineTag === 'unlit') dispatchCounts.unlit += 1;
473
540
 
474
- const instanceDraws = resolveGeometryInstanceBuffer(c, entry, identityInstanceDraws);
541
+ const instanceDraws = resolveGeometryInstanceBuffer(c, entry, identityInstanceDraws, false);
475
542
  if (instanceDraws === null) continue;
476
543
 
477
- // feat-20260611 R2 / M8 / w28 (IS-14): skin entries need a 2-binding
544
+ // feat-20260611 R2 / M8 / w28 (IS-14): skin entries need a 3-binding
478
545
  // group(2) BG matching `pbr-skin-pl` (binding 0 mesh-array UBO +
479
- // binding 1 palette UBO). Building this here -- not in the
546
+ // binding 1 current palette UBO + binding 2 previous palette UBO).
547
+ // Building this here -- not in the
480
548
  // `meshBindGroup` factory above -- because the binding-shape
481
- // (1-entry vs 2-entry) is per-entry, not per-frame. URP / HDRP
549
+ // (1-entry vs 3-entry) is per-entry, not per-frame. URP / HDRP
482
550
  // entries keep using `meshGroup2` (1-entry mesh-array or HDRP
483
551
  // unified). The skin-variant cache key includes both buffer
484
552
  // identities so a future allocator-driven palette buffer rotation
@@ -489,7 +557,7 @@ export function recordGeometryDraws(
489
557
  // BGL-build failure), AND (b) the skin PSO cache returns a non-null
490
558
  // pipeline for this entry. Without (b), the per-submesh selector
491
559
  // below falls back to URP `standardPipeline` (`pbr-pl` layout,
492
- // 1-entry mesh-array BGL); binding the 2-entry skin BG against
560
+ // 1-entry mesh-array BGL); binding the 3-entry skin BG against
493
561
  // that pipeline reproduces the exact `pbr-mesh-array-bgl ... does
494
562
  // not match layout pbr-skin-mesh-array-bgl` device error R1
495
563
  // captured. Mirrors the uniform null skip-draw pattern (M6-T1).
@@ -501,6 +569,8 @@ export function recordGeometryDraws(
501
569
  meshGroup2DynamicOffsets[0] = i * MESH_PER_ENTITY_STRIDE;
502
570
  let group2DynamicOffsets: readonly number[] = meshGroup2DynamicOffsets;
503
571
  const isSkinEntry = entry.source.skin !== undefined;
572
+ const probeBlendRecordAvailable =
573
+ runtime.device.caps.storageBuffer && entry.source.probeBlendRecord !== undefined;
504
574
  // feat-20260612-skin-palette-per-frame-upload M1 / m1-3 + M6: the
505
575
  // record stage reads the GPU buffer reference through
506
576
  // `entry.source.skin.buffer` (per-slice carrier set at extract time
@@ -517,28 +587,41 @@ export function recordGeometryDraws(
517
587
  // and walks 0, 1536, 3072, ... on the storage path.
518
588
  const skinAllocator = pipelineState.skinPaletteAllocator;
519
589
  const skinSlice = entry.source.skin;
590
+ const clusteredSkin = clusteredLighting;
591
+ const skinMeshBindGroupLayout = clusteredSkin
592
+ ? pipelineState.hdrpSkinMeshBindGroupLayout
593
+ : pipelineState.pbrSkinMeshBindGroupLayout;
594
+ const hdrpSkinBuffers =
595
+ isSkinEntry && clusteredSkin
596
+ ? getOrCreateHdrpBuffers(runtime, frameState.installedPipelineConfig?.clusterGrid)
597
+ : null;
520
598
  const skinResources =
521
599
  isSkinEntry &&
522
- pipelineState.pbrSkinMeshBindGroupLayout !== null &&
600
+ skinMeshBindGroupLayout !== null &&
523
601
  skinAllocator !== null &&
524
- skinSlice !== undefined
602
+ skinSlice !== undefined &&
603
+ (!clusteredSkin || hdrpSkinBuffers !== null)
525
604
  ? {
526
- meshArrayBgl: pipelineState.pbrSkinMeshBindGroupLayout,
605
+ meshArrayBgl: skinMeshBindGroupLayout,
527
606
  paletteBuffer: skinSlice.buffer,
528
607
  paletteBindingWindowBytes: skinAllocator.bindingWindowBytes,
608
+ hdrpBuffers: hdrpSkinBuffers,
529
609
  }
530
610
  : null;
531
611
  // Probe the skin PSO cache up front so we can decide whether to swap
532
- // to the 2-binding skin BG. The same probe + selector is repeated in
612
+ // to the skin BG. The same probe + selector is repeated in
533
613
  // the per-submesh loop below (the loop's variantSet derivation is
534
614
  // identical -- skin shader registers a single all-true variant so
535
615
  // the canonical empty-key rule applies on HDRP and the URP key is
536
616
  // the explicit expanded form, mirroring the standard PBR path).
537
617
  const skinVariantSetResult = variantSetFromVertexLayoutProjection(
538
618
  entry.mesh.layoutProjection,
539
- frameState.isHdrpActive
540
- ? ''
541
- : 'CLUSTER_FORWARD_AVAILABLE=false+STORAGE_BUFFER_AVAILABLE=true',
619
+ standardTopologyVariantSet(
620
+ c.standardLighting,
621
+ runtime.device.caps.storageBuffer,
622
+ entry.mesh.layoutProjection.attributes.some((attribute) => attribute.key === 'color'),
623
+ probeBlendRecordAvailable,
624
+ ),
542
625
  );
543
626
  if (!skinVariantSetResult.ok) runtime.errorRegistry.fire(skinVariantSetResult.error);
544
627
  const skinVariantSet = skinVariantSetResult.ok ? skinVariantSetResult.value : undefined;
@@ -559,6 +642,9 @@ export function recordGeometryDraws(
559
642
  undefined,
560
643
  undefined,
561
644
  entry.mesh.layoutProjection,
645
+ undefined,
646
+ undefined,
647
+ undefined,
562
648
  ) ?? null)
563
649
  : null;
564
650
  if (skinResources !== null && skinPsoProbe !== null) {
@@ -579,45 +665,47 @@ export function recordGeometryDraws(
579
665
  const skinMissesBefore = bindGroupCounts.createBindGroup;
580
666
  const skinBindGroup: BindGroup = getOrCreateFromChain(
581
667
  frameState.meshBindGroupCache,
582
- [pipelineState.meshStorageBuffer.buffer, skinResources.paletteBuffer],
668
+ [
669
+ pipelineState.meshStorageBuffer.buffer,
670
+ skinResources.paletteBuffer,
671
+ ...(skinResources.hdrpBuffers === null
672
+ ? []
673
+ : [
674
+ skinResources.hdrpBuffers.lightDataBuffer,
675
+ skinResources.hdrpBuffers.clusterGridBuffer,
676
+ skinResources.hdrpBuffers.lightIndexListBuffer,
677
+ skinResources.hdrpBuffers.clusterUniformBuffer,
678
+ ]),
679
+ ],
583
680
  'pbr-skin-mesh',
584
681
  () => {
682
+ if (skinResources.hdrpBuffers !== null) {
683
+ const result = createHdrpSkinUnifiedBindGroup(
684
+ runtime,
685
+ skinResources.hdrpBuffers,
686
+ skinResources.meshArrayBgl,
687
+ pipelineState.meshStorageBuffer.buffer,
688
+ skinResources.paletteBuffer,
689
+ skinResources.paletteBindingWindowBytes,
690
+ );
691
+ if (result === null) {
692
+ throw new RhiError({
693
+ code: 'webgpu-runtime-error',
694
+ expected: 'HDRP clustered skin BindGroup creation succeeds',
695
+ hint: 'inspect prior errorRegistry events for createBindGroup failure detail',
696
+ });
697
+ }
698
+ return result;
699
+ }
585
700
  const result = runtime.device.createBindGroup({
586
701
  label: 'pbr-skin-mesh-bg',
587
702
  layout: skinResources.meshArrayBgl,
588
- entries: [
589
- {
590
- binding: 0,
591
- resource: {
592
- kind: 'buffer',
593
- value: {
594
- buffer: pipelineState.meshStorageBuffer.buffer,
595
- offset: 0,
596
- size: meshBindSize,
597
- },
598
- },
599
- },
600
- {
601
- binding: 1,
602
- resource: {
603
- kind: 'buffer',
604
- value: {
605
- buffer: skinResources.paletteBuffer,
606
- offset: 0,
607
- // M6 SSOT: static BG entry size (= MAX_JOINTS * 64 =
608
- // 16320 B) sourced from the allocator. The per-draw
609
- // window slides via `group2DynamicOffsets[1]`
610
- // (= entry.source.skin.byteOffset) so this size
611
- // stays at the worst case across all skin entries
612
- // -- one BG covers every skinned draw in the frame
613
- // (m3-1b miss=1 + hit=N-1 contract). The allocator
614
- // guarantees `buffer.size >= byteOffset + this size`
615
- // so dynOffset[1] passes WebGPU validation.
616
- size: skinResources.paletteBindingWindowBytes,
617
- },
618
- },
619
- },
620
- ],
703
+ entries: createPbrSkinMeshBindGroupEntries(
704
+ pipelineState.meshStorageBuffer.buffer,
705
+ meshBindSize,
706
+ skinResources.paletteBuffer,
707
+ skinResources.paletteBindingWindowBytes,
708
+ ),
621
709
  });
622
710
  if (!result.ok) throw result.error;
623
711
  return result.value;
@@ -634,9 +722,10 @@ export function recordGeometryDraws(
634
722
  // Replaces the prior PR #353 hard-coded `0` second slot -- every
635
723
  // skin entry now points the palette window at its own slice while
636
724
  // sharing the worst-case BG entry size above.
637
- skinGroup2DynamicOffsets[0] = i * MESH_PER_ENTITY_STRIDE;
638
- skinGroup2DynamicOffsets[1] = entry.source.skin?.byteOffset ?? 0;
639
- group2DynamicOffsets = skinGroup2DynamicOffsets;
725
+ group2DynamicOffsets = pbrSkinMeshDynamicOffsets(
726
+ i * MESH_PER_ENTITY_STRIDE,
727
+ entry.source.skin?.byteOffset ?? 0,
728
+ );
640
729
  } else if (isSkinEntry) {
641
730
  // Skin entry but skin PSO not ready (cache miss / async build pending,
642
731
  // or skin pipeline layout failed at boot). Skip the draw rather than
@@ -762,6 +851,8 @@ export function recordGeometryDraws(
762
851
  entry.source.skin !== undefined
763
852
  ? SKIN_MATERIAL_SHADER_ID
764
853
  : submeshMaterial.materialShaderId;
854
+ const probeBlendAvailable =
855
+ probeBlendRecordAvailable && isStandardPbrMaterialShader(smMaterialShaderId);
765
856
  const isSpriteShader =
766
857
  smMaterialShaderId === 'forgeax::sprite' || smMaterialShaderId === 'forgeax::sprite-lit';
767
858
  // Preserve the dedicated sprite-pass state when the linear-LDR graph
@@ -778,6 +869,8 @@ export function recordGeometryDraws(
778
869
  : geometryRenderStateForTopology(smTopology, submeshMaterial.renderState);
779
870
  const pipelineRenderState = geometryRenderStateForPass(basePipelineRenderState, passKind);
780
871
  let smPipelineHandle: typeof pipelineState.unlitPipeline;
872
+ let materialGroup2Contract: 'mesh' | 'skin' | 'cluster' | 'skin-cluster' | undefined;
873
+ let materialPipelineEntry: MaterialShaderPipelineEntry | null = null;
781
874
  if (smMaterialShaderId === undefined || smMaterialShaderId === 'forgeax::default-unlit') {
782
875
  const unlitShaderId = smMaterialShaderId ?? 'forgeax::default-unlit';
783
876
  const unlitProjectionVariantResult = variantSetFromVertexLayoutProjection(
@@ -789,9 +882,10 @@ export function recordGeometryDraws(
789
882
  continue;
790
883
  }
791
884
  const unlitHasColor = unlitProjectionVariantResult.value === 'VERTEX_COLOR_AVAILABLE=true';
792
- const unlitVariantSet = unlitHasColor
793
- ? ''
794
- : 'STORAGE_BUFFER_AVAILABLE=true+VERTEX_COLOR_AVAILABLE=false';
885
+ const unlitVariantSet = standardStorageVariantSet(
886
+ runtime.device.caps.storageBuffer,
887
+ unlitHasColor,
888
+ );
795
889
  const unlitRsp = resolveMaterialPipeline(
796
890
  unlitShaderId,
797
891
  pipelineRenderState,
@@ -801,8 +895,9 @@ export function recordGeometryDraws(
801
895
  colorFormatOverride,
802
896
  entry.mesh.layoutProjection,
803
897
  );
898
+ materialPipelineEntry = unlitRsp;
804
899
  smPipelineHandle =
805
- unlitRsp ??
900
+ unlitRsp?.pipeline ??
806
901
  (colorFormatOverride === undefined
807
902
  ? selectGeometryPipeline(pipelineState, isHdrTarget, msaaActive)
808
903
  : null);
@@ -829,11 +924,12 @@ export function recordGeometryDraws(
829
924
  // VERTEX_COLOR_AVAILABLE=false axis, so retain the two capability
830
925
  // axes explicitly or the selector would silently choose the URP
831
926
  // group(2) layout for an HDRP cluster bind group.
832
- const capabilityVariantSet = frameState.isHdrpActive
833
- ? hasVertexColor
834
- ? ''
835
- : 'CLUSTER_FORWARD_AVAILABLE=true+STORAGE_BUFFER_AVAILABLE=true'
836
- : 'CLUSTER_FORWARD_AVAILABLE=false+STORAGE_BUFFER_AVAILABLE=true';
927
+ const capabilityVariantSet = standardTopologyVariantSet(
928
+ c.standardLighting,
929
+ runtime.device.caps.storageBuffer,
930
+ hasVertexColor,
931
+ probeBlendAvailable,
932
+ );
837
933
  // Sprite's base request must retain the boot-selected artifact. Only
838
934
  // SpriteInstances uses the explicit empty key for the
839
935
  // PER_INSTANCE_REGION=true variant; synthesizing the generic PBR
@@ -848,19 +944,12 @@ export function recordGeometryDraws(
848
944
  : capabilityVariantSet === ''
849
945
  ? entry.variantSet
850
946
  : `${capabilityVariantSet}+${entry.variantSet}`;
851
- const projectionVariantSetResult = isSpriteShader
852
- ? ({ ok: true, value: variantSet } as const)
853
- : variantSetFromVertexLayoutProjection(entry.mesh.layoutProjection, variantSet);
854
- if (!projectionVariantSetResult.ok) {
855
- runtime.errorRegistry.fire(projectionVariantSetResult.error);
856
- continue;
857
- }
858
947
  const cachedPipeline = resolveMaterialPipeline(
859
948
  smMaterialShaderId,
860
949
  pipelineRenderState,
861
950
  smTopology,
862
951
  entry.mesh.indexFormat,
863
- projectionVariantSetResult.value,
952
+ variantSet,
864
953
  colorFormatOverride,
865
954
  entry.mesh.layoutProjection,
866
955
  );
@@ -877,7 +966,8 @@ export function recordGeometryDraws(
877
966
  // build resolves. The pre-loop skin-PSO probe still skips the
878
967
  // entire entry on first-submesh probe miss; this site only
879
968
  // fires on per-submesh topology variance miss.
880
- smPipelineHandle = cachedPipeline ?? null;
969
+ materialPipelineEntry = cachedPipeline;
970
+ smPipelineHandle = cachedPipeline?.pipeline ?? null;
881
971
  } else {
882
972
  smPipelineHandle = selectGeometryPipeline(pipelineState, isHdrTarget, msaaActive);
883
973
  }
@@ -885,37 +975,38 @@ export function recordGeometryDraws(
885
975
  if (smPipelineHandle === null) {
886
976
  continue;
887
977
  }
978
+ // The probe record is an ABI extension of the built-in Standard PBR
979
+ // shaders only. RenderScene may retain a record on every projected
980
+ // renderable, but unlit/custom shaders still use the one-binding
981
+ // instances BGL and must never receive the probe bind group. Resolve
982
+ // this per submesh so mixed-material meshes cannot cross the layouts.
983
+ const instanceDraws = resolveGeometryInstanceBuffer(
984
+ c,
985
+ entry,
986
+ identityInstanceDraws,
987
+ probeBlendAvailable,
988
+ );
989
+ if (instanceDraws === null) continue;
888
990
  // Standard clustered PBR variants declare the unified cluster/SSAO
889
991
  // group(2) layout. Unlit and other URP-layout materials must bind the
890
992
  // ordinary mesh group instead; choosing one group for the whole pass
891
993
  // makes Dawn reject an otherwise valid unlit pipeline and invalidates
892
994
  // the command buffer before it reaches the surface.
893
- const usesStandardClusterBindings = smMaterialShaderId === 'forgeax::default-standard-pbr';
894
995
  if (!isSkinEntry) {
895
- if (usesStandardClusterBindings) {
896
- if (meshGroup2 === null) continue;
897
- group2BindGroup = meshGroup2;
898
- } else {
899
- const fallbackGroup = meshBindGroup ?? meshGroup2;
900
- if (fallbackGroup === null) continue;
901
- group2BindGroup = fallbackGroup;
902
- }
996
+ materialGroup2Contract = materialPipelineEntry?.group2Contract;
997
+ if (materialGroup2Contract === undefined) continue;
998
+ const selectedGroup = selectMaterialGroup2(
999
+ meshGroup2,
1000
+ meshBindGroup,
1001
+ materialGroup2Contract,
1002
+ );
1003
+ if (selectedGroup === null) continue;
1004
+ group2BindGroup = selectedGroup;
903
1005
  }
904
1006
  pass.setBindGroup(2, group2BindGroup, group2DynamicOffsets);
905
1007
 
906
1008
  if (profilePhase === undefined) {
907
- submitSubmeshDraws(
908
- pass,
909
- bindingState,
910
- smPipelineHandle,
911
- instanceDraws,
912
- entry.mesh.indexed,
913
- sm.indexCount,
914
- sm.vertexCount,
915
- sm.indexOffset,
916
- );
917
- } else {
918
- profileGeometrySegment(c, passKind, 'draw-submit', () =>
1009
+ recordOcclusionCandidate(() =>
919
1010
  submitSubmeshDraws(
920
1011
  pass,
921
1012
  bindingState,
@@ -927,6 +1018,21 @@ export function recordGeometryDraws(
927
1018
  sm.indexOffset,
928
1019
  ),
929
1020
  );
1021
+ } else {
1022
+ profileGeometrySegment(c, passKind, 'draw-submit', () =>
1023
+ recordOcclusionCandidate(() =>
1024
+ submitSubmeshDraws(
1025
+ pass,
1026
+ bindingState,
1027
+ smPipelineHandle,
1028
+ instanceDraws,
1029
+ entry.mesh.indexed,
1030
+ sm.indexCount,
1031
+ sm.vertexCount,
1032
+ sm.indexOffset,
1033
+ ),
1034
+ ),
1035
+ );
930
1036
  }
931
1037
  }
932
1038
  }
@@ -941,10 +1047,38 @@ function resolveGeometryInstanceBuffer(
941
1047
  c: _InternalRenderPipelineContext,
942
1048
  entry: _InternalRenderPipelineContext['validatedOrdered'][number],
943
1049
  identityInstanceDraws: readonly GeometryInstanceDraw[],
1050
+ useProbeBlend: boolean,
944
1051
  ): readonly GeometryInstanceDraw[] | null {
945
1052
  const { runtime, pipelineState, frameState } = c;
946
1053
  const inst = entry.source.instances;
947
- if (inst === undefined) return identityInstanceDraws;
1054
+ const probeBinding =
1055
+ !useProbeBlend ||
1056
+ !runtime.device.caps.storageBuffer ||
1057
+ entry.source.probeBlendRecord === undefined
1058
+ ? undefined
1059
+ : resolveProbeBlendBuffer(
1060
+ c,
1061
+ entry.source.probeBlendRecord,
1062
+ worldEntityKey(entry.source.worldId, entry.source.entityKey),
1063
+ );
1064
+ if (inst === undefined) {
1065
+ const identity = identityInstanceDraws[0];
1066
+ if (identity === undefined) return null;
1067
+ return [
1068
+ {
1069
+ ...identity,
1070
+ instanceBindGroup: resolveGeometryInstancesBindGroup(
1071
+ c,
1072
+ pipelineState.identityInstanceBuffer,
1073
+ probeBinding?.buffer,
1074
+ ),
1075
+ probeOffset: probeBinding?.offset ?? -1,
1076
+ },
1077
+ ];
1078
+ }
1079
+ // A present, empty Instances array means zero draws. Do not fall back to
1080
+ // the shared identity buffer, which would silently render one instance.
1081
+ if (inst.instanceCount === 0) return [];
948
1082
  let instanceBuffer: Buffer = pipelineState.identityInstanceBuffer;
949
1083
  let instanceCount = 1;
950
1084
  {
@@ -982,7 +1116,12 @@ function resolveGeometryInstanceBuffer(
982
1116
  }
983
1117
  draws.push({
984
1118
  instanceBuffer: buffer.handle,
985
- instanceBindGroup: resolveGeometryInstancesBindGroup(c, buffer.handle),
1119
+ instanceBindGroup: resolveGeometryInstancesBindGroup(
1120
+ c,
1121
+ buffer.handle,
1122
+ probeBinding?.buffer,
1123
+ ),
1124
+ probeOffset: probeBinding?.offset ?? -1,
986
1125
  instanceCount: count,
987
1126
  });
988
1127
  }
@@ -1074,25 +1213,80 @@ function resolveGeometryInstanceBuffer(
1074
1213
  return [
1075
1214
  {
1076
1215
  instanceBuffer,
1077
- instanceBindGroup: resolveGeometryInstancesBindGroup(c, instanceBuffer),
1216
+ instanceBindGroup: resolveGeometryInstancesBindGroup(c, instanceBuffer, probeBinding?.buffer),
1217
+ probeOffset: probeBinding?.offset ?? -1,
1078
1218
  instanceCount,
1079
1219
  },
1080
1220
  ];
1081
1221
  }
1082
1222
 
1083
- function resolveGeometryInstancesBindGroup(
1223
+ export function resolveProbeBlendBuffer(
1224
+ c: _InternalRenderPipelineContext,
1225
+ record: import('../scene/probe-blend-record').ProbeBlendRecord | undefined,
1226
+ entityKey?: number,
1227
+ ): { readonly buffer: Buffer; readonly offset: number } {
1228
+ const { runtime, frameState } = c;
1229
+ const usage = runtime.device.caps.storageBuffer
1230
+ ? GPU_BUFFER_USAGE_STORAGE | GPU_BUFFER_USAGE_COPY_DST
1231
+ : GPU_BUFFER_USAGE_UNIFORM | GPU_BUFFER_USAGE_COPY_DST;
1232
+ if (record === undefined) throw new Error('probe blend record is required for probe allocation');
1233
+ if (entityKey === undefined) throw new Error('probe blend record requires an entity key');
1234
+ const offset = probeBlendRecordOffset(record.objectKey);
1235
+ const requiredCapacity = record.objectKey + 2;
1236
+ let buffer = frameState.probeBlendRecordBuffer;
1237
+ if (buffer === undefined || frameState.probeBlendRecordBufferCapacity < requiredCapacity) {
1238
+ const created = runtime.device.createBuffer({
1239
+ label: 'probe-blend-records',
1240
+ size: requiredCapacity * PROBE_BLEND_RECORD_STRIDE,
1241
+ usage,
1242
+ mappedAtCreation: false,
1243
+ });
1244
+ if (!created.ok) throw created.error;
1245
+ buffer = new GpuBuffer(runtime.device, created.value);
1246
+ frameState.probeBlendRecordBuffer = buffer;
1247
+ frameState.probeBlendRecordBufferCapacity = requiredCapacity;
1248
+ // The cache is tied to the previous backing allocation. A new buffer has
1249
+ // no valid record contents, so every later object must upload its full
1250
+ // 160B payload even when generation/bytes match the old allocation.
1251
+ frameState.probeBlendBuffers.clear();
1252
+ }
1253
+ const cached = frameState.probeBlendBuffers.get(entityKey);
1254
+ const unchanged =
1255
+ cached !== undefined &&
1256
+ cached.generation === record.generation &&
1257
+ cached.bytes.length === record.bytes.length &&
1258
+ cached.bytes.every((value, index) => value === record.bytes[index]);
1259
+ if (!unchanged) {
1260
+ const uploaded = runtime.device.queue.writeBuffer(buffer.handle, offset, record.bytes);
1261
+ if (!uploaded.ok) throw uploaded.error;
1262
+ // Publish the generation only after the complete 160B queue write succeeds.
1263
+ frameState.probeBlendBuffers.set(entityKey, {
1264
+ generation: record.generation,
1265
+ bytes: new Uint8Array(record.bytes),
1266
+ });
1267
+ }
1268
+ return { buffer: buffer.handle, offset };
1269
+ }
1270
+
1271
+ export function resolveGeometryInstancesBindGroup(
1084
1272
  c: _InternalRenderPipelineContext,
1085
1273
  instanceBuffer: Buffer,
1274
+ probeBuffer?: Buffer,
1086
1275
  ): BindGroup {
1087
1276
  const { runtime, pipelineState, frameState, bindGroupCounts } = c;
1277
+ const layout =
1278
+ probeBuffer === undefined
1279
+ ? pipelineState.instancesBindGroupLayout
1280
+ : pipelineState.probeInstancesBindGroupLayout;
1281
+ if (layout === undefined) throw new Error('probe instances bind-group layout is unavailable');
1088
1282
  return getOrCreateFromChain(
1089
1283
  frameState.instancesBgShared,
1090
- [pipelineState.instancesBindGroupLayout, instanceBuffer],
1091
- 'instances',
1284
+ probeBuffer === undefined ? [layout, instanceBuffer] : [layout, instanceBuffer, probeBuffer],
1285
+ probeBuffer === undefined ? 'instances-no-probe' : 'instances-probe',
1092
1286
  () => {
1093
1287
  const result = runtime.device.createBindGroup({
1094
1288
  label: 'pbr-instances-bg',
1095
- layout: pipelineState.instancesBindGroupLayout,
1289
+ layout,
1096
1290
  entries: [
1097
1291
  {
1098
1292
  binding: 0,
@@ -1101,6 +1295,17 @@ function resolveGeometryInstancesBindGroup(
1101
1295
  value: { buffer: instanceBuffer },
1102
1296
  },
1103
1297
  },
1298
+ ...(probeBuffer === undefined
1299
+ ? []
1300
+ : [
1301
+ {
1302
+ binding: 1,
1303
+ resource: {
1304
+ kind: 'buffer' as const,
1305
+ value: { buffer: probeBuffer, offset: 0, size: PROBE_BLEND_RECORD_BYTE_SIZE },
1306
+ },
1307
+ },
1308
+ ]),
1104
1309
  ],
1105
1310
  });
1106
1311
  if (!result.ok) throw result.error;