@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,389 @@
1
+ import type { Buffer, Result, RhiDevice, Sampler, Texture } from '@forgeax/engine-rhi';
2
+ import { RhiError } from '@forgeax/engine-rhi';
3
+ import { err, ok } from '@forgeax/engine-types';
4
+ import type { DeviceScope } from '../../device/device-scope';
5
+ import { LifecycleTransaction } from '../../device/lifecycle-transaction';
6
+ import {
7
+ GPU_TEXTURE_USAGE_COPY_DST,
8
+ GPU_TEXTURE_USAGE_TEXTURE_BINDING,
9
+ } from '../../gpu-texture-usage';
10
+ import { GPU_BUFFER_USAGE_COPY_DST, GPU_BUFFER_USAGE_UNIFORM } from '../../gpu-usage';
11
+
12
+ export const EXTENDED_LIGHTING_TOPOLOGY = 'extendedLighting' as const;
13
+ export const IES_SLICE_CAPACITY = 32;
14
+ export const COOKIE_SLICE_CAPACITY = 32;
15
+ export const PROBE_RECORD_CAPACITY = 64;
16
+ export const IES_SLICE_WIDTH = 256;
17
+ export const IES_SLICE_HEIGHT = 128;
18
+ export const COOKIE_SLICE_SIZE = 256;
19
+ export const COOKIE_MATRIX_BYTES = 32 * 16 * Float32Array.BYTES_PER_ELEMENT;
20
+ /**
21
+ * Minimum per-stage sampled-texture limit for the shared PBR + extended-
22
+ * lighting pipeline-layout topology. The current BGL closure reserves 18
23
+ * sampled textures for the URP path and 20 for the HDRP/Probe path after the
24
+ * material IBL and transmission injections; WebGPU validates this pipeline-
25
+ * layout count even when a compiled shader variant does not read every
26
+ * optional entry.
27
+ */
28
+ export const EXTENDED_LIGHTING_REQUIRED_SAMPLED_TEXTURES = 20;
29
+
30
+ /**
31
+ * Keep shader-variant selection and resource admission on one capability fact.
32
+ * An omitted limit is treated as unavailable: a caller must not claim the
33
+ * extended topology without a numeric device limit proving it fits.
34
+ */
35
+ export function extendedLightingSampledTextureCapacityAvailable(
36
+ maxSampledTexturesPerShaderStage: number | undefined,
37
+ ): boolean {
38
+ return (
39
+ maxSampledTexturesPerShaderStage !== undefined &&
40
+ maxSampledTexturesPerShaderStage >= EXTENDED_LIGHTING_REQUIRED_SAMPLED_TEXTURES
41
+ );
42
+ }
43
+
44
+ export interface ExtendedLightingCapabilityResult {
45
+ readonly admitted: boolean;
46
+ readonly topology: typeof EXTENDED_LIGHTING_TOPOLOGY;
47
+ readonly reason: string | undefined;
48
+ }
49
+
50
+ export interface ExtendedLightingResourceInput {
51
+ readonly device: RhiDevice | undefined;
52
+ readonly scope: DeviceScope;
53
+ readonly iesSliceCount: number;
54
+ readonly cookieSliceCount: number;
55
+ readonly cookieMatrices: number;
56
+ readonly iesData?: Uint8Array | undefined;
57
+ readonly cookieData?: Uint8Array | undefined;
58
+ readonly cookieMatrixData?: Float32Array | undefined;
59
+ }
60
+
61
+ export interface ExtendedLightingResourceCandidate {
62
+ readonly topology: typeof EXTENDED_LIGHTING_TOPOLOGY;
63
+ readonly generation: number;
64
+ readonly scope: DeviceScope;
65
+ readonly iesSliceCount: number;
66
+ readonly cookieSliceCount: number;
67
+ readonly cookieMatrices: number;
68
+ readonly sampler: Sampler;
69
+ readonly iesTexture: Texture | undefined;
70
+ readonly cookieTexture: Texture | undefined;
71
+ readonly cookieMatrixBuffer: Buffer | undefined;
72
+ readonly descriptorBytes: number;
73
+ readonly uploadCount: number;
74
+ }
75
+
76
+ export interface ExtendedLightingResourceInspection {
77
+ readonly topology: typeof EXTENDED_LIGHTING_TOPOLOGY;
78
+ readonly generation: number;
79
+ readonly status: 'empty' | 'candidate' | 'accepted';
80
+ readonly accepted: boolean;
81
+ readonly resourceCount: number;
82
+ readonly descriptorBytes: number;
83
+ readonly uploadCount: number;
84
+ readonly blendInvalidations: number;
85
+ readonly passCount: number;
86
+ }
87
+
88
+ function failure(expected: string, actual: string): Result<never, RhiError> {
89
+ return err(
90
+ new RhiError({
91
+ code: 'webgpu-runtime-error',
92
+ expected,
93
+ hint: 'repair the extended lighting resource facts and retry the candidate generation',
94
+ detail: { error: { code: 'extended-lighting-resource', message: actual } },
95
+ }),
96
+ );
97
+ }
98
+
99
+ function validCount(value: number, capacity: number): boolean {
100
+ return Number.isSafeInteger(value) && value >= 0 && value <= capacity;
101
+ }
102
+
103
+ /** Derive admission from the RHI facts; no backend-kind policy is involved. */
104
+ export function deriveExtendedLightingCapability(
105
+ device: Pick<RhiDevice, 'caps' | 'limits'>,
106
+ ): ExtendedLightingCapabilityResult {
107
+ const maxSampledTextures = device.limits.maxSampledTexturesPerShaderStage;
108
+ if (!extendedLightingSampledTextureCapacityAvailable(maxSampledTextures)) {
109
+ return {
110
+ admitted: false,
111
+ topology: EXTENDED_LIGHTING_TOPOLOGY,
112
+ reason: `maxSampledTexturesPerShaderStage ${maxSampledTextures ?? 0} < ${EXTENDED_LIGHTING_REQUIRED_SAMPLED_TEXTURES}`,
113
+ };
114
+ }
115
+ const maxLayers = device.limits.maxTextureArrayLayers ?? 0;
116
+ const maxUniformBuffers = device.limits.maxUniformBuffersPerShaderStage ?? 0;
117
+ if (maxLayers < IES_SLICE_CAPACITY) {
118
+ return {
119
+ admitted: false,
120
+ topology: EXTENDED_LIGHTING_TOPOLOGY,
121
+ reason: `maxTextureArrayLayers ${maxLayers} < ${IES_SLICE_CAPACITY}`,
122
+ };
123
+ }
124
+ if (maxUniformBuffers < 1) {
125
+ return {
126
+ admitted: false,
127
+ topology: EXTENDED_LIGHTING_TOPOLOGY,
128
+ reason: `maxUniformBuffersPerShaderStage ${maxUniformBuffers} < 1`,
129
+ };
130
+ }
131
+ if (
132
+ !device.caps.storageBuffer ||
133
+ !device.caps.rgba16floatRenderable ||
134
+ !device.caps.samplerAliasing
135
+ ) {
136
+ return {
137
+ admitted: false,
138
+ topology: EXTENDED_LIGHTING_TOPOLOGY,
139
+ reason: 'required storage-buffer, rgba16float, or sampler capability is unavailable',
140
+ };
141
+ }
142
+ return { admitted: true, topology: EXTENDED_LIGHTING_TOPOLOGY, reason: undefined };
143
+ }
144
+
145
+ function createTexture(
146
+ device: RhiDevice,
147
+ label: string,
148
+ format: 'r16float' | 'rgba8unorm',
149
+ width: number,
150
+ height: number,
151
+ layers: number,
152
+ ): Result<Texture, RhiError> {
153
+ return device.createTexture({
154
+ label,
155
+ size: { width, height, depthOrArrayLayers: layers },
156
+ mipLevelCount: 1,
157
+ sampleCount: 1,
158
+ dimension: '2d',
159
+ format,
160
+ usage: GPU_TEXTURE_USAGE_COPY_DST | GPU_TEXTURE_USAGE_TEXTURE_BINDING,
161
+ viewFormats: [],
162
+ textureBindingViewDimension: undefined,
163
+ });
164
+ }
165
+
166
+ function requireResource<T>(result: Result<T, RhiError>): T {
167
+ if (!result.ok) throw result.error;
168
+ return result.value;
169
+ }
170
+
171
+ function writeTextureSlices(
172
+ device: RhiDevice,
173
+ texture: Texture,
174
+ data: Uint8Array | undefined,
175
+ bytesPerRow: number,
176
+ height: number,
177
+ layerCount: number,
178
+ width: number,
179
+ ): number {
180
+ if (data === undefined || layerCount === 0) return 0;
181
+ const bytesPerSlice = bytesPerRow * height;
182
+ const requiredBytes = bytesPerSlice * layerCount;
183
+ if (data.byteLength < requiredBytes) {
184
+ throw new Error(`extended lighting texture upload requires ${requiredBytes} bytes`);
185
+ }
186
+ for (let layer = 0; layer < layerCount; layer += 1) {
187
+ const start = layer * bytesPerSlice;
188
+ requireResource(
189
+ device.queue.writeTexture(
190
+ { texture, mipLevel: 0, origin: { x: 0, y: 0, z: layer } },
191
+ data.subarray(start, start + bytesPerSlice),
192
+ { offset: 0, bytesPerRow, rowsPerImage: height },
193
+ { width, height, depthOrArrayLayers: 1 },
194
+ ),
195
+ );
196
+ }
197
+ return layerCount;
198
+ }
199
+
200
+ /** Build a complete candidate; nothing is adopted until the transaction commits. */
201
+ export async function createExtendedLightingResourceCandidate(
202
+ input: ExtendedLightingResourceInput,
203
+ ): Promise<Result<ExtendedLightingResourceCandidate, RhiError>> {
204
+ const { device, scope } = input;
205
+ if (device === undefined) return failure('a live RHI device is required', 'device is undefined');
206
+ if (!validCount(input.iesSliceCount, IES_SLICE_CAPACITY)) {
207
+ return failure(`IES slice count <= ${IES_SLICE_CAPACITY}`, String(input.iesSliceCount));
208
+ }
209
+ if (!validCount(input.cookieSliceCount, COOKIE_SLICE_CAPACITY)) {
210
+ return failure(
211
+ `Cookie slice count <= ${COOKIE_SLICE_CAPACITY}`,
212
+ String(input.cookieSliceCount),
213
+ );
214
+ }
215
+ if (!validCount(input.cookieMatrices, COOKIE_SLICE_CAPACITY)) {
216
+ return failure(`Cookie matrix count <= ${COOKIE_SLICE_CAPACITY}`, String(input.cookieMatrices));
217
+ }
218
+ const capability = deriveExtendedLightingCapability(device);
219
+ if (!capability.admitted)
220
+ return failure('extendedLighting capability admission', capability.reason ?? 'unavailable');
221
+ if (
222
+ input.cookieMatrixData !== undefined &&
223
+ input.cookieMatrixData.byteLength < input.cookieMatrices * 16 * Float32Array.BYTES_PER_ELEMENT
224
+ ) {
225
+ return failure(
226
+ 'cookie matrix upload payload',
227
+ `requires ${input.cookieMatrices * 16 * Float32Array.BYTES_PER_ELEMENT} bytes`,
228
+ );
229
+ }
230
+
231
+ const transaction = new LifecycleTransaction(scope);
232
+ let iesTexture: Texture | undefined;
233
+ let cookieTexture: Texture | undefined;
234
+ let cookieMatrixBuffer: Buffer | undefined;
235
+ let sampler: Sampler | undefined;
236
+ let uploadCount = 0;
237
+ transaction.add({
238
+ kind: 'texture',
239
+ create: () => {
240
+ const created = requireResource(
241
+ createTexture(
242
+ device,
243
+ 'extended-lighting-ies',
244
+ 'r16float',
245
+ IES_SLICE_WIDTH,
246
+ IES_SLICE_HEIGHT,
247
+ IES_SLICE_CAPACITY,
248
+ ),
249
+ );
250
+ uploadCount += writeTextureSlices(
251
+ device,
252
+ created,
253
+ input.iesData,
254
+ IES_SLICE_WIDTH * 2,
255
+ IES_SLICE_HEIGHT,
256
+ input.iesSliceCount,
257
+ IES_SLICE_WIDTH,
258
+ );
259
+ iesTexture = created;
260
+ return created;
261
+ },
262
+ cleanup: (value) => {
263
+ const destroyed = device.destroyTexture(value);
264
+ if (!destroyed.ok) throw destroyed.error;
265
+ },
266
+ });
267
+ transaction.add({
268
+ kind: 'texture',
269
+ create: () => {
270
+ const created = requireResource(
271
+ createTexture(
272
+ device,
273
+ 'extended-lighting-cookie',
274
+ 'rgba8unorm',
275
+ COOKIE_SLICE_SIZE,
276
+ COOKIE_SLICE_SIZE,
277
+ COOKIE_SLICE_CAPACITY,
278
+ ),
279
+ );
280
+ uploadCount += writeTextureSlices(
281
+ device,
282
+ created,
283
+ input.cookieData,
284
+ COOKIE_SLICE_SIZE * 4,
285
+ COOKIE_SLICE_SIZE,
286
+ input.cookieSliceCount,
287
+ COOKIE_SLICE_SIZE,
288
+ );
289
+ cookieTexture = created;
290
+ return created;
291
+ },
292
+ cleanup: (value) => {
293
+ const destroyed = device.destroyTexture(value);
294
+ if (!destroyed.ok) throw destroyed.error;
295
+ },
296
+ });
297
+ transaction.add({
298
+ kind: 'buffer',
299
+ create: () => {
300
+ const created = requireResource(
301
+ device.createBuffer({
302
+ label: 'extended-lighting-cookie-matrices',
303
+ size: COOKIE_MATRIX_BYTES,
304
+ usage: GPU_BUFFER_USAGE_COPY_DST | GPU_BUFFER_USAGE_UNIFORM,
305
+ mappedAtCreation: false,
306
+ }),
307
+ );
308
+ if (input.cookieMatrixData !== undefined && input.cookieMatrices > 0) {
309
+ requireResource(device.queue.writeBuffer(created, 0, input.cookieMatrixData));
310
+ uploadCount += 1;
311
+ }
312
+ cookieMatrixBuffer = created;
313
+ return created;
314
+ },
315
+ cleanup: (value) => {
316
+ const destroyed = device.destroyBuffer(value);
317
+ if (!destroyed.ok) throw destroyed.error;
318
+ },
319
+ });
320
+ transaction.add({
321
+ // Samplers are bindable GPU resources, not host listeners. Keeping the
322
+ // lifecycle kind aligned with the resource's actual renderer role makes
323
+ // scope inspection and rollback receipts truthful.
324
+ kind: 'binding',
325
+ create: () => {
326
+ const created = requireResource(
327
+ device.createSampler({
328
+ label: 'extended-lighting-clamp-linear',
329
+ addressModeU: 'clamp-to-edge',
330
+ addressModeV: 'clamp-to-edge',
331
+ addressModeW: 'clamp-to-edge',
332
+ magFilter: 'linear',
333
+ minFilter: 'linear',
334
+ mipmapFilter: 'nearest',
335
+ }),
336
+ );
337
+ sampler = created;
338
+ return created;
339
+ },
340
+ cleanup: () => undefined,
341
+ });
342
+ const committed = await transaction.commit();
343
+ if (!committed.ok)
344
+ return failure(committed.error.primary.expected, committed.error.primary.message);
345
+ if (
346
+ iesTexture === undefined ||
347
+ cookieTexture === undefined ||
348
+ cookieMatrixBuffer === undefined ||
349
+ sampler === undefined
350
+ ) {
351
+ return failure(
352
+ 'complete extendedLighting candidate resources',
353
+ 'resource transaction returned an incomplete set',
354
+ );
355
+ }
356
+ return ok({
357
+ topology: EXTENDED_LIGHTING_TOPOLOGY,
358
+ generation: scope.generation,
359
+ scope,
360
+ iesSliceCount: input.iesSliceCount,
361
+ cookieSliceCount: input.cookieSliceCount,
362
+ cookieMatrices: input.cookieMatrices,
363
+ sampler,
364
+ iesTexture,
365
+ cookieTexture,
366
+ cookieMatrixBuffer,
367
+ descriptorBytes:
368
+ IES_SLICE_WIDTH * IES_SLICE_HEIGHT * 2 * IES_SLICE_CAPACITY +
369
+ COOKIE_SLICE_SIZE * COOKIE_SLICE_SIZE * 4 * COOKIE_SLICE_CAPACITY +
370
+ COOKIE_MATRIX_BYTES,
371
+ uploadCount,
372
+ });
373
+ }
374
+
375
+ export function inspectExtendedLightingResources(
376
+ scope: DeviceScope,
377
+ ): ExtendedLightingResourceInspection {
378
+ return {
379
+ topology: EXTENDED_LIGHTING_TOPOLOGY,
380
+ generation: scope.generation,
381
+ status: 'empty',
382
+ accepted: false,
383
+ resourceCount: 0,
384
+ descriptorBytes: 0,
385
+ uploadCount: 0,
386
+ blendInvalidations: 0,
387
+ passCount: 0,
388
+ };
389
+ }
@@ -0,0 +1,194 @@
1
+ import type { TextureAsset } from '@forgeax/engine-types';
2
+ import { COOKIE_SLICE_SIZE } from './resources';
3
+
4
+ export interface SpotModifierFactors {
5
+ readonly brdf: number;
6
+ readonly range: number;
7
+ readonly cone: number;
8
+ readonly ies?: number | undefined;
9
+ readonly cookie?: number | undefined;
10
+ readonly shadow: number;
11
+ }
12
+
13
+ export interface IesCoordinates {
14
+ readonly azimuth: number;
15
+ readonly elevation: number;
16
+ }
17
+
18
+ export interface CookieUv {
19
+ readonly u: number;
20
+ readonly v: number;
21
+ }
22
+
23
+ /**
24
+ * The fixed GPU representation consumed by the extended-lighting Cookie
25
+ * array. The matrix is deliberately keyed by Cookie slice rather than by
26
+ * light: it carries only the source texture aspect correction. The shader
27
+ * still owns the light-local basis, roll, and outer-cone projection, so one
28
+ * Cookie can be shared by Spots with different directions or cone angles.
29
+ */
30
+ export interface CookieProjection {
31
+ readonly data: Uint8Array;
32
+ readonly matrix: Float32Array;
33
+ readonly aspect: number;
34
+ }
35
+
36
+ const DEG_TO_RAD = Math.PI / 180;
37
+
38
+ const COOKIE_PROJECTION_CACHE = new WeakMap<TextureAsset, CookieProjection | null>();
39
+
40
+ function srgbToLinear(value: number): number {
41
+ return value <= 0.04045 ? value / 12.92 : ((value + 0.055) / 1.055) ** 2.4;
42
+ }
43
+
44
+ function clamp01(value: number): number {
45
+ return Math.min(1, Math.max(0, value));
46
+ }
47
+
48
+ function sourceChannel(asset: TextureAsset, x: number, y: number, channel: number): number {
49
+ const offset = (y * asset.shape.extent.width + x) * 4 + channel;
50
+ const encoded = (asset.data[offset] ?? 0) / 255;
51
+ return channel < 3 && asset.colorSpace === 'srgb' ? srgbToLinear(encoded) : encoded;
52
+ }
53
+
54
+ function sampleSourceChannel(asset: TextureAsset, x: number, y: number, channel: number): number {
55
+ const sourceX = clamp01((x + 0.5) / COOKIE_SLICE_SIZE) * (asset.shape.extent.width - 1);
56
+ const sourceY = clamp01((y + 0.5) / COOKIE_SLICE_SIZE) * (asset.shape.extent.height - 1);
57
+ const x0 = Math.floor(sourceX);
58
+ const y0 = Math.floor(sourceY);
59
+ const x1 = Math.min(asset.shape.extent.width - 1, x0 + 1);
60
+ const y1 = Math.min(asset.shape.extent.height - 1, y0 + 1);
61
+ const tx = sourceX - x0;
62
+ const ty = sourceY - y0;
63
+ const top =
64
+ sourceChannel(asset, x0, y0, channel) * (1 - tx) + sourceChannel(asset, x1, y0, channel) * tx;
65
+ const bottom =
66
+ sourceChannel(asset, x0, y1, channel) * (1 - tx) + sourceChannel(asset, x1, y1, channel) * tx;
67
+ return top * (1 - ty) + bottom * ty;
68
+ }
69
+
70
+ /**
71
+ * Project a filterable 2D RGBA Cookie into the renderer's fixed linear
72
+ * 256x256 array slice. This is a producer-boundary operation and is cached by
73
+ * the immutable TextureAsset object, so the frame path never decodes or
74
+ * resamples the source repeatedly.
75
+ */
76
+ export function prepareCookieProjection(asset: TextureAsset): CookieProjection | undefined {
77
+ if (COOKIE_PROJECTION_CACHE.has(asset)) {
78
+ return COOKIE_PROJECTION_CACHE.get(asset) ?? undefined;
79
+ }
80
+ const supportedFormat = asset.format === 'rgba8unorm' || asset.format === 'rgba8unorm-srgb';
81
+ const validDimensions =
82
+ Number.isSafeInteger(asset.shape.extent.width) &&
83
+ Number.isSafeInteger(asset.shape.extent.height) &&
84
+ asset.shape.extent.width > 0 &&
85
+ asset.shape.extent.height > 0;
86
+ const validFormatPair =
87
+ (asset.format === 'rgba8unorm-srgb' && asset.colorSpace === 'srgb') ||
88
+ (asset.format === 'rgba8unorm' && asset.colorSpace === 'linear');
89
+ const validPayload =
90
+ asset.data.byteLength >= asset.shape.extent.width * asset.shape.extent.height * 4;
91
+ if (!supportedFormat || !validDimensions || !validFormatPair || !validPayload) {
92
+ COOKIE_PROJECTION_CACHE.set(asset, null);
93
+ return undefined;
94
+ }
95
+
96
+ const data = new Uint8Array(COOKIE_SLICE_SIZE * COOKIE_SLICE_SIZE * 4);
97
+ for (let y = 0; y < COOKIE_SLICE_SIZE; y += 1) {
98
+ for (let x = 0; x < COOKIE_SLICE_SIZE; x += 1) {
99
+ const target = (y * COOKIE_SLICE_SIZE + x) * 4;
100
+ data[target] = Math.round(clamp01(sampleSourceChannel(asset, x, y, 0)) * 255);
101
+ data[target + 1] = Math.round(clamp01(sampleSourceChannel(asset, x, y, 1)) * 255);
102
+ data[target + 2] = Math.round(clamp01(sampleSourceChannel(asset, x, y, 2)) * 255);
103
+ // Alpha stays linear and is intentionally preserved: the shader
104
+ // multiplies sampled RGB by this lane as part of Cookie semantics.
105
+ data[target + 3] = Math.round(clamp01(sampleSourceChannel(asset, x, y, 3)) * 255);
106
+ }
107
+ }
108
+
109
+ // Column-major mat4. The shader multiplies the unprojected local
110
+ // (x/depth, y/depth) pair by this aspect-only matrix, then applies the
111
+ // Spot's outer-cone tangent and the [0,1] translation. Keeping outerCone
112
+ // out of this slice-keyed matrix allows one Cookie to be shared by lights.
113
+ const matrix = new Float32Array(16);
114
+ matrix[0] = asset.shape.extent.height / asset.shape.extent.width;
115
+ matrix[5] = 1;
116
+ matrix[10] = 1;
117
+ matrix[15] = 1;
118
+ const projection = {
119
+ data,
120
+ matrix,
121
+ aspect: asset.shape.extent.width / asset.shape.extent.height,
122
+ };
123
+ COOKIE_PROJECTION_CACHE.set(asset, projection);
124
+ return projection;
125
+ }
126
+
127
+ /** Create the deterministic identity payload used for unused Cookie slices. */
128
+ export function createCookieProjectionMatrixData(count: number): Float32Array {
129
+ const data = new Float32Array(count * 16);
130
+ for (let index = 0; index < count; index += 1) {
131
+ const base = index * 16;
132
+ data[base] = 1;
133
+ data[base + 5] = 1;
134
+ data[base + 10] = 1;
135
+ data[base + 15] = 1;
136
+ }
137
+ return data;
138
+ }
139
+
140
+ function normalized(vector: ArrayLike<number>): [number, number, number] | undefined {
141
+ const x = vector[0] ?? 0;
142
+ const y = vector[1] ?? 0;
143
+ const z = vector[2] ?? 0;
144
+ const length = Math.hypot(x, y, z);
145
+ return length > 0 && Number.isFinite(length) ? [x / length, y / length, z / length] : undefined;
146
+ }
147
+
148
+ export function spotModifierProduct(factors: SpotModifierFactors): number {
149
+ return (
150
+ factors.brdf *
151
+ factors.range *
152
+ factors.cone *
153
+ (factors.ies ?? 1) *
154
+ (factors.cookie ?? 1) *
155
+ factors.shadow
156
+ );
157
+ }
158
+
159
+ export function projectIesCoordinates(
160
+ toPoint: ArrayLike<number>,
161
+ rollDeg: number,
162
+ ): IesCoordinates | undefined {
163
+ const direction = normalized(toPoint);
164
+ if (direction === undefined || direction[2] >= 0) return undefined;
165
+ const roll = rollDeg * DEG_TO_RAD;
166
+ const rolledX = direction[0] * Math.cos(roll) - direction[1] * Math.sin(roll);
167
+ const rolledY = direction[0] * Math.sin(roll) + direction[1] * Math.cos(roll);
168
+ return {
169
+ azimuth: (Math.atan2(rolledY, rolledX) + Math.PI * 2) % (Math.PI * 2),
170
+ elevation: Math.acos(Math.min(1, Math.max(-1, -direction[2]))) / Math.PI,
171
+ };
172
+ }
173
+
174
+ export function projectCookieUv(
175
+ toPoint: ArrayLike<number>,
176
+ rollDeg: number,
177
+ aspect: number,
178
+ outerConeDeg = 45,
179
+ ): CookieUv | undefined {
180
+ const direction = normalized(toPoint);
181
+ if (direction === undefined || direction[2] >= 0 || !Number.isFinite(aspect) || aspect <= 0)
182
+ return undefined;
183
+ const cone = Math.atan2(Math.hypot(direction[0], direction[1]), -direction[2]);
184
+ const outerCone = outerConeDeg * DEG_TO_RAD;
185
+ if (cone > outerCone) return undefined;
186
+ const roll = rollDeg * DEG_TO_RAD;
187
+ const x = direction[0] * Math.cos(roll) - direction[1] * Math.sin(roll);
188
+ const y = direction[0] * Math.sin(roll) + direction[1] * Math.cos(roll);
189
+ const scale = Math.tan(outerCone);
190
+ return {
191
+ u: 0.5 + (x / -direction[2] / scale / aspect) * 0.5,
192
+ v: 0.5 + (y / -direction[2] / scale) * 0.5,
193
+ };
194
+ }
@@ -0,0 +1,92 @@
1
+ import type { LightResourceUnavailableError } from '../../errors/render';
2
+ import {
3
+ type LightInspection,
4
+ lightInspectionIdentity,
5
+ projectLightInspection,
6
+ } from '../../inspection-types';
7
+ import type { ExtendedLightingResourceCandidate } from './resources';
8
+
9
+ export type ExtendedLightingResourceStatus = 'empty' | 'candidate' | 'accepted';
10
+
11
+ export interface ExtendedLightingState {
12
+ readonly enabled: boolean;
13
+ readonly generation: number;
14
+ readonly status: ExtendedLightingResourceStatus;
15
+ readonly candidate: ExtendedLightingResourceCandidate | undefined;
16
+ readonly accepted: ExtendedLightingResourceCandidate | undefined;
17
+ readonly lastKnownGood: ExtendedLightingResourceCandidate | undefined;
18
+ readonly resourceCount: number;
19
+ readonly descriptorBytes: number;
20
+ readonly uploadCount: number;
21
+ readonly passCount: number;
22
+ readonly bindGroupCount: number;
23
+ readonly failure: LightResourceUnavailableError | undefined;
24
+ readonly failureKeys: readonly string[];
25
+ }
26
+
27
+ export function createExtendedLightingState(generation: number): ExtendedLightingState {
28
+ return {
29
+ enabled: false,
30
+ generation,
31
+ status: 'empty',
32
+ candidate: undefined,
33
+ accepted: undefined,
34
+ lastKnownGood: undefined,
35
+ resourceCount: 0,
36
+ descriptorBytes: 0,
37
+ uploadCount: 0,
38
+ passCount: 0,
39
+ bindGroupCount: 0,
40
+ failure: undefined,
41
+ failureKeys: [],
42
+ };
43
+ }
44
+
45
+ export function promoteExtendedLightingCandidate(
46
+ state: ExtendedLightingState,
47
+ candidate: ExtendedLightingResourceCandidate | undefined,
48
+ ): ExtendedLightingState {
49
+ if (candidate === undefined) return state;
50
+ return {
51
+ ...state,
52
+ enabled: true,
53
+ generation: candidate.generation,
54
+ status: 'accepted',
55
+ candidate: undefined,
56
+ accepted: candidate,
57
+ lastKnownGood: candidate,
58
+ resourceCount: 4,
59
+ descriptorBytes: candidate.descriptorBytes,
60
+ uploadCount: candidate.uploadCount,
61
+ };
62
+ }
63
+
64
+ export function recordExtendedLightingFailure(
65
+ state: ExtendedLightingState,
66
+ failure: LightResourceUnavailableError,
67
+ ): ExtendedLightingState {
68
+ const key = `${failure.detail.entity}:${failure.detail.feature}:${failure.detail.generation}`;
69
+ if (state.failureKeys.includes(key)) return state;
70
+ return {
71
+ ...state,
72
+ failure,
73
+ failureKeys: [...state.failureKeys, key],
74
+ };
75
+ }
76
+
77
+ export function projectExtendedLightingInspection(state: ExtendedLightingState): LightInspection {
78
+ const identity = (candidate: ExtendedLightingResourceCandidate | undefined) =>
79
+ candidate === undefined
80
+ ? undefined
81
+ : lightInspectionIdentity(candidate.topology, candidate.generation);
82
+ return projectLightInspection({
83
+ generation: state.generation,
84
+ candidate: identity(state.candidate),
85
+ accepted: identity(state.accepted),
86
+ lastKnownGood: identity(state.lastKnownGood),
87
+ failure: state.failure?.code,
88
+ failureKeys: state.failureKeys,
89
+ resourceCount: state.resourceCount,
90
+ uploadBytes: state.descriptorBytes,
91
+ });
92
+ }