@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
@@ -0,0 +1,120 @@
1
+ import { err, ok, type Result } from '@forgeax/engine-types';
2
+ import type { PreparedStandardLighting } from './prepare';
3
+ import type { StandardClusterTransport } from './transport';
4
+
5
+ /** A prepared frame with no local lights on a non-storage backend. */
6
+ export interface StandardNoLocalTopologyInput {
7
+ readonly kind: 'no-local-lights';
8
+ readonly prepared: PreparedStandardLighting;
9
+ }
10
+
11
+ /** A prepared frame whose Standard surface uses one proven Cluster transport. */
12
+ export interface StandardClusteredTopologyInput {
13
+ readonly kind: 'clustered';
14
+ readonly prepared: PreparedStandardLighting;
15
+ readonly transport: StandardClusterTransport;
16
+ }
17
+
18
+ /**
19
+ * The only lighting value accepted by a Standard topology adapter. It is a
20
+ * projection of one prepared frame, not a second light/config/capability
21
+ * input. Both Forward and Deferred keep the same object identity for a frame.
22
+ */
23
+ export type StandardTopologyInput = StandardNoLocalTopologyInput | StandardClusteredTopologyInput;
24
+
25
+ export type StandardTopologyInputValue = StandardTopologyInput;
26
+
27
+ /**
28
+ * Stable identity for the graph-facing Standard lighting declaration.
29
+ *
30
+ * The prepared light payload itself is frame-local and must never be retained
31
+ * by a compiled graph. These are the only facts that affect the Cluster graph
32
+ * shape and persistent buffer contract, so the record owner can reject an old
33
+ * graph before uploading a payload derived from a different declaration.
34
+ */
35
+ export function standardLightingTopologySignature(
36
+ input: StandardTopologyInputValue | undefined,
37
+ ): string {
38
+ if (input === undefined) return 'missing';
39
+ if (input.kind === 'no-local-lights') return 'no-local-lights';
40
+ return JSON.stringify({
41
+ kind: input.kind,
42
+ transport: input.transport.kind,
43
+ producer: input.transport.producer,
44
+ grid: input.prepared.layout.grid,
45
+ clusterGridU32Length: input.prepared.layout.clusterGridU32Length,
46
+ lightIndexListCapacity: input.prepared.layout.lightIndexListCapacity,
47
+ lightDataSlotCount: input.prepared.layout.lightDataSlotCount,
48
+ lightBoundsInt32Length: input.prepared.layout.lightBoundsInt32Length,
49
+ });
50
+ }
51
+
52
+ export interface StandardTopologyInputError {
53
+ readonly code: 'topology-input-invalid';
54
+ readonly expected: 'prepared Standard lighting topology input';
55
+ readonly hint: 'derive topology from prepared Standard lighting';
56
+ readonly detail: {
57
+ readonly field: 'kind' | 'prepared' | 'transport' | 'lights' | 'capabilities';
58
+ };
59
+ }
60
+
61
+ function invalid(
62
+ field: StandardTopologyInputError['detail']['field'],
63
+ ): Result<never, StandardTopologyInputError> {
64
+ return err({
65
+ code: 'topology-input-invalid',
66
+ expected: 'prepared Standard lighting topology input',
67
+ hint: 'derive topology from prepared Standard lighting',
68
+ detail: { field },
69
+ });
70
+ }
71
+
72
+ /**
73
+ * Validate that transport and prepared membership are the same derivation.
74
+ * The identity checks make it impossible for an adapter to silently combine
75
+ * one path's layout/counts with another path's prepared light corpus.
76
+ */
77
+ export function deriveStandardTopologyInput(
78
+ input: StandardTopologyInput,
79
+ ): Result<StandardTopologyInputValue, StandardTopologyInputError> {
80
+ const candidate = input as StandardTopologyInput & {
81
+ readonly kind?: unknown;
82
+ readonly lights?: unknown;
83
+ readonly capabilities?: unknown;
84
+ readonly transport?: unknown;
85
+ };
86
+ if ('lights' in candidate) return invalid('lights');
87
+ if ('capabilities' in candidate) return invalid('capabilities');
88
+ if (input === null || typeof input !== 'object') return invalid('kind');
89
+ if (input.prepared === null || typeof input.prepared !== 'object') {
90
+ return invalid('prepared');
91
+ }
92
+
93
+ const prepared = input.prepared;
94
+ if (input.kind === 'no-local-lights') {
95
+ if (prepared.local.length !== 0 || 'transport' in candidate) return invalid('transport');
96
+ return ok(input);
97
+ }
98
+ if (input.kind !== 'clustered') return invalid('kind');
99
+ if (
100
+ !('transport' in candidate) ||
101
+ candidate.transport === null ||
102
+ typeof candidate.transport !== 'object'
103
+ ) {
104
+ return invalid('transport');
105
+ }
106
+
107
+ const transport = input.transport;
108
+ const requested = prepared.local.length;
109
+ const transportMatchesPrepared =
110
+ transport.layout === prepared.layout &&
111
+ transport.requestedLightCount === requested &&
112
+ transport.admittedLightCount === requested &&
113
+ transport.membershipEntryCount === prepared.membershipEntryCount &&
114
+ transport.lightBoundsBytes === prepared.lightBounds.byteLength;
115
+ const producerMatchesKind =
116
+ (transport.producer === 'gpu' && transport.kind === 'compute-storage') ||
117
+ (transport.producer === 'cpu' && transport.kind === 'cpu-storage');
118
+ if (!transportMatchesPrepared || !producerMatchesKind) return invalid('transport');
119
+ return ok(input);
120
+ }
@@ -0,0 +1,78 @@
1
+ import { err, ok, type Result } from '@forgeax/engine-types';
2
+ import { type RenderError, StandardClusterTransportUnavailableError } from '../../errors/render';
3
+ import { BYTES_PER_DIRECT_LIGHT_SLOT } from '../../light-buffer-layout';
4
+ import type { PreparedStandardLighting } from './prepare';
5
+
6
+ export interface StandardClusterCapabilities {
7
+ readonly compute: boolean;
8
+ readonly storageBuffer: boolean;
9
+ /**
10
+ * The graph producer is ready to encode the selected compute lane. The
11
+ * renderer supplies this from the actual pipeline + bind-group layout; it is
12
+ * required so capability admission cannot forge a GPU producer from
13
+ * `compute` alone.
14
+ */
15
+ readonly membershipPipelineReady: boolean;
16
+ }
17
+
18
+ /** Only transports with storage-backed membership representation exist. */
19
+ export type StandardClusterTransportKind = 'compute-storage' | 'cpu-storage';
20
+ export type StandardClusterMembershipProducer = 'cpu' | 'gpu';
21
+
22
+ export interface StandardClusterTransport {
23
+ readonly kind: StandardClusterTransportKind;
24
+ readonly producer: StandardClusterMembershipProducer;
25
+ readonly layout: PreparedStandardLighting['layout'];
26
+ readonly requestedLightCount: number;
27
+ readonly admittedLightCount: number;
28
+ readonly membershipEntryCount: number;
29
+ readonly occupiedClusterCount: number;
30
+ readonly clusterGridBytes: number;
31
+ readonly lightIndexListBytes: number;
32
+ readonly lightDataBytes: number;
33
+ readonly lightBoundsBytes: number;
34
+ }
35
+
36
+ function occupiedClusterCount(prepared: PreparedStandardLighting): number {
37
+ let occupied = 0;
38
+ for (let index = 1; index < prepared.clusterGrid.length; index += 2) {
39
+ if ((prepared.clusterGrid[index] ?? 0) > 0) occupied += 1;
40
+ }
41
+ return occupied;
42
+ }
43
+
44
+ /**
45
+ * Select a transport from one prepared frame. Capability facts choose only a
46
+ * producer/storage pair; all counts and byte sizes come from that frame.
47
+ */
48
+ export function selectStandardClusterTransport(
49
+ capabilities: StandardClusterCapabilities,
50
+ prepared: PreparedStandardLighting,
51
+ ): Result<StandardClusterTransport, RenderError> {
52
+ const requested = prepared.local.length;
53
+ if (!capabilities.storageBuffer) {
54
+ return err(
55
+ new StandardClusterTransportUnavailableError(
56
+ requested,
57
+ 'enable a proven storage-buffer Cluster transport; compute without storage is not a membership path',
58
+ ),
59
+ );
60
+ }
61
+
62
+ const producer: StandardClusterMembershipProducer =
63
+ capabilities.compute && capabilities.membershipPipelineReady ? 'gpu' : 'cpu';
64
+ const kind: StandardClusterTransportKind = producer === 'gpu' ? 'compute-storage' : 'cpu-storage';
65
+ return ok({
66
+ kind,
67
+ producer,
68
+ layout: prepared.layout,
69
+ requestedLightCount: requested,
70
+ admittedLightCount: requested,
71
+ membershipEntryCount: prepared.membershipEntryCount,
72
+ occupiedClusterCount: occupiedClusterCount(prepared),
73
+ clusterGridBytes: prepared.layout.clusterGridU32Length * Uint32Array.BYTES_PER_ELEMENT,
74
+ lightIndexListBytes: prepared.membershipEntryCount * Uint32Array.BYTES_PER_ELEMENT,
75
+ lightDataBytes: requested * BYTES_PER_DIRECT_LIGHT_SLOT,
76
+ lightBoundsBytes: prepared.lightBounds.byteLength,
77
+ });
78
+ }
@@ -1,21 +1,13 @@
1
- import type {
2
- GraphAccess,
3
- GraphBuffer,
4
- GraphTextureDescriptor,
5
- RenderGraphBuilder,
1
+ import {
2
+ type GraphAccess,
3
+ type GraphTextureDescriptor,
4
+ type RenderGraphBuilder,
6
5
  RenderGraphError,
7
6
  } from '@forgeax/engine-render-graph';
8
7
  import { err, ok, type Result } from '@forgeax/engine-types';
9
- import { HdrpDeferredCapsInsufficientError, SceneDataUnavailableError } from '../errors/render';
8
+ import { SceneDataUnavailableError, StandardProfileInvalidError } from '../errors/render';
10
9
  import type { FramePlan } from '../extract/environment';
11
- import {
12
- GPU_BUFFER_USAGE_COPY_DST,
13
- GPU_BUFFER_USAGE_STORAGE,
14
- GPU_BUFFER_USAGE_UNIFORM,
15
- } from '../gpu-usage';
16
- import { getOrCreateHdrpBuffers, type HdrpBuffers } from '../hdrp-buffers';
17
10
  import { DEFERRED_COLOR_FORMATS } from '../pipeline-spec';
18
- import type { _InternalRenderPipelineContext } from '../record/render-context';
19
11
  import type {
20
12
  RenderPipeline,
21
13
  RenderPipelineBuildContext,
@@ -48,16 +40,20 @@ import {
48
40
  } from '../typed-render-graph-primitives';
49
41
  import { addTypedShadowPasses } from '../typed-shadow-passes';
50
42
  import { addAuthoredVolumetricFogPasses } from '../volume/passes';
51
-
52
43
  import { buildStandardForwardLane } from './standard-forward-lane';
44
+ import {
45
+ addStandardClusterMembershipPass,
46
+ importStandardClusterBuffers,
47
+ standardClusterReadAccesses,
48
+ } from './standard-lighting/graph';
49
+ import {
50
+ deriveStandardTopologyInput,
51
+ type StandardTopologyInputValue,
52
+ } from './standard-lighting/topology';
53
53
  import { addStandardPost } from './standard-post';
54
54
  import {
55
- CLUSTER_GRID_STRIDE_U32,
56
- DEFAULT_CLUSTER_GRID,
57
55
  DEFAULT_STANDARD_PROFILE,
58
- LIGHT_INDEX_LIST_CAPACITY,
59
- MAX_LIGHTS,
60
- resolveStandardLane,
56
+ STANDARD_LIGHT_COUNTS,
61
57
  STANDARD_PIPELINE_ID,
62
58
  type StandardProfile,
63
59
  } from './standard-profile';
@@ -125,26 +121,11 @@ fn cs_cluster_membership(@builtin(global_invocation_id) global_id : vec3<u32>) {
125
121
  }
126
122
  }
127
123
  `;
128
- export class HdrpInstallError extends Error {
129
- readonly code = 'hdrp-grid-invalid' as const;
130
- readonly expected = 'clusterGrid.{x,y,z} each integer in [1, 64]';
131
- readonly hint: string;
132
- readonly detail: { readonly x: number; readonly y: number; readonly z: number };
133
-
134
- constructor(x: number, y: number, z: number) {
135
- const hint = `clusterGrid {x:${x}, y:${y}, z:${z}} is invalid; set {x,y,z} to positive integers in [1, 64]`;
136
- super(`hdrp-grid-invalid: ${hint}`);
137
- this.name = 'HdrpInstallError';
138
- this.hint = hint;
139
- this.detail = { x, y, z };
140
- }
141
- }
142
-
143
124
  export function validateClusterGrid(grid: {
144
125
  x: number;
145
126
  y: number;
146
127
  z: number;
147
- }): Result<{ x: number; y: number; z: number }, HdrpInstallError> {
128
+ }): Result<{ x: number; y: number; z: number }, StandardProfileInvalidError> {
148
129
  const { x, y, z } = grid;
149
130
  return Number.isInteger(x) &&
150
131
  Number.isInteger(y) &&
@@ -156,7 +137,12 @@ export function validateClusterGrid(grid: {
156
137
  z >= 1 &&
157
138
  z <= 64
158
139
  ? ok({ x, y, z })
159
- : err(new HdrpInstallError(x, y, z));
140
+ : err(
141
+ new StandardProfileInvalidError(
142
+ `clusterGrid {x:${x}, y:${y}, z:${z}} is invalid; set x, y, and z to positive integers in [1, 64]`,
143
+ { field: 'clusterGrid', actual: { x, y, z } },
144
+ ),
145
+ );
160
146
  }
161
147
 
162
148
  function target(
@@ -167,114 +153,20 @@ function target(
167
153
  return createRenderPipelineTarget(graph, label, descriptor);
168
154
  }
169
155
 
170
- interface HdrpGraphBuffers {
171
- readonly lightData: GraphBuffer;
172
- readonly clusterGrid: GraphBuffer;
173
- readonly lightIndexList: GraphBuffer;
174
- readonly clusterUniform: GraphBuffer;
175
- readonly lightBounds: GraphBuffer;
176
- }
177
-
178
- function importBuffers(
179
- graph: RenderGraphBuilder<RenderPipelineFrame>,
180
- topology: RenderPipelineTopology,
181
- ): Result<HdrpGraphBuffers, RenderGraphError> {
182
- const grid = topology.config?.clusterGrid ?? DEFAULT_CLUSTER_GRID;
183
- const cells = grid.x * grid.y * grid.z;
184
- const storage = topology.lane.storageBuffer;
185
- const usage =
186
- (storage ? GPU_BUFFER_USAGE_STORAGE : GPU_BUFFER_USAGE_UNIFORM) | GPU_BUFFER_USAGE_COPY_DST;
187
- const resolve = (frame: RenderPipelineFrame): HdrpBuffers => {
188
- const internal = frame as _InternalRenderPipelineContext;
189
- const buffers = getOrCreateHdrpBuffers(internal.runtime, grid);
190
- if (buffers === null) throw new Error('HDRP persistent buffer allocation failed');
191
- return buffers;
192
- };
193
- const lightData = graph.importBuffer(
194
- 'hdrp-light-data',
195
- { size: (storage ? MAX_LIGHTS : 128) * 64, usage },
196
- (frame) => resolve(frame).lightDataBuffer,
197
- );
198
- if (!lightData.ok) return lightData;
199
- const clusterGrid = graph.importBuffer(
200
- 'hdrp-cluster-grid',
201
- { size: storage ? cells * CLUSTER_GRID_STRIDE_U32 * 4 : 32, usage },
202
- (frame) => resolve(frame).clusterGridBuffer,
203
- );
204
- if (!clusterGrid.ok) return clusterGrid;
205
- const lightIndexList = graph.importBuffer(
206
- 'hdrp-light-index-list',
207
- { size: storage ? LIGHT_INDEX_LIST_CAPACITY * 4 : 32, usage },
208
- (frame) => resolve(frame).lightIndexListBuffer,
209
- );
210
- if (!lightIndexList.ok) return lightIndexList;
211
- const clusterUniform = graph.importBuffer(
212
- 'hdrp-cluster-uniform',
213
- { size: 32, usage: GPU_BUFFER_USAGE_UNIFORM | GPU_BUFFER_USAGE_COPY_DST },
214
- (frame) => resolve(frame).clusterUniformBuffer,
215
- );
216
- if (!clusterUniform.ok) return clusterUniform;
217
- const lightBounds = graph.importBuffer(
218
- 'hdrp-light-bounds',
219
- { size: MAX_LIGHTS * 6 * 4, usage },
220
- (frame) => resolve(frame).lightBoundsBuffer,
221
- );
222
- if (!lightBounds.ok) return lightBounds;
223
- return ok({
224
- lightData: lightData.value,
225
- clusterGrid: clusterGrid.value,
226
- lightIndexList: lightIndexList.value,
227
- clusterUniform: clusterUniform.value,
228
- lightBounds: lightBounds.value,
229
- });
230
- }
231
-
232
- function addMembershipPass(
233
- graph: RenderGraphBuilder<RenderPipelineFrame>,
234
- topology: RenderPipelineTopology,
235
- buffers: HdrpGraphBuffers,
236
- ): Result<void, RenderGraphError> {
237
- if (!topology.lane.compute || !topology.lane.storageBuffer) return ok(undefined);
238
- return graph.addComputePass('cluster-membership-producer', {
239
- accesses: [
240
- { resource: buffers.clusterGrid, usage: 'storage-read' },
241
- { resource: buffers.clusterUniform, usage: 'uniform-read' },
242
- { resource: buffers.lightBounds, usage: 'storage-read' },
243
- { resource: buffers.lightIndexList, usage: 'storage-write' },
244
- ],
245
- executeIf: (frame) => {
246
- const internal = frame as _InternalRenderPipelineContext;
247
- return (
248
- internal.pipelineState.hdrpClusterMembershipPipeline !== null &&
249
- internal.hdrpClusterMembershipBindGroup !== null
250
- );
251
- },
252
- encode: ({ pass, frame }) => {
253
- const internal = frame as _InternalRenderPipelineContext;
254
- const pipeline = internal.pipelineState.hdrpClusterMembershipPipeline;
255
- const bindings = internal.hdrpClusterMembershipBindGroup;
256
- if (pipeline === null || bindings === null) return;
257
- const grid = topology.config?.clusterGrid ?? DEFAULT_CLUSTER_GRID;
258
- pass.setPipeline(pipeline);
259
- pass.setBindGroup(0, bindings);
260
- pass.dispatchWorkgroups(Math.ceil((grid.x * grid.y * grid.z) / 64));
261
- },
262
- });
263
- }
264
-
265
- function buildHdrp(
156
+ function buildStandardDeferredLane(
266
157
  context: RenderPipelineBuildContext<RenderPipelineFrame>,
267
158
  topology: RenderPipelineTopology,
159
+ lighting: StandardTopologyInputValue,
268
160
  ): ReturnType<RenderPipeline['build']> {
269
- if (topology.lane.maxColorAttachments < 4) {
270
- return err(new HdrpDeferredCapsInsufficientError(topology.lane.maxColorAttachments));
271
- }
272
161
  const graph = context.graph;
273
162
  const surface = importRenderPipelineSurface(graph, topology);
274
163
  if (!surface.ok) return surface;
275
- const buffers = importBuffers(graph, topology);
164
+ const buffers = importStandardClusterBuffers(graph, lighting);
276
165
  if (!buffers.ok) return buffers;
277
- const membership = addMembershipPass(graph, topology, buffers.value);
166
+ const membership =
167
+ buffers.value === null
168
+ ? ok(undefined)
169
+ : addStandardClusterMembershipPass(graph, lighting, buffers.value);
278
170
  if (!membership.ok) return membership;
279
171
  const shadows = addTypedShadowPasses(graph, topology);
280
172
  if (!shadows.ok) return shadows;
@@ -305,9 +197,7 @@ function buildHdrp(
305
197
  taa: topology.camera.antialias === 'taa',
306
198
  motionBlur: topology.temporal?.motionBlur === true,
307
199
  });
308
- const temporalLane = topology.lane.compute
309
- ? (topology.standardProfile?.lighting ?? 'direct')
310
- : 'cpu-webgl2';
200
+ const temporalLane = topology.lane.compute ? 'clustered' : 'cpu-webgl2';
311
201
  const temporalAdmission = standardTemporalLaneAdmission({
312
202
  lane: temporalLane,
313
203
  demand: temporalDemand,
@@ -330,7 +220,11 @@ function buildHdrp(
330
220
  }),
331
221
  );
332
222
  }
333
-
223
+ const gpuDriven = context.projectGpuDriven({
224
+ format: scene.value.format,
225
+ sampleCount: scene.value.sampleCount,
226
+ });
227
+ if (!gpuDriven.ok) return gpuDriven;
334
228
  const gbuffer = addTypedScenePass(graph, {
335
229
  name: 'g-buffer',
336
230
  color: gbuffer0.value,
@@ -363,25 +257,13 @@ function buildHdrp(
363
257
  { resource: gbuffer1.value.view, usage: 'sampled-read' },
364
258
  { resource: gbuffer2.value.view, usage: 'sampled-read' },
365
259
  { resource: depth.value.view, usage: 'depth-stencil-read' },
366
- {
367
- resource: buffers.value.lightData,
368
- usage: topology.lane.storageBuffer ? 'storage-read' : 'uniform-read',
369
- },
370
- {
371
- resource: buffers.value.clusterGrid,
372
- usage: topology.lane.storageBuffer ? 'storage-read' : 'uniform-read',
373
- },
374
- {
375
- resource: buffers.value.lightIndexList,
376
- usage: topology.lane.storageBuffer ? 'storage-read' : 'uniform-read',
377
- },
378
- { resource: buffers.value.clusterUniform, usage: 'uniform-read' },
260
+ ...(buffers.value === null ? [] : standardClusterReadAccesses(buffers.value)),
379
261
  ...(ssao === undefined
380
262
  ? []
381
263
  : ([{ resource: ssao.view, usage: 'sampled-read' }] satisfies GraphAccess[])),
382
264
  { resource: scene.value.view, usage: 'color-attachment' },
383
265
  ];
384
- const lighting = graph.addRasterPass('lighting', {
266
+ const lightingPass = graph.addRasterPass('lighting', {
385
267
  accesses: lightingAccesses,
386
268
  colorAttachments: [
387
269
  {
@@ -393,7 +275,7 @@ function buildHdrp(
393
275
  ],
394
276
  encode: () => undefined,
395
277
  });
396
- if (!lighting.ok) return lighting;
278
+ if (!lightingPass.ok) return lightingPass;
397
279
 
398
280
  const skybox = addTypedSkyboxPass(graph, scene.value);
399
281
  if (!skybox.ok) return skybox;
@@ -403,21 +285,8 @@ function buildHdrp(
403
285
  demand: transmissionDemand,
404
286
  sourceSampleCount: scene.value.sampleCount,
405
287
  }).active;
406
- const forwardExtraAccesses: GraphAccess[] = [
407
- {
408
- resource: buffers.value.lightData,
409
- usage: topology.lane.storageBuffer ? 'storage-read' : 'uniform-read',
410
- },
411
- {
412
- resource: buffers.value.clusterGrid,
413
- usage: topology.lane.storageBuffer ? 'storage-read' : 'uniform-read',
414
- },
415
- {
416
- resource: buffers.value.lightIndexList,
417
- usage: topology.lane.storageBuffer ? 'storage-read' : 'uniform-read',
418
- },
419
- { resource: buffers.value.clusterUniform, usage: 'uniform-read' },
420
- ];
288
+ const forwardExtraAccesses: GraphAccess[] =
289
+ buffers.value === null ? [] : [...standardClusterReadAccesses(buffers.value)];
421
290
 
422
291
  const forward = addTypedScenePass(graph, {
423
292
  name: 'forward',
@@ -430,16 +299,20 @@ function buildHdrp(
430
299
  gbuffer0.value,
431
300
  gbuffer1.value,
432
301
  gbuffer2.value,
433
- shadows.value.directional,
302
+ ...(shadows.value.directional === undefined ? [] : [shadows.value.directional]),
434
303
  shadows.value.spot,
435
304
  ...(shadows.value.point === undefined ? [] : [shadows.value.point]),
436
305
  ...(ssao === undefined ? [] : [ssao]),
437
306
  ],
438
- directionalShadow: shadows.value.directional,
307
+ ...(shadows.value.directional === undefined
308
+ ? {}
309
+ : { directionalShadow: shadows.value.directional }),
439
310
  spotShadow: shadows.value.spot,
440
311
  ...(ssao === undefined ? {} : { ssao }),
312
+ ...(gpuDriven.value === undefined ? {} : { gpuDriven: gpuDriven.value }),
441
313
  passKind: 'forward',
442
314
  ...(transmissionActive ? { recordMode: 'opaque' as const } : {}),
315
+ ...(context.occlusion === undefined ? {} : { occlusion: context.occlusion }),
443
316
  extraAccesses: forwardExtraAccesses,
444
317
  });
445
318
  if (!forward.ok) return forward;
@@ -472,7 +345,7 @@ function buildHdrp(
472
345
  gbuffer0.value,
473
346
  gbuffer1.value,
474
347
  gbuffer2.value,
475
- shadows.value.directional,
348
+ ...(shadows.value.directional === undefined ? [] : [shadows.value.directional]),
476
349
  shadows.value.spot,
477
350
  ...(shadows.value.point === undefined ? [] : [shadows.value.point]),
478
351
  ...(ssao === undefined ? [] : [ssao]),
@@ -501,7 +374,7 @@ function buildHdrp(
501
374
  gbuffer0.value,
502
375
  gbuffer1.value,
503
376
  gbuffer2.value,
504
- shadows.value.directional,
377
+ ...(shadows.value.directional === undefined ? [] : [shadows.value.directional]),
505
378
  shadows.value.spot,
506
379
  ...(shadows.value.point === undefined ? [] : [shadows.value.point]),
507
380
  ...(ssao === undefined ? [] : [ssao]),
@@ -529,8 +402,9 @@ function buildHdrp(
529
402
  topology,
530
403
  scene.value,
531
404
  depthSample.value,
532
- shadows.value.directional.view,
405
+ shadows.value.directional?.view,
533
406
  shadows.value.spot.view,
407
+ buffers.value,
534
408
  );
535
409
  if (!volume.ok) return volume;
536
410
  }
@@ -556,8 +430,7 @@ function buildHdrp(
556
430
  if (!features.ok) return features;
557
431
  const observation = addTypedFrameObservationPass(graph, scene.value, 'forgeax::standard');
558
432
  if (!observation.ok) return observation;
559
-
560
- return addStandardPost(
433
+ const post = addStandardPost(
561
434
  context,
562
435
  topology,
563
436
  scene.value,
@@ -565,13 +438,19 @@ function buildHdrp(
565
438
  surface.value,
566
439
  temporal.value?.temporal,
567
440
  );
441
+ if (!post.ok) return post;
442
+ const cubeCaptures = context.contributeCubeCaptures?.();
443
+ if (cubeCaptures !== undefined && !cubeCaptures.ok) return cubeCaptures;
444
+ return ok(undefined);
568
445
  }
569
- const buildStandardClusteredLane = buildHdrp;
570
-
571
446
  export interface StandardPipeline extends RenderPipeline {
572
447
  readonly identity: typeof STANDARD_PIPELINE_ID;
573
448
  }
574
449
 
450
+ export function standardProfileSupportsReflectionProbes(_profile: StandardProfile): boolean {
451
+ return true;
452
+ }
453
+
575
454
  /** Standard graph inputs are derived once from the immutable frame plan. */
576
455
  export type StandardFramePlan = FramePlan;
577
456
 
@@ -579,6 +458,43 @@ function profileFor(topology: RenderPipelineTopology): StandardProfile {
579
458
  return topology.standardProfile ?? DEFAULT_STANDARD_PROFILE;
580
459
  }
581
460
 
461
+ function resolveStandardTopologyInput(
462
+ context: RenderPipelineBuildContext<RenderPipelineFrame>,
463
+ ): Result<StandardTopologyInputValue, RenderGraphError> {
464
+ const supplied = context.standardLighting;
465
+ if (supplied !== undefined) {
466
+ const derived = deriveStandardTopologyInput(supplied);
467
+ if (derived.ok) return derived;
468
+ return err(
469
+ new RenderGraphError({
470
+ code: 'resource-descriptor-invalid',
471
+ expected: 'Forward/Deferred consume one prepared Standard topology input',
472
+ hint: derived.error.hint,
473
+ detail: {
474
+ resourceLabel: 'forgeax::standard',
475
+ field: `standardLighting.${derived.error.detail.field}`,
476
+ expected: derived.error.expected,
477
+ actual: 'invalid',
478
+ },
479
+ }),
480
+ );
481
+ }
482
+
483
+ return err(
484
+ new RenderGraphError({
485
+ code: 'resource-descriptor-invalid',
486
+ expected: 'RenderPipelineBuildContext.standardLighting from frame preparation',
487
+ hint: 'prepare Standard lighting once, select a proven Cluster transport, and pass it to both lanes',
488
+ detail: {
489
+ resourceLabel: 'forgeax::standard',
490
+ field: 'standardLighting',
491
+ expected: 'prepared Standard lighting topology input',
492
+ actual: 'invalid',
493
+ },
494
+ }),
495
+ );
496
+ }
497
+
582
498
  function standardTopology(
583
499
  topology: RenderPipelineTopology,
584
500
  profile: StandardProfile,
@@ -596,26 +512,41 @@ function standardTopology(
596
512
  }
597
513
 
598
514
  /**
599
- * The sole built-in pipeline entry point. Direct and clustered lighting are
600
- * execution lanes selected from the same profile and graph owner; callers do
601
- * not install a second topology or submit authority.
515
+ * The sole built-in pipeline entry point. All local lights use the same
516
+ * prepared Cluster topology; the profile chooses only Forward or Deferred
517
+ * graph shape and never a second lighting authority.
602
518
  */
603
519
  function buildStandard(
604
520
  context: RenderPipelineBuildContext<RenderPipelineFrame>,
605
521
  topology: RenderPipelineTopology,
606
522
  ): ReturnType<RenderPipeline['build']> {
607
523
  const profile = profileFor(topology);
608
- const lane = resolveStandardLane(profile, {
609
- compute: topology.lane.compute,
610
- storageBuffer: topology.lane.storageBuffer,
611
- });
524
+ if (!STANDARD_LIGHT_COUNTS.some((count) => count === profile.lightCount)) {
525
+ return err(
526
+ new RenderGraphError({
527
+ code: 'resource-descriptor-invalid',
528
+ expected: 'StandardProfile.lightCount is one of 1, 32, or 256',
529
+ hint: 'set StandardProfile.lightCount to 1, 32, or 256',
530
+ detail: {
531
+ resourceLabel: 'forgeax::standard',
532
+ field: 'lightCount',
533
+ expected: '1 | 32 | 256',
534
+ actual: profile.lightCount,
535
+ },
536
+ }),
537
+ );
538
+ }
612
539
  const effective = standardTopology(topology, profile);
613
- // A missing Camera is an intentional clear-only frame. Keep it on the
614
- // direct raster lane so clustered/HDRP resources cannot introduce work or
615
- // a post-process lookup into this minimal submit contract.
616
- if (effective.clearOnly === true) return buildStandardForwardLane(context, effective);
617
- if (lane === 'clustered') return buildStandardClusteredLane(context, effective);
618
- return buildStandardForwardLane(context, effective);
540
+ const lighting = resolveStandardTopologyInput(context);
541
+ if (!lighting.ok) return lighting;
542
+ // A missing Camera is an intentional clear-only frame. Keep it on the
543
+ // forward raster lane so clustered resources cannot introduce work.
544
+ if (effective.clearOnly === true) {
545
+ return buildStandardForwardLane(context, effective, lighting.value);
546
+ }
547
+ return profile.renderPath === 'forward'
548
+ ? buildStandardForwardLane(context, effective, lighting.value)
549
+ : buildStandardDeferredLane(context, effective, lighting.value);
619
550
  }
620
551
 
621
552
  export const standardPipeline: StandardPipeline = Object.freeze({