@forgeax/engine-render 0.1.21 → 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 (426) hide show
  1. package/README.md +150 -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.map +1 -1
  5. package/dist/assembly/factory.d.ts +14 -6
  6. package/dist/assembly/factory.d.ts.map +1 -1
  7. package/dist/assembly/host-contract.d.ts +10 -0
  8. package/dist/assembly/host-contract.d.ts.map +1 -1
  9. package/dist/authoring.mjs +1 -1
  10. package/dist/{chunk-PCHBPYML.mjs → chunk-4L3P6DT5.mjs} +2 -2
  11. package/dist/chunk-4L3P6DT5.mjs.map +1 -0
  12. package/dist/{chunk-VFPLTKCU.mjs → chunk-4NPUASZR.mjs} +15 -4
  13. package/dist/chunk-4NPUASZR.mjs.map +1 -0
  14. package/dist/chunk-DIYW3M5D.mjs +5085 -0
  15. package/dist/chunk-DIYW3M5D.mjs.map +1 -0
  16. package/dist/chunk-FBC4R44J.mjs +1003 -0
  17. package/dist/chunk-FBC4R44J.mjs.map +1 -0
  18. package/dist/{chunk-FS2KNUQH.mjs → chunk-FF7K3FSO.mjs} +253 -489
  19. package/dist/chunk-FF7K3FSO.mjs.map +1 -0
  20. package/dist/chunk-HZUPSYW7.mjs +1104 -0
  21. package/dist/chunk-HZUPSYW7.mjs.map +1 -0
  22. package/dist/{chunk-6OPXDQ2E.mjs → chunk-QODA5UKU.mjs} +33 -294
  23. package/dist/chunk-QODA5UKU.mjs.map +1 -0
  24. package/dist/chunk-YALPS44A.mjs +296 -0
  25. package/dist/chunk-YALPS44A.mjs.map +1 -0
  26. package/dist/{chunk-5YADUCA7.mjs → chunk-ZUWKAZ2I.mjs} +585 -991
  27. package/dist/chunk-ZUWKAZ2I.mjs.map +1 -0
  28. package/dist/cluster-binner.d.ts +5 -0
  29. package/dist/cluster-binner.d.ts.map +1 -1
  30. package/dist/components/index.d.ts +3 -0
  31. package/dist/components/index.d.ts.map +1 -1
  32. package/dist/components/light-helpers.d.ts +4 -0
  33. package/dist/components/light-helpers.d.ts.map +1 -1
  34. package/dist/components/light-probe.d.ts +9 -0
  35. package/dist/components/light-probe.d.ts.map +1 -0
  36. package/dist/components/rect-area-light.d.ts +12 -0
  37. package/dist/components/rect-area-light.d.ts.map +1 -0
  38. package/dist/components/scene-instance.d.ts +4 -0
  39. package/dist/components/scene-instance.d.ts.map +1 -1
  40. package/dist/components/spot-light.d.ts +3 -0
  41. package/dist/components/spot-light.d.ts.map +1 -1
  42. package/dist/construct-renderer.mjs +10437 -10044
  43. package/dist/construct-renderer.mjs.map +1 -1
  44. package/dist/device/gpu-residency.d.ts +8 -1
  45. package/dist/device/gpu-residency.d.ts.map +1 -1
  46. package/dist/device/lifecycle-transaction.d.ts +2 -0
  47. package/dist/device/lifecycle-transaction.d.ts.map +1 -0
  48. package/dist/environment/lifecycle.d.ts.map +1 -1
  49. package/dist/errors/gpu-driven.d.ts +26 -0
  50. package/dist/errors/gpu-driven.d.ts.map +1 -0
  51. package/dist/errors/index.d.ts +1 -0
  52. package/dist/errors/index.d.ts.map +1 -1
  53. package/dist/errors/recover.d.ts +9 -1
  54. package/dist/errors/recover.d.ts.map +1 -1
  55. package/dist/errors/render.d.ts +26 -1
  56. package/dist/errors/render.d.ts.map +1 -1
  57. package/dist/extract/gpu-driven.d.ts +50 -0
  58. package/dist/extract/gpu-driven.d.ts.map +1 -0
  59. package/dist/extract/visibility.d.ts.map +1 -1
  60. package/dist/gpu-driven/batch-topology.d.ts +34 -0
  61. package/dist/gpu-driven/batch-topology.d.ts.map +1 -1
  62. package/dist/gpu-driven/prepared-draw.d.ts +63 -0
  63. package/dist/gpu-driven/prepared-draw.d.ts.map +1 -0
  64. package/dist/gpu-driven/production-raster.d.ts +98 -2
  65. package/dist/gpu-driven/production-raster.d.ts.map +1 -1
  66. package/dist/gpu-driven/view-gpu.d.ts +64 -1
  67. package/dist/gpu-driven/view-gpu.d.ts.map +1 -1
  68. package/dist/gpu-scene-schema.d.ts +14 -0
  69. package/dist/gpu-scene-schema.d.ts.map +1 -1
  70. package/dist/gpu-scene.d.ts +8 -1
  71. package/dist/gpu-scene.d.ts.map +1 -1
  72. package/dist/gpu-usage.d.ts +0 -1
  73. package/dist/gpu-usage.d.ts.map +1 -1
  74. package/dist/hdrp-buffers.d.ts +3 -3
  75. package/dist/hdrp-buffers.d.ts.map +1 -1
  76. package/dist/index.d.ts +12 -1
  77. package/dist/index.d.ts.map +1 -1
  78. package/dist/index.mjs +90 -5
  79. package/dist/index.mjs.map +1 -1
  80. package/dist/inspection-types.d.ts +163 -1
  81. package/dist/inspection-types.d.ts.map +1 -1
  82. package/dist/internal.d.ts +9 -0
  83. package/dist/internal.d.ts.map +1 -1
  84. package/dist/internal.mjs +23 -2
  85. package/dist/internal.mjs.map +1 -1
  86. package/dist/light-buffer-layout.d.ts +58 -149
  87. package/dist/light-buffer-layout.d.ts.map +1 -1
  88. package/dist/materials.d.ts.map +1 -1
  89. package/dist/pbr-pipeline.d.ts +26 -12
  90. package/dist/pbr-pipeline.d.ts.map +1 -1
  91. package/dist/pipeline/standard-forward-lane.d.ts.map +1 -1
  92. package/dist/pipeline/standard-lighting/graph.d.ts.map +1 -1
  93. package/dist/pipeline/standard-lighting/light-frame.d.ts +3 -3
  94. package/dist/pipeline/standard-lighting/light-frame.d.ts.map +1 -1
  95. package/dist/pipeline/standard-lighting/topology.d.ts +1 -1
  96. package/dist/pipeline/standard-lighting/topology.d.ts.map +1 -1
  97. package/dist/pipeline/standard-lighting/transport.d.ts.map +1 -1
  98. package/dist/pipeline/standard-pipeline.d.ts.map +1 -1
  99. package/dist/pipeline-builder.d.ts +2 -0
  100. package/dist/pipeline-builder.d.ts.map +1 -1
  101. package/dist/pipeline-spec.d.ts +1 -1
  102. package/dist/pipeline-spec.d.ts.map +1 -1
  103. package/dist/plugin.d.ts.map +1 -1
  104. package/dist/prepare/extended-lighting/ltc-resources.d.ts +31 -0
  105. package/dist/prepare/extended-lighting/ltc-resources.d.ts.map +1 -0
  106. package/dist/prepare/extended-lighting/resources.d.ts +72 -0
  107. package/dist/prepare/extended-lighting/resources.d.ts.map +1 -0
  108. package/dist/prepare/extended-lighting/spot-modifiers.d.ts +42 -0
  109. package/dist/prepare/extended-lighting/spot-modifiers.d.ts.map +1 -0
  110. package/dist/prepare/extended-lighting/state.d.ts +24 -0
  111. package/dist/prepare/extended-lighting/state.d.ts.map +1 -0
  112. package/dist/record/frame-lighting.d.ts +8 -6
  113. package/dist/record/frame-lighting.d.ts.map +1 -1
  114. package/dist/record/frame-snapshot.d.ts +50 -10
  115. package/dist/record/frame-snapshot.d.ts.map +1 -1
  116. package/dist/record/frame.d.ts +7 -3
  117. package/dist/record/frame.d.ts.map +1 -1
  118. package/dist/record/gpu-timing.d.ts +19 -7
  119. package/dist/record/gpu-timing.d.ts.map +1 -1
  120. package/dist/record/helpers.d.ts +0 -20
  121. package/dist/record/helpers.d.ts.map +1 -1
  122. package/dist/record/main-pass-geometry.d.ts +6 -1
  123. package/dist/record/main-pass-geometry.d.ts.map +1 -1
  124. package/dist/record/main-pass-material.d.ts +3 -1
  125. package/dist/record/main-pass-material.d.ts.map +1 -1
  126. package/dist/record/main-pass-sprite-draws.d.ts.map +1 -1
  127. package/dist/record/mesh-ssbo.d.ts.map +1 -1
  128. package/dist/record/render-context.d.ts +57 -6
  129. package/dist/record/render-context.d.ts.map +1 -1
  130. package/dist/record/shadow-pass.d.ts.map +1 -1
  131. package/dist/record/typed-frame-graph.d.ts +49 -2
  132. package/dist/record/typed-frame-graph.d.ts.map +1 -1
  133. package/dist/record/view-ubo.d.ts +1 -2
  134. package/dist/record/view-ubo.d.ts.map +1 -1
  135. package/dist/reflection/inspection.d.ts +10 -0
  136. package/dist/reflection/inspection.d.ts.map +1 -0
  137. package/dist/reflection/projection.d.ts +49 -0
  138. package/dist/reflection/projection.d.ts.map +1 -1
  139. package/dist/reflection/record-owner.d.ts +60 -0
  140. package/dist/reflection/record-owner.d.ts.map +1 -0
  141. package/dist/render-contract.d.ts +14 -8
  142. package/dist/render-contract.d.ts.map +1 -1
  143. package/dist/render-pipeline.d.ts +7 -0
  144. package/dist/render-pipeline.d.ts.map +1 -1
  145. package/dist/render-system-extract.d.ts +104 -16
  146. package/dist/render-system-extract.d.ts.map +1 -1
  147. package/dist/render-system.d.ts +12 -1
  148. package/dist/render-system.d.ts.map +1 -1
  149. package/dist/scene/probe-blend-record.d.ts +22 -0
  150. package/dist/scene/probe-blend-record.d.ts.map +1 -0
  151. package/dist/scene/probe-blend.d.ts +142 -0
  152. package/dist/scene/probe-blend.d.ts.map +1 -0
  153. package/dist/scene/render-scene-types.d.ts +0 -6
  154. package/dist/scene/render-scene-types.d.ts.map +1 -1
  155. package/dist/scene/render-scene.d.ts +103 -9
  156. package/dist/scene/render-scene.d.ts.map +1 -1
  157. package/dist/scene/visibility/bounds.d.ts +20 -0
  158. package/dist/scene/visibility/bounds.d.ts.map +1 -0
  159. package/dist/scene/visibility/budget.d.ts +16 -0
  160. package/dist/scene/visibility/budget.d.ts.map +1 -0
  161. package/dist/scene/visibility/facet.d.ts +73 -0
  162. package/dist/scene/visibility/facet.d.ts.map +1 -0
  163. package/dist/scene/visibility/gpu-frame-timing.d.ts +41 -0
  164. package/dist/scene/visibility/gpu-frame-timing.d.ts.map +1 -0
  165. package/dist/scene/visibility/gpu-lod.d.ts +46 -0
  166. package/dist/scene/visibility/gpu-lod.d.ts.map +1 -0
  167. package/dist/scene/visibility/inspection.d.ts +132 -0
  168. package/dist/scene/visibility/inspection.d.ts.map +1 -0
  169. package/dist/scene/visibility/lod-selector.d.ts +25 -0
  170. package/dist/scene/visibility/lod-selector.d.ts.map +1 -0
  171. package/dist/scene/visibility/occlusion-confidence.d.ts +81 -0
  172. package/dist/scene/visibility/occlusion-confidence.d.ts.map +1 -0
  173. package/dist/scene/visibility/occlusion-pass.d.ts +57 -0
  174. package/dist/scene/visibility/occlusion-pass.d.ts.map +1 -0
  175. package/dist/scene/visibility/occlusion-query-pool.d.ts +57 -0
  176. package/dist/scene/visibility/occlusion-query-pool.d.ts.map +1 -0
  177. package/dist/scene/visibility/occlusion-runtime.d.ts +96 -0
  178. package/dist/scene/visibility/occlusion-runtime.d.ts.map +1 -0
  179. package/dist/scene/visibility/types.d.ts +34 -0
  180. package/dist/scene/visibility/types.d.ts.map +1 -0
  181. package/dist/ssr/admission.d.ts +122 -0
  182. package/dist/ssr/admission.d.ts.map +1 -0
  183. package/dist/ssr/composition.d.ts +32 -0
  184. package/dist/ssr/composition.d.ts.map +1 -0
  185. package/dist/ssr/errors.d.ts +39 -0
  186. package/dist/ssr/errors.d.ts.map +1 -0
  187. package/dist/ssr/identity.d.ts +13 -0
  188. package/dist/ssr/identity.d.ts.map +1 -0
  189. package/dist/systems/skin-palette-allocator.d.ts +1 -1
  190. package/dist/temporal/frame-coordinator.d.ts +13 -0
  191. package/dist/temporal/frame-coordinator.d.ts.map +1 -1
  192. package/dist/temporal/frame.d.ts +2 -0
  193. package/dist/temporal/frame.d.ts.map +1 -1
  194. package/dist/temporal/index.mjs +6 -5
  195. package/dist/temporal/view.d.ts +7 -0
  196. package/dist/temporal/view.d.ts.map +1 -1
  197. package/dist/tilemap-chunk-extract-system.d.ts +1 -1
  198. package/dist/typed-render-graph-primitives.d.ts +4 -0
  199. package/dist/typed-render-graph-primitives.d.ts.map +1 -1
  200. package/dist/volume/passes.d.ts +8 -4
  201. package/dist/volume/passes.d.ts.map +1 -1
  202. package/package.json +20 -20
  203. package/src/__tests__/cluster-grid-default-surface.unit.test.ts +5 -0
  204. package/src/__tests__/detached-inspection.integration.test.ts +6 -0
  205. package/src/__tests__/device-feature-admission.unit.test.ts +13 -1
  206. package/src/__tests__/direct-light-snapshot.unit.test.ts +59 -3
  207. package/src/__tests__/environment-generation.integration.test.ts +16 -0
  208. package/src/__tests__/evidence-identity.ts +13 -0
  209. package/src/__tests__/evidence-identity.unit.test.ts +24 -0
  210. package/src/__tests__/extended-lighting-recovery.browser.test.ts +14 -0
  211. package/src/__tests__/extended-lighting-recovery.dawn.test.ts +14 -0
  212. package/src/__tests__/extended-lighting-recovery.integration.test.ts +81 -0
  213. package/src/__tests__/extended-lighting-resources.unit.test.ts +51 -0
  214. package/src/__tests__/extended-lighting-zero-feature.integration.test.ts +52 -0
  215. package/src/__tests__/factory-contract.integration.test.ts +33 -0
  216. package/src/__tests__/frame-observation.contract.test.ts +15 -0
  217. package/src/__tests__/gpu-driven-batch-topology-pbr.unit.test.ts +146 -0
  218. package/src/__tests__/gpu-driven-indirect-raster-evidence.ts +1 -0
  219. package/src/__tests__/gpu-driven-indirect-raster.dawn.test.ts +1 -0
  220. package/src/__tests__/gpu-driven-production.integration.test.ts +572 -9
  221. package/src/__tests__/gpu-driven-scaling.unit.test.ts +66 -2
  222. package/src/__tests__/gpu-driven-view-gpu-evidence.ts +26 -1
  223. package/src/__tests__/gpu-driven-view-graph.integration.test.ts +89 -2
  224. package/src/__tests__/gpu-driven-view.browser.test.ts +3 -3
  225. package/src/__tests__/gpu-driven-view.dawn.test.ts +3 -3
  226. package/src/__tests__/gpu-driven-view.unit.test.ts +50 -0
  227. package/src/__tests__/gpu-lod-evidence.ts +188 -0
  228. package/src/__tests__/gpu-lod-fallback.integration.test.ts +10 -0
  229. package/src/__tests__/gpu-lod-indirect.integration.test.ts +40 -0
  230. package/src/__tests__/gpu-lod-parity.dawn.test.ts +29 -0
  231. package/src/__tests__/gpu-lod-readiness.integration.test.ts +52 -0
  232. package/src/__tests__/gpu-lod-schema.unit.test.ts +66 -0
  233. package/src/__tests__/gpu-lod-selector.unit.test.ts +28 -0
  234. package/src/__tests__/gpu-lod-silhouette.browser.test.ts +13 -0
  235. package/src/__tests__/gpu-resource-store-stride.unit.test.ts +66 -1
  236. package/src/__tests__/gpu-scene.dawn.test.ts +8 -1
  237. package/src/__tests__/gpu-scene.unit.test.ts +49 -3
  238. package/src/__tests__/light-buffer-layout.unit.test.ts +113 -3
  239. package/src/__tests__/light-inspection.unit.test.ts +55 -0
  240. package/src/__tests__/light-resource-error.unit.test.ts +43 -0
  241. package/src/__tests__/lighting-scene-roundtrip.integration.test.ts +109 -0
  242. package/src/__tests__/lod-bounds.unit.test.ts +42 -0
  243. package/src/__tests__/lod-cpu-lane.integration.test.ts +55 -0
  244. package/src/__tests__/lod-cpu-no-change.perf.test.ts +19 -0
  245. package/src/__tests__/lod-gpu-frame-timing.unit.test.ts +49 -0
  246. package/src/__tests__/lod-multi-view.integration.test.ts +63 -0
  247. package/src/__tests__/lod-occlusion-device-loss.integration.test.ts +27 -0
  248. package/src/__tests__/lod-occlusion-final-decision.integration.test.ts +47 -0
  249. package/src/__tests__/lod-occlusion-inspection.integration.test.ts +217 -0
  250. package/src/__tests__/lod-occlusion-inspection.schema.test-d.ts +14 -0
  251. package/src/__tests__/lod-occlusion-inspection.unit.test.ts +72 -0
  252. package/src/__tests__/lod-occlusion-visual-evidence.ts +91 -0
  253. package/src/__tests__/lod-occlusion.browser.test.ts +15 -0
  254. package/src/__tests__/lod-occlusion.dawn.test.ts +20 -0
  255. package/src/__tests__/lod-selector.profile.test.ts +35 -0
  256. package/src/__tests__/lod-selector.unit.test.ts +68 -0
  257. package/src/__tests__/lod-visibility-identity.unit.test.ts +198 -0
  258. package/src/__tests__/lod-visibility-lifecycle.integration.test.ts +132 -0
  259. package/src/__tests__/ltc-resources.unit.test.ts +32 -0
  260. package/src/__tests__/material-contract-inventory.unit.test.ts +17 -0
  261. package/src/__tests__/occlusion-confidence.unit.test.ts +168 -0
  262. package/src/__tests__/occlusion-invalidation.integration.test.ts +37 -0
  263. package/src/__tests__/occlusion-pass-routing.unit.test.ts +16 -0
  264. package/src/__tests__/occlusion-pass.dawn.test.ts +20 -0
  265. package/src/__tests__/occlusion-pass.integration.test.ts +43 -0
  266. package/src/__tests__/occlusion-pass.rhi-null.test.ts +22 -0
  267. package/src/__tests__/occlusion-query-pool.rhi-null.test.ts +21 -0
  268. package/src/__tests__/occlusion-query-pool.unit.test.ts +95 -0
  269. package/src/__tests__/occlusion-query-ticket.integration.test.ts +47 -0
  270. package/src/__tests__/occlusion-query.dawn.test.ts +16 -0
  271. package/src/__tests__/occlusion-query.evidence.ts +178 -0
  272. package/src/__tests__/occlusion-query.rhi-null.test.ts +31 -0
  273. package/src/__tests__/occlusion-runtime.unit.test.ts +120 -0
  274. package/src/__tests__/prepared-gpu-driven-pbr.integration.test.ts +196 -0
  275. package/src/__tests__/probe-bindings.unit.test.ts +200 -0
  276. package/src/__tests__/probe-blend-numeric.unit.test.ts +67 -0
  277. package/src/__tests__/probe-blend-oracle.unit.test.ts +136 -0
  278. package/src/__tests__/probe-capacity.integration.test.ts +97 -0
  279. package/src/__tests__/probe-recovery.integration.test.ts +104 -0
  280. package/src/__tests__/probe-scene-dirty.integration.test.ts +211 -0
  281. package/src/__tests__/profiler-phase-catalog.test.ts +4 -1
  282. package/src/__tests__/profiler-phase-token.test.ts +1 -0
  283. package/src/__tests__/rect-area-boundary.unit.test.ts +24 -0
  284. package/src/__tests__/reflection-fallback-graph.unit.test.ts +67 -0
  285. package/src/__tests__/reflection-fallback-inspection.unit.test.ts +77 -0
  286. package/src/__tests__/reflection-fallback-lifecycle.integration.test.ts +21 -0
  287. package/src/__tests__/reflection-fallback-projection.unit.test.ts +90 -0
  288. package/src/__tests__/reflection-fallback-source.unit.test.ts +32 -0
  289. package/src/__tests__/reflection-probe-owner-placement.unit.test.ts +39 -0
  290. package/src/__tests__/reflection-probe-record-owner.characterization.unit.test.ts +120 -0
  291. package/src/__tests__/render-error-code-owner.test-d.ts +1 -0
  292. package/src/__tests__/render-feature-docs.unit.test.ts +12 -7
  293. package/src/__tests__/render-graph-fallback.integration.test.ts +24 -0
  294. package/src/__tests__/render-perf/extended-lighting.bench.test.ts +66 -0
  295. package/src/__tests__/render-scene-projection.unit.test.ts +447 -18
  296. package/src/__tests__/renderer-factory-material-contract.unit.test.ts +76 -0
  297. package/src/__tests__/skin-motion-regression.unit.test.ts +22 -0
  298. package/src/__tests__/skinned-shadow-caster.test.ts +2 -2
  299. package/src/__tests__/spot-modifier-projection.unit.test.ts +70 -0
  300. package/src/__tests__/ssr-admission-matrix.integration.test.ts +206 -0
  301. package/src/__tests__/ssr-composition.unit.test.ts +46 -0
  302. package/src/__tests__/ssr-fallback-zero-work.bench.test.ts +94 -0
  303. package/src/__tests__/ssr-recovery-errors.unit.test.ts +58 -0
  304. package/src/__tests__/standard-cluster-variant-resolution.unit.test.ts +67 -0
  305. package/src/__tests__/standard-clustered-pipeline.unit.test.ts +7 -0
  306. package/src/__tests__/standard-lighting-inspection.integration.test.ts +1 -1
  307. package/src/__tests__/standard-lighting-write.unit.test.ts +66 -2
  308. package/src/__tests__/temporal-fallback-generation.integration.test.ts +16 -0
  309. package/src/__tests__/temporal-view.unit.test.ts +3 -3
  310. package/src/__tests__/transmission-prewarm.unit.test.ts +69 -0
  311. package/src/__tests__/visibility-budget.integration.test.ts +140 -0
  312. package/src/__tests__/visibility-budget.unit.test.ts +70 -0
  313. package/src/__tests__/visibility-extract.integration.test.ts +11 -6
  314. package/src/__tests__/volumetric-fog-point-spot-accumulation.integration.test.ts +6 -3
  315. package/src/__tests__/volumetric-fog-stage-readback.dawn.test.ts +31 -28
  316. package/src/assembly/backend-contract.ts +13 -0
  317. package/src/assembly/device-feature-admission.ts +16 -9
  318. package/src/assembly/factory.ts +547 -93
  319. package/src/assembly/host-contract.ts +10 -0
  320. package/src/cluster-binner.ts +31 -0
  321. package/src/components/__tests__/lighting-authoring.unit.test.ts +39 -0
  322. package/src/components/__tests__/rect-area-light.unit.test.ts +33 -0
  323. package/src/components/index.ts +3 -0
  324. package/src/components/light-helpers.ts +52 -1
  325. package/src/components/light-probe.ts +13 -0
  326. package/src/components/rect-area-light.ts +15 -0
  327. package/src/components/scene-instance.ts +6 -0
  328. package/src/components/spot-light.ts +3 -0
  329. package/src/device/__tests__/extended-lighting-recovery.unit.test.ts +24 -0
  330. package/src/device/gpu-residency.ts +140 -9
  331. package/src/device/lifecycle-transaction.ts +12 -0
  332. package/src/environment/lifecycle.ts +8 -1
  333. package/src/errors/gpu-driven.ts +92 -0
  334. package/src/errors/index.ts +1 -0
  335. package/src/errors/recover.ts +32 -0
  336. package/src/errors/render.ts +55 -1
  337. package/src/extract/camera.ts +3 -3
  338. package/src/extract/gpu-driven.ts +108 -0
  339. package/src/extract/visibility.ts +0 -23
  340. package/src/gpu-driven/batch-topology.ts +206 -28
  341. package/src/gpu-driven/prepared-draw.ts +208 -0
  342. package/src/gpu-driven/production-raster.ts +953 -41
  343. package/src/gpu-driven/view-gpu.ts +411 -29
  344. package/src/gpu-scene-schema.ts +13 -0
  345. package/src/gpu-scene.ts +134 -65
  346. package/src/gpu-usage.ts +0 -1
  347. package/src/hdrp-buffers.ts +6 -6
  348. package/src/index.ts +74 -0
  349. package/src/inspection-types.ts +220 -1
  350. package/src/internal.ts +38 -0
  351. package/src/light-buffer-layout.ts +154 -324
  352. package/src/materials.ts +16 -2
  353. package/src/pbr-pipeline.ts +151 -45
  354. package/src/pipeline/standard-forward-lane.ts +47 -0
  355. package/src/pipeline/standard-lighting/graph.ts +2 -1
  356. package/src/pipeline/standard-lighting/light-frame.ts +3 -2
  357. package/src/pipeline/standard-lighting/topology.ts +1 -1
  358. package/src/pipeline/standard-lighting/transport.ts +2 -1
  359. package/src/pipeline/standard-pipeline.ts +2 -0
  360. package/src/pipeline-builder.ts +5 -2
  361. package/src/pipeline-spec.ts +12 -1
  362. package/src/plugin.ts +4 -0
  363. package/src/prepare/__tests__/extended-lighting-capability.unit.test.ts +56 -0
  364. package/src/prepare/extended-lighting/ltc-resources.ts +136 -0
  365. package/src/prepare/extended-lighting/resources.ts +389 -0
  366. package/src/prepare/extended-lighting/spot-modifiers.ts +194 -0
  367. package/src/prepare/extended-lighting/state.ts +92 -0
  368. package/src/record/__tests__/gpu-timing.unit.test.ts +177 -0
  369. package/src/record/__tests__/temporal-payload.unit.test.ts +23 -1
  370. package/src/record/__tests__/typed-frame-graph-plan.unit.test.ts +20 -1
  371. package/src/record/frame-lighting.ts +252 -53
  372. package/src/record/frame-snapshot.ts +57 -12
  373. package/src/record/frame.ts +410 -93
  374. package/src/record/gpu-timing.ts +108 -44
  375. package/src/record/helpers.ts +0 -58
  376. package/src/record/main-pass-geometry.ts +204 -39
  377. package/src/record/main-pass-material.ts +8 -1
  378. package/src/record/main-pass-sprite-draws.ts +52 -85
  379. package/src/record/mesh-ssbo.ts +47 -36
  380. package/src/record/render-context.ts +65 -4
  381. package/src/record/shadow-pass.ts +66 -40
  382. package/src/record/typed-frame-graph.ts +225 -83
  383. package/src/record/view-ubo.ts +14 -24
  384. package/src/reflection/inspection.ts +67 -0
  385. package/src/reflection/projection.ts +196 -1
  386. package/src/reflection/record-owner.ts +1283 -0
  387. package/src/render-contract.ts +17 -5
  388. package/src/render-pipeline.ts +5 -0
  389. package/src/render-system-extract.ts +493 -134
  390. package/src/render-system.ts +811 -615
  391. package/src/scene/__tests__/changed-block-summary.candidate.test.ts +36 -0
  392. package/src/scene/probe-blend-record.ts +54 -0
  393. package/src/scene/probe-blend.ts +813 -0
  394. package/src/scene/render-scene-types.ts +0 -7
  395. package/src/scene/render-scene.ts +848 -183
  396. package/src/scene/visibility/bounds.ts +57 -0
  397. package/src/scene/visibility/budget.ts +40 -0
  398. package/src/scene/visibility/facet.ts +400 -0
  399. package/src/scene/visibility/gpu-frame-timing.ts +101 -0
  400. package/src/scene/visibility/gpu-lod.ts +119 -0
  401. package/src/scene/visibility/inspection.ts +313 -0
  402. package/src/scene/visibility/lod-selector.ts +84 -0
  403. package/src/scene/visibility/occlusion-confidence.ts +478 -0
  404. package/src/scene/visibility/occlusion-pass.ts +165 -0
  405. package/src/scene/visibility/occlusion-query-pool.ts +178 -0
  406. package/src/scene/visibility/occlusion-runtime.ts +672 -0
  407. package/src/scene/visibility/types.ts +50 -0
  408. package/src/ssr/admission.ts +451 -0
  409. package/src/ssr/composition.ts +73 -0
  410. package/src/ssr/errors.ts +76 -0
  411. package/src/ssr/identity.ts +12 -0
  412. package/src/systems/skin-palette-allocator.ts +1 -1
  413. package/src/temporal/frame-coordinator.ts +26 -0
  414. package/src/temporal/frame.ts +14 -1
  415. package/src/temporal/view.ts +11 -0
  416. package/src/tilemap-chunk-extract-system.ts +4 -4
  417. package/src/typed-render-graph-primitives.ts +48 -0
  418. package/src/volume/passes.ts +46 -49
  419. package/dist/.tsbuildinfo +0 -1
  420. package/dist/chunk-5YADUCA7.mjs.map +0 -1
  421. package/dist/chunk-6OPXDQ2E.mjs.map +0 -1
  422. package/dist/chunk-BXBQQKFQ.mjs +0 -67
  423. package/dist/chunk-BXBQQKFQ.mjs.map +0 -1
  424. package/dist/chunk-FS2KNUQH.mjs.map +0 -1
  425. package/dist/chunk-PCHBPYML.mjs.map +0 -1
  426. package/dist/chunk-VFPLTKCU.mjs.map +0 -1
@@ -1,14 +1,15 @@
1
1
  import { TRANSPARENT_SORT_MODE_LAYER_Z, TRANSPARENT_SORT_MODE_LAYER_Y } from './chunk-RXZ3RGOU.mjs';
2
- import { DEFAULT_CLUSTER_GRID, GPU_TEXTURE_USAGE_RENDER_ATTACHMENT, GPU_TEXTURE_USAGE_COPY_SRC, EquirectProjectionFailedError, SHADOW_ATLAS_DEFAULT_LAYERS, SHADOW_ATLAS_DEFAULT_FACE_SIZE, ShadowAtlas, PointShadowAtlasUninitializedError, PointShadowAtlasBoundsViolationError, DEFAULT_STANDARD_PROFILE, StandardClusterTransportUnavailableError, createIblKernelCache, GPU_TEXTURE_USAGE_RENDER_ATTACHMENT_AND_TEXTURE_BINDING, GPU_TEXTURE_USAGE_COPY_DST, GPU_TEXTURE_USAGE_TEXTURE_BINDING, STANDARD_OUTPUT_TRANSFORM_FEATURE_ID, MAX_LIGHTS, CLUSTER_GRID_STRIDE_U32, LIGHT_INDEX_LIST_CAPACITY, StandardLightBudgetExceededError, createStandardClusterLayout, RenderTargetDescriptorInvalidError, RendererOperationError, StandardClusterIndexOverflowError, FXAA_POST_PROCESS_ID, VideoUploadUnsupportedError, VertexColorVariantConflictError } from './chunk-6OPXDQ2E.mjs';
3
- import { SPRITE_PREMULTIPLIED_ALPHA_BLEND } from './chunk-VFPLTKCU.mjs';
4
- import { worldEntityKey } from './chunk-BXBQQKFQ.mjs';
5
- import { ok, derive, err as err$1, toShared, ASSET_ERROR_HINTS, deriveTextureLayout, KNOWN_PASS_KINDS, resolveMaterialTextureCoordinates, handleSlot } from '@forgeax/engine-types';
2
+ import { DEFAULT_CLUSTER_GRID, DEFAULT_STANDARD_PROFILE, createIblKernelCache, MAX_LIGHTS, CLUSTER_GRID_STRIDE_U32, LIGHT_INDEX_LIST_CAPACITY, createStandardClusterLayout } from './chunk-YALPS44A.mjs';
3
+ import { SPRITE_PREMULTIPLIED_ALPHA_BLEND } from './chunk-4NPUASZR.mjs';
4
+ import { GPU_SHADER_STAGE_COMPUTE, GPU_BUFFER_USAGE_STORAGE, GPU_BUFFER_USAGE_COPY_DST, GPU_BUFFER_USAGE_UNIFORM, createHdrpBindGroupLayoutDescriptor, IES_SLICE_WIDTH, IES_SLICE_HEIGHT, COOKIE_SLICE_SIZE, GPU_SHADER_STAGE_VERTEX, GPU_SHADER_STAGE_FRAGMENT, GPU_BUFFER_USAGE_INDEX, GPU_BUFFER_USAGE_VERTEX, pbrSkinMeshDynamicOffsets, worldEntityKey, buildPbrMaterialUserRegionEntries, buildBindGroupLayoutDescriptor, isStandardPbrMaterialShader, SHADOW_CASTER_SHADER_ID, shadowCasterVariantSet, COOKIE_MATRIX_BYTES, matchPass, createPbrSkinMeshBindGroupEntries, SPRITE_PASS_PER_INSTANCE_REGION_VARIANT_SET, SKIN_MATERIAL_SHADER_ID, PROBE_BLEND_RECORD_BYTE_SIZE, resolveRenderTargetMaterialSource, probeBlendRecordOffset, PROBE_BLEND_RECORD_STRIDE } from './chunk-HZUPSYW7.mjs';
5
+ import { GPU_TEXTURE_USAGE_RENDER_ATTACHMENT, GPU_TEXTURE_USAGE_COPY_SRC, EquirectProjectionFailedError, SHADOW_ATLAS_DEFAULT_LAYERS, SHADOW_ATLAS_DEFAULT_FACE_SIZE, ShadowAtlas, PointShadowAtlasUninitializedError, PointShadowAtlasBoundsViolationError, StandardClusterTransportUnavailableError, GPU_TEXTURE_USAGE_RENDER_ATTACHMENT_AND_TEXTURE_BINDING, GPU_TEXTURE_USAGE_COPY_DST, GPU_TEXTURE_USAGE_TEXTURE_BINDING, STANDARD_OUTPUT_TRANSFORM_FEATURE_ID, StandardLightBudgetExceededError, RendererOperationError, StandardClusterIndexOverflowError, FXAA_POST_PROCESS_ID, VideoUploadUnsupportedError, VertexColorVariantConflictError } from './chunk-QODA5UKU.mjs';
6
+ import { ok, err as err$1, toShared, ASSET_ERROR_HINTS, deriveTextureLayout, KNOWN_PASS_KINDS, derive, resolveMaterialTextureCoordinates, handleSlot } from '@forgeax/engine-types';
6
7
  import { ok as ok$1, err, RhiError } from '@forgeax/engine-rhi';
7
8
  import { mat3, vec3, mat4 } from '@forgeax/engine-math';
8
- import { DEFAULT_STANDARD_PBR_PARAM_SCHEMA, DEFAULT_MSDF_TEXT_PARAM_SCHEMA, DEFAULT_SPRITE_PARAM_SCHEMA, DEFAULT_UNLIT_PARAM_SCHEMA } from '@forgeax/engine-shader';
9
9
  import { deriveVertexLayoutProjection, deriveVertexBufferLayout } from '@forgeax/engine-geometry';
10
10
  import { resolveAssetHandle } from '@forgeax/engine-assets-runtime';
11
11
  import { probeVideoHighPerfUpload, VIDEO_ELEMENT_PROVIDER_KEY } from '@forgeax/engine-graphics-extras';
12
+ import { DEFAULT_STANDARD_PBR_PARAM_SCHEMA, DEFAULT_MSDF_TEXT_PARAM_SCHEMA, DEFAULT_SPRITE_PARAM_SCHEMA, DEFAULT_UNLIT_PARAM_SCHEMA } from '@forgeax/engine-shader';
12
13
  import { isCompressedFormat, bytesPerRow, blockParamsForFormat } from '@forgeax/engine-codec';
13
14
 
14
15
  function resolveOutputDither(config) {
@@ -83,66 +84,62 @@ function importRenderPipelineSurface(graph, topology) {
83
84
  }
84
85
  });
85
86
  }
86
-
87
- // src/gpu-stage.ts
88
- var GPU_SHADER_STAGE_VERTEX = 1;
89
- var GPU_SHADER_STAGE_FRAGMENT = 2;
90
- var GPU_SHADER_STAGE_COMPUTE = 4;
91
-
92
- // src/gpu-usage.ts
93
- var GPU_BUFFER_USAGE_VERTEX = 32;
94
- var GPU_BUFFER_USAGE_INDEX = 16;
95
- var GPU_BUFFER_USAGE_COPY_DST = 8;
96
- var GPU_BUFFER_USAGE_COPY_SRC = 4;
97
- var GPU_BUFFER_USAGE_UNIFORM = 64;
98
- var GPU_BUFFER_USAGE_STORAGE = 128;
99
- var GPU_BUFFER_USAGE_INDIRECT = 256;
100
- var GPU_BUFFER_USAGE_MAP_READ = 1;
101
- var GPU_BUFFER_USAGE_QUERY_RESOLVE = 512;
102
- var BYTES_PER_LIGHT_SLOT = 64;
103
- var LightSlotKind = {
87
+ var STORAGE_BUFFER_MIN_REQUIRED = 4;
88
+ var BYTES_PER_DIRECT_LIGHT_SLOT = 80;
89
+ var DirectLightSlotKind = {
104
90
  POINT: 0,
105
- SPOT: 1
91
+ SPOT: 1,
92
+ RECT_AREA: 2
106
93
  };
107
- var STORAGE_BUFFER_MIN_REQUIRED = 4;
108
- var POINT_LIGHT_STD430_BYTES = 32;
109
- var SPOT_LIGHT_STD430_BYTES = 80;
110
- var SPOT_LIGHT_SHADOW_TILE_SENTINEL = -1;
111
- var SPOT_LIGHT_PROJECTOR_FLAG = 1073741824;
112
- var SPOT_LIGHT_TILE_MASK = SPOT_LIGHT_PROJECTOR_FLAG - 1;
113
- var LIGHT_ARRAY_HEADER_BYTES = 16;
114
- var LIGHT_ARRAY_MAX_SLOTS = 4;
115
- var POINT_LIGHT_SHADOW_LAYER_SENTINEL = -1;
116
- function packLightSlot(snap, shadow, projectorSelected) {
117
- const out = new Float32Array(16);
118
- out[0] = snap.position[0] ?? 0;
119
- out[1] = snap.position[1] ?? 0;
120
- out[2] = snap.position[2] ?? 0;
121
- out[3] = snap.invRangeSquared;
122
- out[4] = snap.color[0] ?? 0;
123
- out[5] = snap.color[1] ?? 0;
124
- out[6] = snap.color[2] ?? 0;
125
- out[7] = snap.kind === "point" ? 1 : snap.cosInner;
126
- out[8] = snap.kind === "point" ? 0 : snap.direction[0] ?? 0;
127
- out[9] = snap.kind === "point" ? 0 : snap.direction[1] ?? 0;
128
- out[10] = snap.kind === "point" ? 0 : snap.direction[2] ?? 0;
129
- out[11] = snap.kind === "point" ? 0 : snap.cosOuter;
130
- const u32 = new Uint32Array(out.buffer);
131
- u32[12] = snap.kind === "point" ? LightSlotKind.POINT : LightSlotKind.SPOT;
132
- const i32 = new Int32Array(out.buffer);
133
- if (snap.kind === "point" && shadow !== void 0) {
134
- i32[13] = shadow.shadowAtlasLayer;
135
- out[14] = shadow.near;
136
- out[15] = shadow.far;
137
- } else if (snap.kind === "spot") {
138
- const hasProjector = projectorSelected ?? (snap.projectorAsset !== void 0 && snap.lightViewProj !== void 0);
139
- const tile = snap.shadowAtlasTile >= 0 ? snap.shadowAtlasTile : 0;
140
- i32[13] = hasProjector ? SPOT_LIGHT_PROJECTOR_FLAG | tile & SPOT_LIGHT_TILE_MASK : snap.shadowAtlasTile >= 0 ? snap.shadowAtlasTile : SPOT_LIGHT_SHADOW_TILE_SENTINEL;
141
- out[14] = snap.shadowIntensity ?? 1;
142
- out[15] = snap.pcfKernelSize ?? 3;
94
+ var DIRECT_LIGHT_SLOT_METADATA_SENTINEL = 4294967295;
95
+ var DIRECT_LIGHT_SLOT_PROJECTOR_FLAG = 1073741824;
96
+ var DIRECT_LIGHT_SLOT_TILE_MASK = DIRECT_LIGHT_SLOT_PROJECTOR_FLAG - 1;
97
+ var DIRECT_LIGHT_SLOT_FLOAT_COUNT = BYTES_PER_DIRECT_LIGHT_SLOT / Float32Array.BYTES_PER_ELEMENT;
98
+ function directLightMetadata(value) {
99
+ return value === void 0 ? DIRECT_LIGHT_SLOT_METADATA_SENTINEL : value >>> 0;
100
+ }
101
+ function packDirectLightSlot(snapshot, projectorSelected) {
102
+ const out = new Float32Array(DIRECT_LIGHT_SLOT_FLOAT_COUNT);
103
+ out[0] = snapshot.position[0] ?? 0;
104
+ out[1] = snapshot.position[1] ?? 0;
105
+ out[2] = snapshot.position[2] ?? 0;
106
+ out[3] = snapshot.invRangeSquared;
107
+ out[4] = snapshot.color[0] ?? 0;
108
+ out[5] = snapshot.color[1] ?? 0;
109
+ out[6] = snapshot.color[2] ?? 0;
110
+ if (snapshot.kind === "point") {
111
+ out[7] = 1;
112
+ } else if (snapshot.kind === "spot") {
113
+ out[7] = snapshot.cosInner;
114
+ out[8] = snapshot.direction[0] ?? 0;
115
+ out[9] = snapshot.direction[1] ?? 0;
116
+ out[10] = snapshot.direction[2] ?? 0;
117
+ out[11] = snapshot.cosOuter;
118
+ out[12] = snapshot.depthBias ?? 5e-3;
119
+ out[13] = snapshot.normalBias ?? 0.05;
120
+ out[14] = snapshot.shadowIntensity ?? 1;
121
+ out[15] = snapshot.rollDeg ?? 0;
143
122
  } else {
144
- i32[13] = POINT_LIGHT_SHADOW_LAYER_SENTINEL;
145
- }
123
+ out[7] = snapshot.halfWidth;
124
+ out[8] = snapshot.axisY[0] ?? 0;
125
+ out[9] = snapshot.axisY[1] ?? 0;
126
+ out[10] = snapshot.axisY[2] ?? 0;
127
+ out[11] = snapshot.halfHeight;
128
+ out[12] = snapshot.axisX[0] ?? 0;
129
+ out[13] = snapshot.axisX[1] ?? 0;
130
+ out[14] = snapshot.axisX[2] ?? 0;
131
+ }
132
+ const metadata = new Uint32Array(out.buffer);
133
+ metadata[16] = snapshot.kind === "point" ? DirectLightSlotKind.POINT : snapshot.kind === "spot" ? DirectLightSlotKind.SPOT : DirectLightSlotKind.RECT_AREA;
134
+ const spotProjectorSelected = snapshot.kind === "spot" && (projectorSelected ?? (snapshot.projectorAsset !== void 0 && snapshot.lightViewProj !== void 0));
135
+ const spotShadowMetadata = snapshot.kind === "spot" ? spotProjectorSelected ? DIRECT_LIGHT_SLOT_PROJECTOR_FLAG | (snapshot.shadowAtlasTile >= 0 ? snapshot.shadowAtlasTile : 0) & DIRECT_LIGHT_SLOT_TILE_MASK : directLightMetadata(snapshot.shadowAtlasTile) : void 0;
136
+ metadata[17] = directLightMetadata(
137
+ snapshot.kind === "point" ? snapshot.shadowAtlasLayer : snapshot.kind === "spot" ? spotShadowMetadata : void 0
138
+ );
139
+ metadata[18] = directLightMetadata(snapshot.iesProfileSlice);
140
+ metadata[19] = directLightMetadata(
141
+ spotProjectorSelected && snapshot.kind === "spot" ? snapshot.projectorSlice : snapshot.cookieSlice
142
+ );
146
143
  return out;
147
144
  }
148
145
  function assertStorageBufferCap(cap) {
@@ -155,8 +152,8 @@ function assertStorageBufferCap(cap) {
155
152
  return err(
156
153
  new RhiError({
157
154
  code: "limit-exceeded",
158
- expected: `device.limits.maxStorageBuffersPerShaderStage >= ${STORAGE_BUFFER_MIN_REQUIRED}, or exactly 0 for uniform-fallback path`,
159
- hint: `device.limits.maxStorageBuffersPerShaderStage = ${cap} < ${STORAGE_BUFFER_MIN_REQUIRED} and != 0. WebGPU spec default minimum is 8; this may be a downlevel adapter with partial storage support. Wait for todo-125 multi-light-pack which collapses point + spot into a single cluster storage buffer (1 entry instead of 2) for 2-3 buffer environments.`,
155
+ expected: `device.limits.maxStorageBuffersPerShaderStage >= ${STORAGE_BUFFER_MIN_REQUIRED}, or exactly 0 for the mesh-only fallback`,
156
+ hint: `device.limits.maxStorageBuffersPerShaderStage = ${cap} < ${STORAGE_BUFFER_MIN_REQUIRED} and != 0. WebGPU spec default minimum is 8; this adapter cannot run the unified Cluster local-light path.`,
160
157
  detail: {
161
158
  maxStorageBufferBindingSize: cap,
162
159
  requestedBytes: STORAGE_BUFFER_MIN_REQUIRED
@@ -164,621 +161,6 @@ function assertStorageBufferCap(cap) {
164
161
  })
165
162
  );
166
163
  }
167
- var BGL_ONLY_SPEC_STUB = Object.freeze({
168
- shader: { id: "", passKind: "forward", variantSet: void 0 },
169
- attachments: { colorFormats: [], depthFormat: void 0, sampleCount: 1 },
170
- geometry: { topology: "triangle-list", vertexLayout: {} },
171
- renderState: void 0
172
- });
173
- function buildPbrMaterialUserRegionEntries(paramSchema = DEFAULT_STANDARD_PBR_PARAM_SCHEMA) {
174
- const derived = derive(paramSchema);
175
- const entries = derived.bglEntries.map(
176
- (entry) => ({
177
- binding: entry.binding,
178
- visibility: entry.visibility,
179
- ...entry.buffer === void 0 ? {} : { buffer: entry.buffer },
180
- ...entry.sampler === void 0 ? {} : { sampler: entry.sampler },
181
- ...entry.texture === void 0 ? {} : { texture: entry.texture },
182
- ...entry.storageTexture === void 0 ? {} : { storageTexture: entry.storageTexture }
183
- })
184
- );
185
- const ubo = entries[0];
186
- if (ubo !== void 0 && ubo.binding === 0 && ubo.buffer?.type === "uniform") {
187
- entries[0] = {
188
- binding: 0,
189
- visibility: GPU_SHADER_STAGE_VERTEX | GPU_SHADER_STAGE_FRAGMENT,
190
- buffer: { type: "uniform", hasDynamicOffset: true }
191
- };
192
- }
193
- return entries;
194
- }
195
- function appendInjection(bgl, kind) {
196
- const start = bgl.length;
197
- switch (kind) {
198
- case "ibl":
199
- return [
200
- // binding start+0: irradianceMap (texture_cube)
201
- {
202
- binding: start,
203
- visibility: GPU_SHADER_STAGE_FRAGMENT,
204
- texture: { sampleType: "float", viewDimension: "cube" }
205
- },
206
- // binding start+1: irradianceSampler
207
- {
208
- binding: start + 1,
209
- visibility: GPU_SHADER_STAGE_FRAGMENT,
210
- sampler: { type: "filtering" }
211
- },
212
- // binding start+2: prefilterMap (texture_cube)
213
- {
214
- binding: start + 2,
215
- visibility: GPU_SHADER_STAGE_FRAGMENT,
216
- texture: { sampleType: "float", viewDimension: "cube" }
217
- },
218
- // binding start+3: prefilterSampler
219
- {
220
- binding: start + 3,
221
- visibility: GPU_SHADER_STAGE_FRAGMENT,
222
- sampler: { type: "filtering" }
223
- },
224
- // binding start+4: brdfLut (texture_2d)
225
- {
226
- binding: start + 4,
227
- visibility: GPU_SHADER_STAGE_FRAGMENT,
228
- texture: { sampleType: "float", viewDimension: "2d" }
229
- },
230
- // binding start+5: brdfLutSampler
231
- {
232
- binding: start + 5,
233
- visibility: GPU_SHADER_STAGE_FRAGMENT,
234
- sampler: { type: "filtering" }
235
- },
236
- // binding start+6: uniform { intensity: f32 }
237
- {
238
- binding: start + 6,
239
- visibility: GPU_SHADER_STAGE_FRAGMENT,
240
- buffer: { type: "uniform" }
241
- }
242
- ];
243
- case "lightmap":
244
- return [
245
- // emissive sampler + texture pair
246
- {
247
- binding: start,
248
- visibility: GPU_SHADER_STAGE_FRAGMENT,
249
- sampler: { type: "filtering" }
250
- },
251
- {
252
- binding: start + 1,
253
- visibility: GPU_SHADER_STAGE_FRAGMENT,
254
- texture: { sampleType: "float", viewDimension: "2d" }
255
- },
256
- // occlusion sampler + texture pair
257
- {
258
- binding: start + 2,
259
- visibility: GPU_SHADER_STAGE_FRAGMENT,
260
- sampler: { type: "filtering" }
261
- },
262
- {
263
- binding: start + 3,
264
- visibility: GPU_SHADER_STAGE_FRAGMENT,
265
- texture: { sampleType: "float", viewDimension: "2d" }
266
- }
267
- ];
268
- case "shadow":
269
- return [
270
- {
271
- binding: start,
272
- visibility: GPU_SHADER_STAGE_FRAGMENT,
273
- sampler: { type: "comparison" }
274
- },
275
- {
276
- binding: start + 1,
277
- visibility: GPU_SHADER_STAGE_FRAGMENT,
278
- texture: { sampleType: "depth", viewDimension: "2d" }
279
- }
280
- ];
281
- case "transmission":
282
- return [
283
- {
284
- binding: start,
285
- visibility: GPU_SHADER_STAGE_FRAGMENT,
286
- sampler: { type: "filtering" }
287
- },
288
- {
289
- binding: start + 1,
290
- visibility: GPU_SHADER_STAGE_FRAGMENT,
291
- texture: { sampleType: "float", viewDimension: "2d" }
292
- }
293
- ];
294
- }
295
- }
296
- function buildPbrViewBglEntries(caps) {
297
- const lightBufType = caps.storageBuffer ? "read-only-storage" : "uniform";
298
- const entries = [
299
- {
300
- binding: 0,
301
- visibility: GPU_SHADER_STAGE_VERTEX | GPU_SHADER_STAGE_FRAGMENT,
302
- // View captures use the same bind group with a per-face view slot.
303
- // Keeping this dynamic is also valid for the display slot at offset 0.
304
- buffer: { type: "uniform", hasDynamicOffset: true }
305
- },
306
- {
307
- binding: 1,
308
- visibility: GPU_SHADER_STAGE_FRAGMENT,
309
- buffer: { type: lightBufType }
310
- },
311
- {
312
- binding: 2,
313
- visibility: GPU_SHADER_STAGE_FRAGMENT,
314
- buffer: { type: lightBufType }
315
- },
316
- {
317
- binding: 3,
318
- visibility: GPU_SHADER_STAGE_VERTEX | GPU_SHADER_STAGE_FRAGMENT,
319
- texture: { sampleType: "depth", viewDimension: "2d" }
320
- },
321
- {
322
- binding: 4,
323
- visibility: GPU_SHADER_STAGE_FRAGMENT,
324
- sampler: { type: "comparison" }
325
- },
326
- // feat-20260612-point-light-shadows-urp-hdrp Round-2 F-1: point shadow
327
- // cube_array depth atlas. Bound to either the real ShadowAtlas
328
- // cube_array view (when point shadows are active) or a 1x1x6 fallback
329
- // cube_array view cleared to 1.0 (fully lit). Visibility is FRAGMENT
330
- // only -- the directional binding 3 is VERTEX|FRAGMENT for shadow
331
- // probe-debug sampling, but the cube atlas has no host-side probe path.
332
- {
333
- binding: 5,
334
- visibility: GPU_SHADER_STAGE_FRAGMENT,
335
- texture: { sampleType: "depth", viewDimension: "cube-array" }
336
- },
337
- // feat-20260612-point-light-shadows-urp-hdrp Round-2 F-1: point shadow
338
- // params UBO. Carries `array<vec4<f32>, 4>` = 64 B with one lane per
339
- // shadow-casting point light slot (shadowAtlasLayer in [0, 4)). Each
340
- // lane stores `(near, far, 1/(far-near), 0)` so the fragment-shader
341
- // depth-ref reconstruction (lighting-punctual.wgsl evalPointShadowed)
342
- // can avoid sampling LightSlot for the URP path. HDRP rides the same
343
- // constants on `LightSlot.kind_and_pad.zw` so binding 6 is unused on
344
- // HDRP shaders even though the BGL declares it (charter P4 single SSOT
345
- // BGL across pipelines; the HDRP variant simply doesn't reference the
346
- // binding in WGSL, which is allowed).
347
- {
348
- binding: 6,
349
- visibility: GPU_SHADER_STAGE_FRAGMENT,
350
- buffer: { type: "uniform" }
351
- },
352
- // feat-20260613-csm-cascaded-shadow-maps M5 / w28: shadowCasterCascade
353
- // UBO (16 B). Carries the 0-based cascade index of the shadow pass
354
- // currently being rasterized so `shadow_caster.wgsl` can index into
355
- // `view.lightViewProj_X` per cascade. Shifted from binding 5 to
356
- // binding 7 on 2026-06-13 to make room for point-shadow bindings 5/6
357
- // (they predate this feat in main; CSM's slot was the optimal-yield
358
- // give since point-shadow needs FRAGMENT-only and the cascade UBO
359
- // needs vertex-stage too — keeping cascade higher avoids interleaving
360
- // visibility flags within the contiguous shadow-binding cluster).
361
- {
362
- binding: 7,
363
- visibility: GPU_SHADER_STAGE_VERTEX | GPU_SHADER_STAGE_FRAGMENT,
364
- buffer: { type: "uniform" }
365
- },
366
- // feat-20260625-spot-light-shadow-mapping M3 / w14 (D-5): spot shadow
367
- // atlas. A single `texture_depth_2d` holding up to 4 spot shadows in a 2x2
368
- // tile grid (urp-pipeline.ts spotShadowDepth). FRAGMENT-only — the spot
369
- // shadow factor is reconstructed at fragment time via perspective-divide in
370
- // `evalSpotShadowed` (lighting-punctual.wgsl).
371
- //
372
- // ALWAYS-ON (no caps gate, unlike the point cube_array atlas at binding 5
373
- // which rides POINT_SHADOW_AVAILABLE): spot uses `texture_depth_2d` which is
374
- // compat-safe in every WebGPU profile, so the binding is unconditionally
375
- // declared. The matching WGSL declaration is `spotShadowMap` at @group(0)
376
- // binding 8 in common.wgsl (also unconditional) — the two must stay in
377
- // lock-step or WebGPU validation rejects the bind group at smoke time
378
- // (memory: BGL shape mismatch is a browser-path-only bug). No binding 9
379
- // sampler: spot reuses the comparison sampler at binding 4.
380
- // feat-20260625-spot-light-shadow-mapping M3 / w14 (D-5): spot shadow 2D
381
- // atlas, the LAST view-BG binding. The per-spot fragment-read perspective
382
- // lightViewProj matrices that w24 originally declared at a standalone
383
- // binding 9 uniform buffer were folded into the View UBO (binding 0,
384
- // `view.spotLightViewProj`) in w25 (scope-amend webkit-fallback): the
385
- // standalone binding pushed the WebGL2 fallback fragment uniform-buffer
386
- // count to 12, over GLES 3.0's `max_uniform_buffers_per_shader_stage = 11`,
387
- // crashing pipeline-layout creation on the compat path (this feat's target).
388
- {
389
- binding: 8,
390
- visibility: GPU_SHADER_STAGE_FRAGMENT,
391
- texture: { sampleType: "depth", viewDimension: "2d" }
392
- }
393
- ];
394
- if (caps.projectorAvailable !== false) {
395
- entries.push(
396
- {
397
- binding: 11,
398
- visibility: GPU_SHADER_STAGE_FRAGMENT,
399
- texture: { sampleType: "float", viewDimension: "2d" }
400
- },
401
- {
402
- binding: 12,
403
- visibility: GPU_SHADER_STAGE_FRAGMENT,
404
- sampler: { type: "filtering" }
405
- }
406
- );
407
- }
408
- entries.push({
409
- binding: 10,
410
- visibility: GPU_SHADER_STAGE_VERTEX,
411
- buffer: { type: "uniform", hasDynamicOffset: true }
412
- });
413
- return entries;
414
- }
415
- function buildPbrPipelineLayouts(device, caps) {
416
- const viewBglRes = device.createBindGroupLayout(
417
- buildBindGroupLayoutDescriptor(BGL_ONLY_SPEC_STUB, { kind: "pbr-view", caps })
418
- );
419
- if (!viewBglRes.ok) throw viewBglRes.error;
420
- const materialBglRes = device.createBindGroupLayout(
421
- buildBindGroupLayoutDescriptor(BGL_ONLY_SPEC_STUB, { kind: "pbr-material-merged" })
422
- );
423
- if (!materialBglRes.ok) throw materialBglRes.error;
424
- const meshArrayBglRes = device.createBindGroupLayout(
425
- buildBindGroupLayoutDescriptor(BGL_ONLY_SPEC_STUB, { kind: "pbr-mesh-array", caps })
426
- );
427
- if (!meshArrayBglRes.ok) throw meshArrayBglRes.error;
428
- const instancesBglRes = device.createBindGroupLayout(
429
- buildBindGroupLayoutDescriptor(BGL_ONLY_SPEC_STUB, { kind: "pbr-instances", caps })
430
- );
431
- if (!instancesBglRes.ok) throw instancesBglRes.error;
432
- const layouts = [
433
- viewBglRes.value,
434
- materialBglRes.value,
435
- meshArrayBglRes.value,
436
- instancesBglRes.value
437
- ];
438
- const pipelineLayoutRes = device.createPipelineLayout({
439
- label: "pbr-pl",
440
- bindGroupLayouts: layouts
441
- });
442
- if (!pipelineLayoutRes.ok) throw pipelineLayoutRes.error;
443
- return {
444
- pipelineLayout: pipelineLayoutRes.value,
445
- viewBgl: viewBglRes.value,
446
- materialBgl: materialBglRes.value,
447
- meshArrayBgl: meshArrayBglRes.value,
448
- instancesBgl: instancesBglRes.value,
449
- bindGroupLayouts: layouts
450
- };
451
- }
452
- var SKIN_MATERIAL_SHADER_ID = "forgeax::pbr-skin";
453
- var SHADOW_CASTER_SHADER_ID = "forgeax::default-shadow-caster";
454
- function shadowCasterVariantSet(storageBuffer, skinned) {
455
- const skinningDisabled = !skinned;
456
- if (storageBuffer && skinningDisabled) return "";
457
- return `SKINNING_DISABLED=${String(skinningDisabled)}+STORAGE_BUFFER_AVAILABLE=${String(storageBuffer)}`;
458
- }
459
- function resolvePipelineGroup2Contract(source) {
460
- const withoutComments = source.replace(/\/\*[\s\S]*?\*\//gu, "").replace(/\/\/.*$/gmu, "");
461
- const bindings = [
462
- ...withoutComments.matchAll(/@group\s*\(\s*2\s*\)\s*@binding\s*\(\s*(\d+)\s*\)/gu)
463
- ].map((match) => Number(match[1]));
464
- const hasSkinBindings = bindings.includes(1) || bindings.includes(2);
465
- const hasClusterBindings = bindings.some((binding) => binding >= 3);
466
- if (hasSkinBindings && hasClusterBindings) return "skin-cluster";
467
- if (hasSkinBindings) return "skin";
468
- if (hasClusterBindings) return "cluster";
469
- return "mesh";
470
- }
471
- function isStandardPbrMaterialShader(shaderId) {
472
- return shaderId === "forgeax::default-standard-pbr" || shaderId === SKIN_MATERIAL_SHADER_ID || shaderId === "forgeax::default-standard-pbr-skin";
473
- }
474
- function buildPbrSkinLayouts(device, caps, pbr) {
475
- const skinMeshArrayBglRes = device.createBindGroupLayout(
476
- buildBindGroupLayoutDescriptor(BGL_ONLY_SPEC_STUB, {
477
- kind: "pbr-skin-mesh-array",
478
- caps
479
- })
480
- );
481
- if (!skinMeshArrayBglRes.ok) throw skinMeshArrayBglRes.error;
482
- const layouts = [
483
- pbr.viewBgl,
484
- pbr.materialBgl,
485
- skinMeshArrayBglRes.value,
486
- pbr.instancesBgl
487
- ];
488
- const pipelineLayoutRes = device.createPipelineLayout({
489
- label: "pbr-skin-pl",
490
- bindGroupLayouts: layouts
491
- });
492
- if (!pipelineLayoutRes.ok) throw pipelineLayoutRes.error;
493
- return {
494
- pipelineLayout: pipelineLayoutRes.value,
495
- viewBgl: pbr.viewBgl,
496
- materialBgl: pbr.materialBgl,
497
- meshArrayBgl: skinMeshArrayBglRes.value,
498
- instancesBgl: pbr.instancesBgl,
499
- bindGroupLayouts: layouts
500
- };
501
- }
502
- function createPbrSkinMeshBindGroupEntries(meshBuffer, meshSize, paletteBuffer, paletteWindowBytes) {
503
- return [
504
- {
505
- binding: 0,
506
- resource: { kind: "buffer", value: { buffer: meshBuffer, offset: 0, size: meshSize } }
507
- },
508
- ...[1, 2].map((binding) => ({
509
- binding,
510
- resource: {
511
- kind: "buffer",
512
- value: {
513
- buffer: paletteBuffer,
514
- offset: 0,
515
- size: paletteWindowBytes
516
- }
517
- }
518
- }))
519
- ];
520
- }
521
- function pbrSkinMeshDynamicOffsets(meshOffset, paletteOffset) {
522
- return [meshOffset, paletteOffset, paletteOffset];
523
- }
524
- var SPRITE_PASS_PER_INSTANCE_REGION_VARIANT_SET = "";
525
- function createHdrpBindGroupLayoutDescriptor() {
526
- const meshBufType = "read-only-storage";
527
- const clusterBufType = "read-only-storage";
528
- return {
529
- label: "hdrp-unified-bgl-group2",
530
- entries: [
531
- {
532
- binding: 0,
533
- // Standard fragment lighting (transmission/refraction and clustered
534
- // evaluation) reads the same mesh transform window as the vertex
535
- // stage. Keep this visibility in the HDRP descriptor aligned with
536
- // the URP mesh-array descriptor; restricting it to vertex makes the
537
- // HDRP pipeline invalid when fs_main accesses `meshes[0]`.
538
- visibility: GPU_SHADER_STAGE_VERTEX | GPU_SHADER_STAGE_FRAGMENT,
539
- buffer: { type: meshBufType, hasDynamicOffset: true }
540
- },
541
- // Bindings 1 and 2 stay absent for the URP physical isolation gap.
542
- {
543
- binding: 3,
544
- visibility: GPU_SHADER_STAGE_FRAGMENT,
545
- buffer: { type: clusterBufType, hasDynamicOffset: false }
546
- },
547
- {
548
- binding: 4,
549
- visibility: GPU_SHADER_STAGE_FRAGMENT,
550
- buffer: { type: clusterBufType, hasDynamicOffset: false }
551
- },
552
- {
553
- binding: 5,
554
- visibility: GPU_SHADER_STAGE_FRAGMENT,
555
- buffer: { type: clusterBufType, hasDynamicOffset: false }
556
- },
557
- {
558
- binding: 6,
559
- visibility: GPU_SHADER_STAGE_FRAGMENT,
560
- buffer: { type: "uniform", hasDynamicOffset: false }
561
- },
562
- {
563
- binding: 7,
564
- visibility: GPU_SHADER_STAGE_FRAGMENT,
565
- texture: { sampleType: "float", viewDimension: "2d", multisampled: false }
566
- },
567
- {
568
- binding: 8,
569
- visibility: GPU_SHADER_STAGE_FRAGMENT,
570
- sampler: { type: "filtering" }
571
- }
572
- ]
573
- };
574
- }
575
- function createHdrpSkinBindGroupLayoutDescriptor() {
576
- const base = createHdrpBindGroupLayoutDescriptor();
577
- const baseEntries = base.entries;
578
- if (baseEntries === void 0 || baseEntries[0] === void 0) {
579
- throw new Error("HDRP base group(2) layout must declare mesh binding 0");
580
- }
581
- const paletteType = "read-only-storage";
582
- return {
583
- label: "hdrp-skin-unified-bgl-group2",
584
- entries: [
585
- baseEntries[0],
586
- {
587
- binding: 1,
588
- visibility: GPU_SHADER_STAGE_VERTEX,
589
- buffer: { type: paletteType, hasDynamicOffset: true }
590
- },
591
- {
592
- binding: 2,
593
- visibility: GPU_SHADER_STAGE_VERTEX,
594
- buffer: { type: paletteType, hasDynamicOffset: true }
595
- },
596
- ...baseEntries.slice(1)
597
- ]
598
- };
599
- }
600
- function resolveMaterialParamSchema(spec, options) {
601
- if (options.materialParamSchema !== void 0) return options.materialParamSchema;
602
- if (options.registry !== void 0) {
603
- const lookup = options.registry.findMaterialArtifact(spec.shader.id);
604
- if (lookup.ok) return lookup.value.paramSchema;
605
- }
606
- return void 0;
607
- }
608
- function buildBindGroupLayoutDescriptor(spec, options) {
609
- switch (options.kind) {
610
- case "pbr-view": {
611
- const caps = options.caps ?? { storageBuffer: true };
612
- return {
613
- label: "pbr-view-bgl",
614
- entries: buildPbrViewBglEntries(caps)
615
- };
616
- }
617
- case "pbr-mesh-array": {
618
- const caps = options.caps ?? { storageBuffer: true };
619
- const meshBufType = caps.storageBuffer ? "read-only-storage" : "uniform";
620
- return {
621
- label: "pbr-mesh-array-bgl",
622
- entries: [
623
- {
624
- binding: 0,
625
- visibility: GPU_SHADER_STAGE_VERTEX | GPU_SHADER_STAGE_FRAGMENT,
626
- buffer: { type: meshBufType, hasDynamicOffset: true }
627
- }
628
- ]
629
- };
630
- }
631
- case "pbr-instances": {
632
- const caps = options.caps ?? { storageBuffer: true };
633
- const meshBufType = caps.storageBuffer ? "read-only-storage" : "uniform";
634
- return {
635
- label: "pbr-instances-bgl",
636
- entries: [
637
- {
638
- binding: 0,
639
- // Standard transmission reads the same per-instance transform in
640
- // fs_main to convert glTF unit-space thickness into world metres.
641
- // Keep one shared instances BGL and widen its visibility instead
642
- // of introducing a second transform upload or six new varyings.
643
- visibility: GPU_SHADER_STAGE_VERTEX | GPU_SHADER_STAGE_FRAGMENT,
644
- buffer: { type: meshBufType, hasDynamicOffset: false }
645
- }
646
- ]
647
- };
648
- }
649
- case "pbr-skin-mesh-array": {
650
- const caps = options.caps ?? { storageBuffer: true };
651
- const meshBufType = caps.storageBuffer ? "read-only-storage" : "uniform";
652
- return {
653
- label: "pbr-skin-mesh-array-bgl",
654
- entries: [
655
- {
656
- binding: 0,
657
- visibility: GPU_SHADER_STAGE_VERTEX,
658
- buffer: { type: meshBufType, hasDynamicOffset: true }
659
- },
660
- {
661
- binding: 1,
662
- visibility: GPU_SHADER_STAGE_VERTEX,
663
- buffer: { type: meshBufType, hasDynamicOffset: true }
664
- },
665
- {
666
- binding: 2,
667
- visibility: GPU_SHADER_STAGE_VERTEX,
668
- buffer: { type: meshBufType, hasDynamicOffset: true }
669
- }
670
- ]
671
- };
672
- }
673
- case "pbr-material-merged": {
674
- const resolvedSchema = resolveMaterialParamSchema(spec, options);
675
- const userRegion = buildPbrMaterialUserRegionEntries(resolvedSchema);
676
- const afterIbl = [...userRegion, ...appendInjection(userRegion, "ibl")];
677
- const merged = [...afterIbl, ...appendInjection(afterIbl, "transmission")];
678
- return {
679
- label: "pbr-material-skylight-bgl",
680
- entries: merged
681
- };
682
- }
683
- case "unlit-material": {
684
- const resolvedSchema = resolveMaterialParamSchema(spec, options);
685
- return {
686
- label: "unlit-material-bgl",
687
- entries: buildPbrMaterialUserRegionEntries(resolvedSchema)
688
- };
689
- }
690
- case "hdrp-7-slot": {
691
- const desc = createHdrpBindGroupLayoutDescriptor();
692
- return {
693
- label: desc.label ?? "hdrp-unified-bgl-group2",
694
- entries: [...desc.entries ?? []]
695
- };
696
- }
697
- case "fullscreen-post": {
698
- return {
699
- label: "fullscreen-post-bgl",
700
- entries: buildFullscreenPostInputEntries(spec)
701
- };
702
- }
703
- case "fullscreen-post-with-params": {
704
- return {
705
- label: "fullscreen-post-with-params-bgl",
706
- entries: [
707
- ...buildFullscreenPostInputEntries(spec),
708
- {
709
- binding: 2,
710
- visibility: GPU_SHADER_STAGE_FRAGMENT,
711
- buffer: { type: "uniform" }
712
- }
713
- ]
714
- };
715
- }
716
- case "fullscreen-post-with-scene-depth": {
717
- return {
718
- label: "fullscreen-post-with-scene-depth-bgl",
719
- entries: [
720
- ...buildFullscreenPostInputEntries(spec),
721
- {
722
- binding: 2,
723
- visibility: GPU_SHADER_STAGE_FRAGMENT,
724
- buffer: { type: "uniform" }
725
- },
726
- {
727
- binding: 3,
728
- visibility: GPU_SHADER_STAGE_FRAGMENT,
729
- texture: { sampleType: "depth", viewDimension: "2d" }
730
- },
731
- {
732
- binding: 4,
733
- visibility: GPU_SHADER_STAGE_FRAGMENT,
734
- sampler: { type: "non-filtering" }
735
- }
736
- ]
737
- };
738
- }
739
- case "fullscreen-post-with-scene-depth-msaa": {
740
- return {
741
- label: "fullscreen-post-with-scene-depth-msaa-bgl",
742
- entries: [
743
- ...buildFullscreenPostInputEntries(spec),
744
- {
745
- binding: 2,
746
- visibility: GPU_SHADER_STAGE_FRAGMENT,
747
- buffer: { type: "uniform" }
748
- },
749
- {
750
- binding: 3,
751
- visibility: GPU_SHADER_STAGE_FRAGMENT,
752
- texture: { sampleType: "depth", viewDimension: "2d", multisampled: true }
753
- },
754
- {
755
- binding: 4,
756
- visibility: GPU_SHADER_STAGE_FRAGMENT,
757
- sampler: { type: "non-filtering" }
758
- }
759
- ]
760
- };
761
- }
762
- }
763
- }
764
- function buildFullscreenPostInputEntries(spec) {
765
- const inputFormat = spec.attachments.depthFormat ?? spec.attachments.colorFormats[0];
766
- const sampleType = inputFormat === "depth32float" || inputFormat === "depth24plus" || inputFormat === "depth24plus-stencil8" || inputFormat === "depth16unorm" ? "depth" : inputFormat === "r32float" ? "unfilterable-float" : "float";
767
- return [
768
- {
769
- binding: 0,
770
- visibility: GPU_SHADER_STAGE_FRAGMENT,
771
- texture: { sampleType, viewDimension: "2d" }
772
- },
773
- {
774
- binding: 1,
775
- visibility: GPU_SHADER_STAGE_FRAGMENT,
776
- sampler: {
777
- type: sampleType === "depth" ? "comparison" : "filtering"
778
- }
779
- }
780
- ];
781
- }
782
164
  var DEFERRED_COLOR_FORMATS = [
783
165
  "rgba16float",
784
166
  "rgba8unorm",
@@ -880,12 +262,15 @@ function standardCapabilityVariantSet(clustered, storageBuffer, vertexColorAvail
880
262
  if (clustered && storageBuffer && vertexColorAvailable) return "";
881
263
  return `CLUSTER_FORWARD_AVAILABLE=${clustered}+STORAGE_BUFFER_AVAILABLE=${storageBuffer}`;
882
264
  }
883
- function standardTopologyVariantSet(topology, storageBuffer, vertexColorAvailable) {
884
- return standardCapabilityVariantSet(
265
+ function standardTopologyVariantSet(topology, storageBuffer, vertexColorAvailable, probeBlendAvailable = false) {
266
+ const capabilityVariantSet = standardCapabilityVariantSet(
885
267
  topology?.kind === "clustered",
886
268
  storageBuffer,
887
269
  vertexColorAvailable
888
270
  );
271
+ if (!probeBlendAvailable || !storageBuffer) return capabilityVariantSet;
272
+ const explicitCapabilityVariantSet = capabilityVariantSet === "" ? "CLUSTER_FORWARD_AVAILABLE=true+STORAGE_BUFFER_AVAILABLE=true" : capabilityVariantSet;
273
+ return `${explicitCapabilityVariantSet}+PROBE_BLEND_AVAILABLE=true`;
889
274
  }
890
275
  function standardTopologyBindGroupReady(topology, clusterBindGroup) {
891
276
  return topology?.kind !== "clustered" || clusterBindGroup !== null && clusterBindGroup !== void 0;
@@ -1525,52 +910,62 @@ function isMeshSsboDevMode() {
1525
910
  return true;
1526
911
  }
1527
912
  var _meshSsboScratch = new Uint8Array(0);
913
+ var _meshSsboScratchFloats = new Float32Array(0);
1528
914
  function uploadMeshSsboBatch(queue, meshStorageBuffer, validatedOrdered, foldDispatchPlan) {
1529
915
  const slotCount = validatedOrdered.length;
1530
916
  const neededBytes = slotCount * MESH_PER_ENTITY_STRIDE;
1531
917
  if (_meshSsboScratch.length < neededBytes) {
1532
918
  _meshSsboScratch = new Uint8Array(neededBytes);
919
+ _meshSsboScratchFloats = new Float32Array(_meshSsboScratch.buffer);
1533
920
  } else {
1534
921
  _meshSsboScratch.fill(0, 0, neededBytes);
1535
922
  }
1536
923
  const normalMatrixScratch = mat3.create();
924
+ const strideFloats = MESH_PER_ENTITY_STRIDE / Float32Array.BYTES_PER_ELEMENT;
1537
925
  for (let i = 0; i < slotCount; i++) {
1538
926
  const entry = validatedOrdered[i];
1539
927
  if (entry === void 0) continue;
1540
- const slot = new Float32Array(_meshSsboScratch.buffer, i * MESH_PER_ENTITY_STRIDE, 48);
928
+ const slot = i * strideFloats;
1541
929
  const isFoldHead = foldDispatchPlan?.headBuckets.has(i) === true;
1542
930
  if (isFoldHead) {
1543
- slot[0] = 1;
1544
- slot[5] = 1;
1545
- slot[10] = 1;
1546
- slot[15] = 1;
1547
- slot[16] = 1;
1548
- slot[20] = 1;
1549
- slot[24] = 1;
1550
- slot[28] = 1;
1551
- slot[33] = 1;
1552
- slot[38] = 1;
1553
- slot[43] = 1;
1554
- slot[44] = 1;
931
+ _meshSsboScratchFloats[slot] = 1;
932
+ _meshSsboScratchFloats[slot + 5] = 1;
933
+ _meshSsboScratchFloats[slot + 10] = 1;
934
+ _meshSsboScratchFloats[slot + 15] = 1;
935
+ _meshSsboScratchFloats[slot + 16] = 1;
936
+ _meshSsboScratchFloats[slot + 20] = 1;
937
+ _meshSsboScratchFloats[slot + 24] = 1;
938
+ _meshSsboScratchFloats[slot + 28] = 1;
939
+ _meshSsboScratchFloats[slot + 33] = 1;
940
+ _meshSsboScratchFloats[slot + 38] = 1;
941
+ _meshSsboScratchFloats[slot + 43] = 1;
942
+ _meshSsboScratchFloats[slot + 44] = 1;
1555
943
  } else {
1556
944
  const worldFromLocal = entry.source.transform.world;
1557
- for (let k = 0; k < 16; k++) slot[k] = worldFromLocal[k] ?? 0;
945
+ for (let k = 0; k < 16; k++) _meshSsboScratchFloats[slot + k] = worldFromLocal[k] ?? 0;
1558
946
  const normal = mat3.normalMatrix(normalMatrixScratch, worldFromLocal);
1559
- slot[16] = normal[0] ?? 0;
1560
- slot[17] = normal[1] ?? 0;
1561
- slot[18] = normal[2] ?? 0;
1562
- slot[20] = normal[3] ?? 0;
1563
- slot[21] = normal[4] ?? 0;
1564
- slot[22] = normal[5] ?? 0;
1565
- slot[24] = normal[6] ?? 0;
1566
- slot[25] = normal[7] ?? 0;
1567
- slot[26] = normal[8] ?? 0;
947
+ _meshSsboScratchFloats[slot + 16] = normal[0] ?? 0;
948
+ _meshSsboScratchFloats[slot + 17] = normal[1] ?? 0;
949
+ _meshSsboScratchFloats[slot + 18] = normal[2] ?? 0;
950
+ _meshSsboScratchFloats[slot + 20] = normal[3] ?? 0;
951
+ _meshSsboScratchFloats[slot + 21] = normal[4] ?? 0;
952
+ _meshSsboScratchFloats[slot + 22] = normal[5] ?? 0;
953
+ _meshSsboScratchFloats[slot + 24] = normal[6] ?? 0;
954
+ _meshSsboScratchFloats[slot + 25] = normal[7] ?? 0;
955
+ _meshSsboScratchFloats[slot + 26] = normal[8] ?? 0;
1568
956
  const previousWorld = entry.source.temporal?.previousTransform.world ?? worldFromLocal;
1569
- for (let k = 0; k < 16; k++) slot[28 + k] = previousWorld[k] ?? 0;
1570
- const reactiveMaterial = entry.source.materials.some(
1571
- (material) => material.transparent === true || material.materialShaderId === "forgeax::sprite" || material.materialShaderId === "forgeax::sprite-lit" || material.materialShaderId !== void 0 && !material.materialShaderId.startsWith("forgeax::")
1572
- );
1573
- slot[44] = entry.source.temporal?.reactive === true || reactiveMaterial ? 1 : 0;
957
+ for (let k = 0; k < 16; k++) {
958
+ _meshSsboScratchFloats[slot + 28 + k] = previousWorld[k] ?? 0;
959
+ }
960
+ let reactiveMaterial = false;
961
+ for (const material of entry.source.materials) {
962
+ const shader = material.materialShaderId;
963
+ if (material.transparent === true || shader === "forgeax::sprite" || shader === "forgeax::sprite-lit" || shader !== void 0 && !shader.startsWith("forgeax::")) {
964
+ reactiveMaterial = true;
965
+ break;
966
+ }
967
+ }
968
+ _meshSsboScratchFloats[slot + 44] = entry.source.temporal?.reactive === true || reactiveMaterial ? 1 : 0;
1574
969
  }
1575
970
  }
1576
971
  if (neededBytes > 0) {
@@ -1965,7 +1360,7 @@ function getOrCreateHdrpBuffers(runtime, grid = DEFAULT_CLUSTER_GRID) {
1965
1360
  }
1966
1361
  const device = runtime.device;
1967
1362
  const clusterUniformBytes = 32;
1968
- const lightDataBytes = MAX_LIGHTS * BYTES_PER_LIGHT_SLOT;
1363
+ const lightDataBytes = MAX_LIGHTS * BYTES_PER_DIRECT_LIGHT_SLOT;
1969
1364
  const clusterCells = grid.x * grid.y * grid.z;
1970
1365
  const clusterGridBytes = clusterCells * CLUSTER_GRID_STRIDE_U32 * 4;
1971
1366
  const lightIndexListBytes = LIGHT_INDEX_LIST_CAPACITY * 4;
@@ -2690,7 +2085,7 @@ function selectStandardClusterTransport(capabilities, prepared) {
2690
2085
  occupiedClusterCount: occupiedClusterCount(prepared),
2691
2086
  clusterGridBytes: prepared.layout.clusterGridU32Length * Uint32Array.BYTES_PER_ELEMENT,
2692
2087
  lightIndexListBytes: prepared.membershipEntryCount * Uint32Array.BYTES_PER_ELEMENT,
2693
- lightDataBytes: requested * 64,
2088
+ lightDataBytes: requested * BYTES_PER_DIRECT_LIGHT_SLOT,
2694
2089
  lightBoundsBytes: prepared.lightBounds.byteLength
2695
2090
  });
2696
2091
  }
@@ -2939,12 +2334,9 @@ function writePointsLinesViewUbo(queue, buffer, camera, width, height, model, st
2939
2334
  const uploaded = queue.writeBuffer(buffer, byteOffset, payload);
2940
2335
  if (!uploaded.ok) throw uploaded.error;
2941
2336
  }
2942
- function writeViewUbo(queue, viewUniformBuffer, camera, light, lights, spotShadowSnapshots, fogOrTemporalOrOffset, temporal, projectorSpotIndex) {
2943
- const byteOffset = typeof fogOrTemporalOrOffset === "number" ? fogOrTemporalOrOffset : 0;
2944
- const fogOrTemporal = typeof fogOrTemporalOrOffset === "number" ? void 0 : fogOrTemporalOrOffset;
2945
- const isTemporal = fogOrTemporal !== void 0 && ("currentJitterUv" in fogOrTemporal || "currentUnjitteredViewProjection" in fogOrTemporal);
2946
- const fog = isTemporal ? void 0 : fogOrTemporal;
2947
- const resolvedTemporal = temporal ?? (isTemporal ? fogOrTemporal : void 0);
2337
+ function writeViewUbo(queue, viewUniformBuffer, camera, light, lights, spotShadowSnapshots, temporalOrOffset, projectorSpotIndex) {
2338
+ const byteOffset = typeof temporalOrOffset === "number" ? temporalOrOffset : 0;
2339
+ const resolvedTemporal = typeof temporalOrOffset === "number" ? void 0 : temporalOrOffset;
2948
2340
  const projMatrix = computeProjectionMatrix(camera);
2949
2341
  const viewMatrix = computeViewMatrix(camera);
2950
2342
  const unjitteredViewProjection = mat4.create();
@@ -2995,6 +2387,13 @@ function writeViewUbo(queue, viewUniformBuffer, camera, light, lights, spotShado
2995
2387
  viewPayload[228] = camera.near;
2996
2388
  viewPayload[229] = camera.far;
2997
2389
  viewPayload[230] = camera.projection === "orthographic" ? 1 : 0;
2390
+ const previousCameraPosition = resolvedTemporal !== void 0 && "previousCameraPosition" in resolvedTemporal ? resolvedTemporal.previousCameraPosition : void 0;
2391
+ if (previousCameraPosition !== void 0) {
2392
+ viewPayload[232] = previousCameraPosition[0] ?? 0;
2393
+ viewPayload[233] = previousCameraPosition[1] ?? 0;
2394
+ viewPayload[234] = previousCameraPosition[2] ?? 0;
2395
+ viewPayload[235] = 1;
2396
+ }
2998
2397
  if (lights.splitPlanes !== void 0) {
2999
2398
  for (let s = 0; s < 4; s++) {
3000
2399
  for (let lane = 0; lane < 4; lane++) {
@@ -3030,14 +2429,6 @@ function writeViewUbo(queue, viewUniformBuffer, camera, light, lights, spotShado
3030
2429
  }
3031
2430
  }
3032
2431
  }
3033
- if (fog !== void 0) {
3034
- viewPayload[232] = fog.color[0] ?? 0;
3035
- viewPayload[233] = fog.color[1] ?? 0;
3036
- viewPayload[234] = fog.color[2] ?? 0;
3037
- viewPayload[235] = fog.density;
3038
- viewPayload[236] = fog.heightFalloff;
3039
- viewPayload[237] = fog.maxOpacity;
3040
- }
3041
2432
  const viewUploadResult = queue.writeBuffer(viewUniformBuffer, byteOffset, viewPayload);
3042
2433
  if (!viewUploadResult.ok) throw viewUploadResult.error;
3043
2434
  for (const snapshot of lights.pointShadow ?? []) {
@@ -3112,6 +2503,36 @@ function buildPerFrameBindGroups(internals, frameState, pipelineState, hasValida
3112
2503
  const b5View = atlasViewMaybe !== null ? atlasViewMaybe : pipelineState.shadowAtlasFallbackTextureView;
3113
2504
  const graphSpotShadowView = graphTargets?.spotShadow;
3114
2505
  const b8View = graphSpotShadowView !== void 0 ? graphSpotShadowView : pipelineState.shadowFallbackTextureView;
2506
+ const extendedLighting = pipelineState.extendedLightingAvailable ?? true;
2507
+ const iesProfileTextureView = pipelineState.iesProfileTextureView;
2508
+ const cookieTextureView = pipelineState.cookieTextureView;
2509
+ const cookieMatrixBuffer = pipelineState.cookieMatrixBuffer;
2510
+ const ltcLambertTextureView = pipelineState.ltcLambertTextureView;
2511
+ const ltcGgxTextureView = pipelineState.ltcGgxTextureView;
2512
+ const extendedLightingResources = extendedLighting && iesProfileTextureView !== void 0 && cookieTextureView !== void 0 && cookieMatrixBuffer !== void 0 && ltcLambertTextureView !== void 0 && ltcGgxTextureView !== void 0 ? {
2513
+ sampler: pipelineState.defaultSampler,
2514
+ iesProfileTextureView,
2515
+ cookieTextureView,
2516
+ ltcLambertTextureView,
2517
+ ltcGgxTextureView,
2518
+ cookieMatrixBuffer
2519
+ } : void 0;
2520
+ if (extendedLighting && extendedLightingResources === void 0) {
2521
+ return {
2522
+ viewBindGroup: null,
2523
+ meshBindGroup: null,
2524
+ hdrpClusterBindGroup: null,
2525
+ hdrpClusterMembershipBindGroup
2526
+ };
2527
+ }
2528
+ const extendedLightingViews = extendedLightingResources !== void 0 ? [
2529
+ extendedLightingResources.sampler,
2530
+ extendedLightingResources.iesProfileTextureView,
2531
+ extendedLightingResources.cookieTextureView,
2532
+ extendedLightingResources.ltcLambertTextureView,
2533
+ extendedLightingResources.ltcGgxTextureView,
2534
+ extendedLightingResources.cookieMatrixBuffer
2535
+ ] : [];
3115
2536
  const projectorAvailable = pipelineState.projectorAvailable !== false;
3116
2537
  const b11View = graphTargets?.projector ?? pipelineState.defaultWhiteTextureView;
3117
2538
  const b12Sampler = graphTargets?.projectorSampler ?? pipelineState.defaultSampler;
@@ -3119,38 +2540,23 @@ function buildPerFrameBindGroups(internals, frameState, pipelineState, hasValida
3119
2540
  frameState.viewBindGroupCache,
3120
2541
  [
3121
2542
  pipelineState.viewUniformBuffer,
3122
- pipelineState.pointLightsBuffer,
3123
- pipelineState.spotLightsBuffer,
3124
2543
  b3View,
3125
2544
  shadowSampler,
3126
2545
  b5View,
3127
2546
  pipelineState.shadowParamsBuffer,
3128
2547
  b8View,
3129
- ...projectorAvailable ? [b11View, b12Sampler] : [],
2548
+ ...extendedLightingViews,
2549
+ ...extendedLightingResources === void 0 && projectorAvailable ? [b11View, b12Sampler] : [],
3130
2550
  pipelineState.pointsLinesViewBuffer ?? pipelineState.viewUniformBuffer
3131
2551
  ],
3132
2552
  "view-main",
3133
2553
  () => {
3134
2554
  const entries = [
3135
2555
  {
3136
- binding: 0,
3137
- resource: {
3138
- kind: "buffer",
3139
- value: { buffer: pipelineState.viewUniformBuffer, size: VIEW_UNIFORM_BYTES }
3140
- }
3141
- },
3142
- {
3143
- binding: 1,
3144
- resource: {
3145
- kind: "buffer",
3146
- value: { buffer: pipelineState.pointLightsBuffer }
3147
- }
3148
- },
3149
- {
3150
- binding: 2,
2556
+ binding: 0,
3151
2557
  resource: {
3152
2558
  kind: "buffer",
3153
- value: { buffer: pipelineState.spotLightsBuffer }
2559
+ value: { buffer: pipelineState.viewUniformBuffer, size: VIEW_UNIFORM_BYTES }
3154
2560
  }
3155
2561
  },
3156
2562
  {
@@ -3222,9 +2628,56 @@ function buildPerFrameBindGroups(internals, frameState, pipelineState, hasValida
3222
2628
  }
3223
2629
  }
3224
2630
  },
3225
- ...projectorAvailable ? [
2631
+ ...extendedLightingResources === void 0 && projectorAvailable ? [
3226
2632
  { binding: 11, resource: { kind: "textureView", value: b11View } },
3227
2633
  { binding: 12, resource: { kind: "sampler", value: b12Sampler } }
2634
+ ] : [],
2635
+ ...extendedLightingResources !== void 0 ? [
2636
+ {
2637
+ binding: 9,
2638
+ resource: {
2639
+ kind: "sampler",
2640
+ value: extendedLightingResources.sampler
2641
+ }
2642
+ },
2643
+ {
2644
+ binding: 11,
2645
+ resource: {
2646
+ kind: "textureView",
2647
+ value: extendedLightingResources.iesProfileTextureView
2648
+ }
2649
+ },
2650
+ {
2651
+ binding: 12,
2652
+ resource: {
2653
+ kind: "textureView",
2654
+ value: extendedLightingResources.cookieTextureView
2655
+ }
2656
+ },
2657
+ {
2658
+ binding: 13,
2659
+ resource: {
2660
+ kind: "textureView",
2661
+ value: extendedLightingResources.ltcLambertTextureView
2662
+ }
2663
+ },
2664
+ {
2665
+ binding: 14,
2666
+ resource: {
2667
+ kind: "textureView",
2668
+ value: extendedLightingResources.ltcGgxTextureView
2669
+ }
2670
+ },
2671
+ {
2672
+ binding: 15,
2673
+ resource: {
2674
+ kind: "buffer",
2675
+ value: {
2676
+ buffer: extendedLightingResources.cookieMatrixBuffer,
2677
+ size: COOKIE_MATRIX_BYTES
2678
+ }
2679
+ }
2680
+ }
3228
2681
  ] : []
3229
2682
  // feat-20260625-spot-light-shadow-mapping w25: the per-spot
3230
2683
  // fragment-read lightViewProj matrices fold into the View UBO
@@ -3334,13 +2787,14 @@ function prepareFrameLighting(internals, frameState, lights, camera, pipelineSta
3334
2787
  const directionalLight = lights.directional;
3335
2788
  const pointLights = lights.point;
3336
2789
  const spotLights = lights.spot;
2790
+ const rectLights = lights.rect;
3337
2791
  const light = directionalLight ?? {
3338
2792
  kind: "directional",
3339
2793
  direction: vec3.create(0, -1, 0),
3340
2794
  color: vec3.create(0, 0, 0),
3341
2795
  intensity: 0
3342
2796
  };
3343
- const totalLightCount = (directionalLight !== void 0 ? 1 : 0) + pointLights.length + spotLights.length;
2797
+ const totalLightCount = (directionalLight !== void 0 ? 1 : 0) + pointLights.length + spotLights.length + rectLights.length;
3344
2798
  const clusterGrid = frameState.installedPipelineConfig?.clusterGrid ?? DEFAULT_CLUSTER_GRID;
3345
2799
  const local = [
3346
2800
  ...pointLights.map((source) => ({
@@ -3356,6 +2810,13 @@ function prepareFrameLighting(internals, frameState, lights, camera, pipelineSta
3356
2810
  position: source.position,
3357
2811
  range: Number.isFinite(source.invRangeSquared) && source.invRangeSquared > 0 ? Math.sqrt(1 / source.invRangeSquared) : 1e3,
3358
2812
  source
2813
+ })),
2814
+ ...rectLights.map((source) => ({
2815
+ kind: "rect-area",
2816
+ shadowed: false,
2817
+ position: source.position,
2818
+ range: (Number.isFinite(source.invRangeSquared) && source.invRangeSquared > 0 ? Math.sqrt(1 / source.invRangeSquared) : 1e3) + Math.hypot(source.halfWidth, source.halfHeight),
2819
+ source
3359
2820
  }))
3360
2821
  ];
3361
2822
  const prepared = prepareStandardLighting({
@@ -3375,6 +2836,7 @@ function prepareFrameLighting(internals, frameState, lights, camera, pipelineSta
3375
2836
  light,
3376
2837
  pointLights,
3377
2838
  spotLights,
2839
+ rectLights,
3378
2840
  totalLightCount,
3379
2841
  standard: { kind: "no-local-lights", prepared: prepared.value }
3380
2842
  });
@@ -3392,10 +2854,96 @@ function prepareFrameLighting(internals, frameState, lights, camera, pipelineSta
3392
2854
  light,
3393
2855
  pointLights,
3394
2856
  spotLights,
2857
+ rectLights,
3395
2858
  totalLightCount,
3396
2859
  standard: { kind: "clustered", prepared: prepared.value, transport: transport.value }
3397
2860
  });
3398
2861
  }
2862
+ function modifierDigest(data) {
2863
+ let hash = 2166136261;
2864
+ for (let index = 0; index < data.length; index += 1) {
2865
+ hash ^= data[index] ?? 0;
2866
+ hash = Math.imul(hash, 16777619);
2867
+ }
2868
+ return hash >>> 0;
2869
+ }
2870
+ function writeSpotModifierTextures(internals, pipelineState, spots) {
2871
+ const iesTexture = pipelineState.iesProfileTexture;
2872
+ const cookieTexture = pipelineState.cookieTexture;
2873
+ const cookieMatrixBuffer = pipelineState.cookieMatrixBuffer;
2874
+ if (iesTexture === void 0 && cookieTexture === void 0 && cookieMatrixBuffer === void 0)
2875
+ return;
2876
+ let state = pipelineState.spotModifierUploadState;
2877
+ if (state === void 0) {
2878
+ state = { ies: /* @__PURE__ */ new Map(), cookie: /* @__PURE__ */ new Map(), cookieMatrix: /* @__PURE__ */ new Map() };
2879
+ pipelineState.spotModifierUploadState = state;
2880
+ } else if (state.cookieMatrix === void 0) {
2881
+ state = { ...state, cookieMatrix: /* @__PURE__ */ new Map() };
2882
+ pipelineState.spotModifierUploadState = state;
2883
+ }
2884
+ for (const spot of spots) {
2885
+ if (spot.iesProfileSlice !== void 0 && spot.iesProfileData !== void 0 && iesTexture) {
2886
+ if (spot.iesProfileData.byteLength === IES_SLICE_WIDTH * IES_SLICE_HEIGHT * 2) {
2887
+ const digest = modifierDigest(spot.iesProfileData);
2888
+ if (state.ies.get(spot.iesProfileSlice) !== digest) {
2889
+ const result = internals.device.queue.writeTexture(
2890
+ { texture: iesTexture, mipLevel: 0, origin: { x: 0, y: 0, z: spot.iesProfileSlice } },
2891
+ spot.iesProfileData,
2892
+ { offset: 0, bytesPerRow: IES_SLICE_WIDTH * 2, rowsPerImage: IES_SLICE_HEIGHT },
2893
+ { width: IES_SLICE_WIDTH, height: IES_SLICE_HEIGHT, depthOrArrayLayers: 1 }
2894
+ );
2895
+ if (!result.ok) throw result.error;
2896
+ state.ies.set(spot.iesProfileSlice, digest);
2897
+ }
2898
+ }
2899
+ }
2900
+ for (const modifier of [
2901
+ {
2902
+ slice: spot.cookieSlice,
2903
+ data: spot.cookieData,
2904
+ matrix: spot.cookieMatrix
2905
+ },
2906
+ {
2907
+ slice: spot.projectorSlice,
2908
+ data: spot.projectorData,
2909
+ matrix: spot.projectorMatrix
2910
+ }
2911
+ ]) {
2912
+ if (modifier.slice !== void 0 && modifier.data !== void 0 && cookieTexture) {
2913
+ if (modifier.data.byteLength === COOKIE_SLICE_SIZE * COOKIE_SLICE_SIZE * 4) {
2914
+ const digest = modifierDigest(modifier.data);
2915
+ if (state.cookie.get(modifier.slice) !== digest) {
2916
+ const result = internals.device.queue.writeTexture(
2917
+ { texture: cookieTexture, mipLevel: 0, origin: { x: 0, y: 0, z: modifier.slice } },
2918
+ modifier.data,
2919
+ { offset: 0, bytesPerRow: COOKIE_SLICE_SIZE * 4, rowsPerImage: COOKIE_SLICE_SIZE },
2920
+ { width: COOKIE_SLICE_SIZE, height: COOKIE_SLICE_SIZE, depthOrArrayLayers: 1 }
2921
+ );
2922
+ if (!result.ok) throw result.error;
2923
+ state.cookie.set(modifier.slice, digest);
2924
+ }
2925
+ }
2926
+ }
2927
+ if (modifier.slice !== void 0 && modifier.matrix !== void 0 && cookieMatrixBuffer) {
2928
+ const matrixBytes = new Uint8Array(
2929
+ modifier.matrix.buffer,
2930
+ modifier.matrix.byteOffset,
2931
+ modifier.matrix.byteLength
2932
+ );
2933
+ const digest = modifierDigest(matrixBytes);
2934
+ if (state.cookieMatrix.get(modifier.slice) !== digest) {
2935
+ const result = internals.device.queue.writeBuffer(
2936
+ cookieMatrixBuffer,
2937
+ modifier.slice * 16 * Float32Array.BYTES_PER_ELEMENT,
2938
+ modifier.matrix
2939
+ );
2940
+ if (!result.ok) throw result.error;
2941
+ state.cookieMatrix.set(modifier.slice, digest);
2942
+ }
2943
+ }
2944
+ }
2945
+ }
2946
+ }
3399
2947
  function writeShadowParamsBuffer(internals, frameState, pipelineState) {
3400
2948
  const SHADOW_PARAMS_LANE_COUNT = 4;
3401
2949
  const SHADOW_PARAMS_FLOATS_PER_LANE = 4;
@@ -3437,7 +2985,7 @@ function warnZeroLightStandard(frameState, renderables, skylight, totalLightCoun
3437
2985
  }
3438
2986
  }
3439
2987
  }
3440
- function writeHdrpClusterAndSsaoBuffers(internals, frameState, camera, prepared, transport, profilePhase, gpuMembershipPipelineReady = false, membershipBindGroupLayout = null, projectorLightSlotIndex) {
2988
+ function writeHdrpClusterAndSsaoBuffers(internals, frameState, camera, prepared, transport, profilePhase, gpuMembershipPipelineReady = false, membershipBindGroupLayout = null, projectorLightSlotIndex, pipelineState) {
3441
2989
  const configuredClusterGrid = prepared.layout.grid;
3442
2990
  const gpuMembership = transport.producer === "gpu";
3443
2991
  if (gpuMembership && (!gpuMembershipPipelineReady || membershipBindGroupLayout === null)) {
@@ -3485,6 +3033,13 @@ function writeHdrpClusterAndSsaoBuffers(internals, frameState, camera, prepared,
3485
3033
  clusterGridBuffer: hdrpBuffers.clusterGridBuffer
3486
3034
  };
3487
3035
  }
3036
+ if (pipelineState !== void 0) {
3037
+ const preparedSpots = [];
3038
+ for (const local of prepared.local) {
3039
+ if (local.source?.kind === "spot") preparedSpots.push(local.source);
3040
+ }
3041
+ writeSpotModifierTextures(internals, pipelineState, preparedSpots);
3042
+ }
3488
3043
  const gridX = prepared.layout.grid.x;
3489
3044
  const gridY = prepared.layout.grid.y;
3490
3045
  const gridZ = prepared.layout.grid.z;
@@ -3497,22 +3052,16 @@ function writeHdrpClusterAndSsaoBuffers(internals, frameState, camera, prepared,
3497
3052
  profilePhase,
3498
3053
  "record/scene-state/hdrp-cluster/payload-packing",
3499
3054
  () => {
3500
- const lightDataPayload = new Float32Array(prepared.layout.lightDataSlotCount * 16);
3055
+ const lightDataPayload = new Float32Array(
3056
+ prepared.layout.lightDataSlotCount * DIRECT_LIGHT_SLOT_FLOAT_COUNT
3057
+ );
3501
3058
  let slotIdx = 0;
3502
3059
  for (const local of prepared.local) {
3503
3060
  const source = local.source;
3504
3061
  if (source === void 0) return null;
3505
- const projectorSelected = projectorLightSlotIndex !== void 0 && projectorLightSlotIndex === slotIdx;
3506
- const packed = source.kind === "point" && source.shadowAtlasLayer !== void 0 && source.shadowAtlasLayer >= 0 && source.shadowNear !== void 0 && source.shadowFar !== void 0 ? packLightSlot(
3507
- source,
3508
- {
3509
- shadowAtlasLayer: source.shadowAtlasLayer,
3510
- near: source.shadowNear,
3511
- far: source.shadowFar
3512
- },
3513
- projectorSelected
3514
- ) : packLightSlot(source, void 0, projectorSelected);
3515
- lightDataPayload.set(packed, slotIdx * 16);
3062
+ const projectorSelected = projectorLightSlotIndex === void 0 ? void 0 : projectorLightSlotIndex === slotIdx;
3063
+ const packed = packDirectLightSlot(source, projectorSelected);
3064
+ lightDataPayload.set(packed, slotIdx * DIRECT_LIGHT_SLOT_FLOAT_COUNT);
3516
3065
  slotIdx += 1;
3517
3066
  }
3518
3067
  const clusterSsaoConfig = frameState.installedPipelineConfig?.ssao;
@@ -3526,7 +3075,10 @@ function writeHdrpClusterAndSsaoBuffers(internals, frameState, camera, prepared,
3526
3075
  );
3527
3076
  return {
3528
3077
  hdrpBuffers,
3529
- lightDataUploadPayload: lightDataPayload.subarray(0, slotIdx * 16),
3078
+ lightDataUploadPayload: lightDataPayload.subarray(
3079
+ 0,
3080
+ slotIdx * DIRECT_LIGHT_SLOT_FLOAT_COUNT
3081
+ ),
3530
3082
  clusterUniformPayload: new Uint8Array(clusterUniformPayload)
3531
3083
  };
3532
3084
  }
@@ -4792,51 +4344,6 @@ function deriveRenderDataCubemap(source) {
4792
4344
  cubeUsage: GPU_TEXTURE_USAGE_RENDER_ATTACHMENT_AND_TEXTURE_BINDING | GPU_TEXTURE_USAGE_COPY_DST | GPU_TEXTURE_USAGE_COPY_SRC
4793
4345
  });
4794
4346
  }
4795
-
4796
- // src/targets/material-source.ts
4797
- var sourceBindings = /* @__PURE__ */ new WeakMap();
4798
- function sourceToken() {
4799
- return Object.freeze({});
4800
- }
4801
- function resolveRenderTargetMaterialSource(source) {
4802
- return sourceBindings.get(source);
4803
- }
4804
- function invalid(field, value, expected) {
4805
- return {
4806
- ok: false,
4807
- error: new RenderTargetDescriptorInvalidError({ field, value, expected })
4808
- };
4809
- }
4810
- function createRenderTargetMaterialSource(target, descriptor, options) {
4811
- if (options.aspect !== "color") return invalid("aspect", options.aspect, "color");
4812
- if (options.dimension !== descriptor.shape) {
4813
- return invalid("dimension", options.dimension, `dimension matches ${descriptor.shape}`);
4814
- }
4815
- const mipCount = descriptor.mipLevels === 1 ? 1 : Math.floor(Math.log2(Math.max(descriptor.width, descriptor.height))) + 1;
4816
- if (!Number.isInteger(options.mipLevel) || options.mipLevel < 0 || options.mipLevel >= mipCount) {
4817
- return invalid("mipLevel", options.mipLevel, `an admitted mip level below ${mipCount}`);
4818
- }
4819
- if (!Number.isInteger(options.generation) || options.generation < 0) {
4820
- return invalid("generation", options.generation, "a non-negative device generation");
4821
- }
4822
- const result = {
4823
- ok: true,
4824
- value: Object.freeze({
4825
- source: sourceToken(),
4826
- target,
4827
- generation: options.generation,
4828
- shape: descriptor.shape,
4829
- format: descriptor.format,
4830
- view: Object.freeze({
4831
- dimension: options.dimension,
4832
- mipLevel: options.mipLevel,
4833
- resolveRequired: descriptor.sampleCount === 4
4834
- })
4835
- })
4836
- };
4837
- sourceBindings.set(result.value.source, result.value);
4838
- return result;
4839
- }
4840
4347
  var STANDARD_PBR_UBO_SIZE = 384;
4841
4348
  var MATERIAL_PER_ENTITY_STRIDE = 512;
4842
4349
  function resolveSurfaceProfile(storageFormat, viewFormat, facts) {
@@ -5550,9 +5057,14 @@ function submitSubmeshDraws(pass, state, pipeline, instanceDraws, indexed, index
5550
5057
  state.pipeline = pipeline;
5551
5058
  }
5552
5059
  for (const instanceDraw of instanceDraws) {
5553
- if (instanceDraw.instanceBuffer !== state.instancesBuffer) {
5554
- pass.setBindGroup(3, instanceDraw.instanceBindGroup);
5060
+ if (instanceDraw.instanceBuffer !== state.instancesBuffer || instanceDraw.probeOffset !== state.probeOffset) {
5061
+ if (instanceDraw.probeOffset < 0) {
5062
+ pass.setBindGroup(3, instanceDraw.instanceBindGroup);
5063
+ } else {
5064
+ pass.setBindGroup(3, instanceDraw.instanceBindGroup, [instanceDraw.probeOffset]);
5065
+ }
5555
5066
  state.instancesBuffer = instanceDraw.instanceBuffer;
5067
+ state.probeOffset = instanceDraw.probeOffset;
5556
5068
  }
5557
5069
  if (indexed) {
5558
5070
  pass.drawIndexed(indexCount, instanceDraw.instanceCount, indexOffset, 0, 0);
@@ -5590,13 +5102,15 @@ function recordGeometryDraws(c, pass, matchedMaterials, materialSlotIndices, sam
5590
5102
  let lastIndexBuffer = null;
5591
5103
  const bindingState = {
5592
5104
  pipeline: null,
5593
- instancesBuffer: null
5105
+ instancesBuffer: null,
5106
+ probeOffset: -1
5594
5107
  };
5595
5108
  const identityInstanceBuffer = pipelineState.identityInstanceBuffer;
5596
5109
  const identityInstanceDraws = [
5597
5110
  {
5598
5111
  instanceBuffer: identityInstanceBuffer,
5599
- instanceBindGroup: resolveGeometryInstancesBindGroup(c, identityInstanceBuffer),
5112
+ instanceBindGroup: resolveGeometryInstancesBindGroup(c, identityInstanceBuffer, void 0),
5113
+ probeOffset: -1,
5600
5114
  instanceCount: 1
5601
5115
  }
5602
5116
  ];
@@ -5605,13 +5119,17 @@ function recordGeometryDraws(c, pass, matchedMaterials, materialSlotIndices, sam
5605
5119
  const meshGroup2DynamicOffsets = [0];
5606
5120
  let lastStencilReference = null;
5607
5121
  const materialPipelineLookupCache = /* @__PURE__ */ new Map();
5122
+ const recordOcclusionCandidate = (draw) => {
5123
+ draw();
5124
+ };
5608
5125
  const resolveMaterialPipeline = (materialShaderId, renderState, topology, indexFormat, variantSet, colorFormat, layoutProjection) => {
5126
+ const reflectionFallbackFormats = materialShaderId === "forgeax::default-standard-pbr" && c.reflectionFallbackColorFormat !== void 0 ? [c.reflectionFallbackColorFormat] : void 0;
5609
5127
  const renderStateKey = renderStateHash(renderState);
5610
5128
  const shaderLookupCache = materialPipelineLookupCache.get(materialShaderId);
5611
5129
  const cachedLookups = shaderLookupCache?.get(renderStateKey);
5612
5130
  if (cachedLookups !== void 0) {
5613
5131
  for (const cached of cachedLookups) {
5614
- if (cached.isHdrTarget === isHdrTarget && cached.renderStateKey === renderStateKey && cached.topology === topology && cached.indexFormat === indexFormat && cached.variantSet === variantSet && cached.passKind === passKind && cached.layoutProjection.digest === layoutProjection.digest && cached.sampleCount === sampleCount && cached.colorFormatOverride === colorFormat) {
5132
+ if (cached.isHdrTarget === isHdrTarget && cached.renderStateKey === renderStateKey && cached.topology === topology && cached.indexFormat === indexFormat && cached.variantSet === variantSet && cached.passKind === passKind && cached.layoutProjection.digest === layoutProjection.digest && cached.sampleCount === sampleCount && cached.colorFormatOverride === colorFormat && cached.additionalColorFormats?.join(",") === reflectionFallbackFormats?.join(",")) {
5615
5133
  return cached.handle;
5616
5134
  }
5617
5135
  }
@@ -5622,13 +5140,14 @@ function recordGeometryDraws(c, pass, matchedMaterials, materialSlotIndices, sam
5622
5140
  return null;
5623
5141
  }
5624
5142
  const resolvedVariantSet = resolvedVariantSetResult.value;
5143
+ const fallbackVariantSet = materialShaderId !== "forgeax::default-standard-pbr" ? resolvedVariantSet : c.reflectionFallbackColorFormat !== void 0 && resolvedVariantSet === "" ? "" : `${resolvedVariantSet === void 0 || resolvedVariantSet === "" ? "" : `${resolvedVariantSet}+`}REFLECTION_FALLBACK_AVAILABLE=${c.reflectionFallbackColorFormat !== void 0}`;
5625
5144
  const resolvePipeline = () => runtime.getMaterialShaderPipelineEntry?.(
5626
5145
  materialShaderId,
5627
5146
  isHdrTarget,
5628
5147
  renderState,
5629
5148
  topology,
5630
5149
  indexFormat,
5631
- resolvedVariantSet,
5150
+ fallbackVariantSet,
5632
5151
  passKind,
5633
5152
  void 0,
5634
5153
  sampleCount,
@@ -5636,7 +5155,10 @@ function recordGeometryDraws(c, pass, matchedMaterials, materialSlotIndices, sam
5636
5155
  void 0,
5637
5156
  void 0,
5638
5157
  void 0,
5639
- layoutProjection
5158
+ layoutProjection,
5159
+ void 0,
5160
+ void 0,
5161
+ reflectionFallbackFormats
5640
5162
  ) ?? null;
5641
5163
  const handle = profilePhase === void 0 ? resolvePipeline() : profileGeometrySegment(c, passKind, "pipeline-selection", resolvePipeline);
5642
5164
  if (handle !== null) {
@@ -5651,6 +5173,7 @@ function recordGeometryDraws(c, pass, matchedMaterials, materialSlotIndices, sam
5651
5173
  layoutProjection,
5652
5174
  sampleCount,
5653
5175
  colorFormatOverride: colorFormat,
5176
+ additionalColorFormats: reflectionFallbackFormats,
5654
5177
  handle
5655
5178
  };
5656
5179
  if (shaderLookupCache === void 0) {
@@ -5672,7 +5195,12 @@ function recordGeometryDraws(c, pass, matchedMaterials, materialSlotIndices, sam
5672
5195
  const pointsLinesSubmission = c.pointsLines?.prepare(entry, clusteredLighting);
5673
5196
  if (entry.source.pointsLines !== void 0 && pointsLinesSubmission?.plan.drawCount !== 1)
5674
5197
  continue;
5675
- if (passKind === "forward" && c.gpuDrivenEntityKeys.has(worldEntityKey(entry.source.worldId, entry.source.entityKey))) {
5198
+ if (passKind === "forward" && c.gpuDrivenEntityKeys.has(
5199
+ worldEntityKey(
5200
+ c.gpuDrivenWorldKeys?.[entry.source.worldId] ?? entry.source.worldId,
5201
+ entry.source.entityKey
5202
+ )
5203
+ )) {
5676
5204
  continue;
5677
5205
  }
5678
5206
  if (matchedMaterials !== null && !matchedMaterials.has(entry.renderableIndex)) continue;
@@ -5735,11 +5263,9 @@ function recordGeometryDraws(c, pass, matchedMaterials, materialSlotIndices, sam
5735
5263
  const pointsLinesMeshGroup = meshBindGroup ?? meshGroup2;
5736
5264
  if (pointsLinesMeshGroup === null) continue;
5737
5265
  pass.setBindGroup(2, pointsLinesMeshGroup, meshGroup2DynamicOffsets);
5738
- pass.setBindGroup(
5739
- 3,
5740
- identityInstanceDraws[0]?.instanceBindGroup ?? resolveGeometryInstancesBindGroup(c, identityInstanceBuffer)
5741
- );
5742
- recordPointsLinesDraw(pass, pointsLinesSubmission.plan);
5266
+ const pointsLinesInstancesBg = identityInstanceDraws[0]?.instanceBindGroup ?? resolveGeometryInstancesBindGroup(c, identityInstanceBuffer, void 0);
5267
+ pass.setBindGroup(3, pointsLinesInstancesBg);
5268
+ recordOcclusionCandidate(() => recordPointsLinesDraw(pass, pointsLinesSubmission.plan));
5743
5269
  pass.setBindGroup(0, viewBindGroup, [viewBindGroupDynamicOffset, 0]);
5744
5270
  continue;
5745
5271
  }
@@ -5754,12 +5280,13 @@ function recordGeometryDraws(c, pass, matchedMaterials, materialSlotIndices, sam
5754
5280
  }
5755
5281
  }
5756
5282
  dispatchCounts.unlit += 1;
5757
- const instanceDraws = resolveGeometryInstanceBuffer(c, entry, identityInstanceDraws);
5283
+ const instanceDraws = resolveGeometryInstanceBuffer(c, entry, identityInstanceDraws, false);
5758
5284
  if (instanceDraws === null) continue;
5759
5285
  let group2BindGroup = meshGroup2;
5760
5286
  meshGroup2DynamicOffsets[0] = i * MESH_PER_ENTITY_STRIDE;
5761
5287
  let group2DynamicOffsets = meshGroup2DynamicOffsets;
5762
5288
  const isSkinEntry = entry.source.skin !== void 0;
5289
+ const probeBlendRecordAvailable = runtime.device.caps.storageBuffer && entry.source.probeBlendRecord !== void 0;
5763
5290
  const skinAllocator = pipelineState.skinPaletteAllocator;
5764
5291
  const skinSlice = entry.source.skin;
5765
5292
  const clusteredSkin = clusteredLighting;
@@ -5776,7 +5303,8 @@ function recordGeometryDraws(c, pass, matchedMaterials, materialSlotIndices, sam
5776
5303
  standardTopologyVariantSet(
5777
5304
  c.standardLighting,
5778
5305
  runtime.device.caps.storageBuffer,
5779
- entry.mesh.layoutProjection.attributes.some((attribute) => attribute.key === "color")
5306
+ entry.mesh.layoutProjection.attributes.some((attribute) => attribute.key === "color"),
5307
+ probeBlendRecordAvailable
5780
5308
  )
5781
5309
  );
5782
5310
  if (!skinVariantSetResult.ok) runtime.errorRegistry.fire(skinVariantSetResult.error);
@@ -5796,7 +5324,10 @@ function recordGeometryDraws(c, pass, matchedMaterials, materialSlotIndices, sam
5796
5324
  void 0,
5797
5325
  void 0,
5798
5326
  void 0,
5799
- entry.mesh.layoutProjection
5327
+ entry.mesh.layoutProjection,
5328
+ void 0,
5329
+ void 0,
5330
+ void 0
5800
5331
  ) ?? null : null;
5801
5332
  if (skinResources !== null && skinPsoProbe !== null) {
5802
5333
  const meshBindSize = runtime.device.caps.storageBuffer ? MESH_SSBO_BYTES : MESH_UBO_FULL_ARRAY_BYTES;
@@ -5897,6 +5428,7 @@ function recordGeometryDraws(c, pass, matchedMaterials, materialSlotIndices, sam
5897
5428
  pass.setBindGroup(1, perSubmeshBg, materialGroup1DynamicOffsets, 0, 1);
5898
5429
  const smTopology = sm.topology;
5899
5430
  const smMaterialShaderId = entry.source.skin !== void 0 ? SKIN_MATERIAL_SHADER_ID : submeshMaterial.materialShaderId;
5431
+ const probeBlendAvailable = probeBlendRecordAvailable && isStandardPbrMaterialShader(smMaterialShaderId);
5900
5432
  const isSpriteShader = smMaterialShaderId === "forgeax::sprite" || smMaterialShaderId === "forgeax::sprite-lit";
5901
5433
  const basePipelineRenderState = isSpriteShader ? {
5902
5434
  ...submeshMaterial.renderState,
@@ -5942,20 +5474,16 @@ function recordGeometryDraws(c, pass, matchedMaterials, materialSlotIndices, sam
5942
5474
  const capabilityVariantSet = standardTopologyVariantSet(
5943
5475
  c.standardLighting,
5944
5476
  runtime.device.caps.storageBuffer,
5945
- hasVertexColor
5477
+ hasVertexColor,
5478
+ probeBlendAvailable
5946
5479
  );
5947
5480
  const variantSet = isSpriteShader ? smMaterialShaderId === "forgeax::sprite" && entry.source.spriteInstances !== void 0 ? "" : void 0 : entry.variantSet === void 0 ? capabilityVariantSet : capabilityVariantSet === "" ? entry.variantSet : `${capabilityVariantSet}+${entry.variantSet}`;
5948
- const projectionVariantSetResult = isSpriteShader ? { ok: true, value: variantSet } : variantSetFromVertexLayoutProjection(entry.mesh.layoutProjection, variantSet);
5949
- if (!projectionVariantSetResult.ok) {
5950
- runtime.errorRegistry.fire(projectionVariantSetResult.error);
5951
- continue;
5952
- }
5953
5481
  const cachedPipeline = resolveMaterialPipeline(
5954
5482
  smMaterialShaderId,
5955
5483
  pipelineRenderState,
5956
5484
  smTopology,
5957
5485
  entry.mesh.indexFormat,
5958
- projectionVariantSetResult.value,
5486
+ variantSet,
5959
5487
  colorFormatOverride,
5960
5488
  entry.mesh.layoutProjection
5961
5489
  );
@@ -5967,6 +5495,13 @@ function recordGeometryDraws(c, pass, matchedMaterials, materialSlotIndices, sam
5967
5495
  if (smPipelineHandle === null) {
5968
5496
  continue;
5969
5497
  }
5498
+ const instanceDraws2 = resolveGeometryInstanceBuffer(
5499
+ c,
5500
+ entry,
5501
+ identityInstanceDraws,
5502
+ probeBlendAvailable
5503
+ );
5504
+ if (instanceDraws2 === null) continue;
5970
5505
  if (!isSkinEntry) {
5971
5506
  materialGroup2Contract = materialPipelineEntry?.group2Contract;
5972
5507
  if (materialGroup2Contract === void 0) continue;
@@ -5980,40 +5515,63 @@ function recordGeometryDraws(c, pass, matchedMaterials, materialSlotIndices, sam
5980
5515
  }
5981
5516
  pass.setBindGroup(2, group2BindGroup, group2DynamicOffsets);
5982
5517
  if (profilePhase === void 0) {
5983
- submitSubmeshDraws(
5984
- pass,
5985
- bindingState,
5986
- smPipelineHandle,
5987
- instanceDraws,
5988
- entry.mesh.indexed,
5989
- sm.indexCount,
5990
- sm.vertexCount,
5991
- sm.indexOffset
5992
- );
5993
- } else {
5994
- profileGeometrySegment(
5995
- c,
5996
- passKind,
5997
- "draw-submit",
5518
+ recordOcclusionCandidate(
5998
5519
  () => submitSubmeshDraws(
5999
5520
  pass,
6000
5521
  bindingState,
6001
5522
  smPipelineHandle,
6002
- instanceDraws,
5523
+ instanceDraws2,
6003
5524
  entry.mesh.indexed,
6004
5525
  sm.indexCount,
6005
5526
  sm.vertexCount,
6006
5527
  sm.indexOffset
6007
5528
  )
6008
5529
  );
5530
+ } else {
5531
+ profileGeometrySegment(
5532
+ c,
5533
+ passKind,
5534
+ "draw-submit",
5535
+ () => recordOcclusionCandidate(
5536
+ () => submitSubmeshDraws(
5537
+ pass,
5538
+ bindingState,
5539
+ smPipelineHandle,
5540
+ instanceDraws2,
5541
+ entry.mesh.indexed,
5542
+ sm.indexCount,
5543
+ sm.vertexCount,
5544
+ sm.indexOffset
5545
+ )
5546
+ )
5547
+ );
6009
5548
  }
6010
5549
  }
6011
5550
  }
6012
5551
  }
6013
- function resolveGeometryInstanceBuffer(c, entry, identityInstanceDraws) {
5552
+ function resolveGeometryInstanceBuffer(c, entry, identityInstanceDraws, useProbeBlend) {
6014
5553
  const { runtime, pipelineState, frameState } = c;
6015
5554
  const inst = entry.source.instances;
6016
- if (inst === void 0) return identityInstanceDraws;
5555
+ const probeBinding = !useProbeBlend || !runtime.device.caps.storageBuffer || entry.source.probeBlendRecord === void 0 ? void 0 : resolveProbeBlendBuffer(
5556
+ c,
5557
+ entry.source.probeBlendRecord,
5558
+ worldEntityKey(entry.source.worldId, entry.source.entityKey)
5559
+ );
5560
+ if (inst === void 0) {
5561
+ const identity = identityInstanceDraws[0];
5562
+ if (identity === void 0) return null;
5563
+ return [
5564
+ {
5565
+ ...identity,
5566
+ instanceBindGroup: resolveGeometryInstancesBindGroup(
5567
+ c,
5568
+ pipelineState.identityInstanceBuffer,
5569
+ probeBinding?.buffer
5570
+ ),
5571
+ probeOffset: probeBinding?.offset ?? -1
5572
+ }
5573
+ ];
5574
+ }
6017
5575
  if (inst.instanceCount === 0) return [];
6018
5576
  let instanceBuffer = pipelineState.identityInstanceBuffer;
6019
5577
  let instanceCount = 1;
@@ -6047,7 +5605,12 @@ function resolveGeometryInstanceBuffer(c, entry, identityInstanceDraws) {
6047
5605
  }
6048
5606
  draws.push({
6049
5607
  instanceBuffer: buffer.handle,
6050
- instanceBindGroup: resolveGeometryInstancesBindGroup(c, buffer.handle),
5608
+ instanceBindGroup: resolveGeometryInstancesBindGroup(
5609
+ c,
5610
+ buffer.handle,
5611
+ probeBinding?.buffer
5612
+ ),
5613
+ probeOffset: probeBinding?.offset ?? -1,
6051
5614
  instanceCount: count
6052
5615
  });
6053
5616
  }
@@ -6124,21 +5687,57 @@ function resolveGeometryInstanceBuffer(c, entry, identityInstanceDraws) {
6124
5687
  return [
6125
5688
  {
6126
5689
  instanceBuffer,
6127
- instanceBindGroup: resolveGeometryInstancesBindGroup(c, instanceBuffer),
5690
+ instanceBindGroup: resolveGeometryInstancesBindGroup(c, instanceBuffer, probeBinding?.buffer),
5691
+ probeOffset: probeBinding?.offset ?? -1,
6128
5692
  instanceCount
6129
5693
  }
6130
5694
  ];
6131
5695
  }
6132
- function resolveGeometryInstancesBindGroup(c, instanceBuffer) {
5696
+ function resolveProbeBlendBuffer(c, record, entityKey) {
5697
+ const { runtime, frameState } = c;
5698
+ const usage = runtime.device.caps.storageBuffer ? GPU_BUFFER_USAGE_STORAGE | GPU_BUFFER_USAGE_COPY_DST : GPU_BUFFER_USAGE_UNIFORM | GPU_BUFFER_USAGE_COPY_DST;
5699
+ if (record === void 0) throw new Error("probe blend record is required for probe allocation");
5700
+ if (entityKey === void 0) throw new Error("probe blend record requires an entity key");
5701
+ const offset = probeBlendRecordOffset(record.objectKey);
5702
+ const requiredCapacity = record.objectKey + 2;
5703
+ let buffer = frameState.probeBlendRecordBuffer;
5704
+ if (buffer === void 0 || frameState.probeBlendRecordBufferCapacity < requiredCapacity) {
5705
+ const created = runtime.device.createBuffer({
5706
+ label: "probe-blend-records",
5707
+ size: requiredCapacity * PROBE_BLEND_RECORD_STRIDE,
5708
+ usage,
5709
+ mappedAtCreation: false
5710
+ });
5711
+ if (!created.ok) throw created.error;
5712
+ buffer = new GpuBuffer(runtime.device, created.value);
5713
+ frameState.probeBlendRecordBuffer = buffer;
5714
+ frameState.probeBlendRecordBufferCapacity = requiredCapacity;
5715
+ frameState.probeBlendBuffers.clear();
5716
+ }
5717
+ const cached = frameState.probeBlendBuffers.get(entityKey);
5718
+ const unchanged = cached !== void 0 && cached.generation === record.generation && cached.bytes.length === record.bytes.length && cached.bytes.every((value, index) => value === record.bytes[index]);
5719
+ if (!unchanged) {
5720
+ const uploaded = runtime.device.queue.writeBuffer(buffer.handle, offset, record.bytes);
5721
+ if (!uploaded.ok) throw uploaded.error;
5722
+ frameState.probeBlendBuffers.set(entityKey, {
5723
+ generation: record.generation,
5724
+ bytes: new Uint8Array(record.bytes)
5725
+ });
5726
+ }
5727
+ return { buffer: buffer.handle, offset };
5728
+ }
5729
+ function resolveGeometryInstancesBindGroup(c, instanceBuffer, probeBuffer) {
6133
5730
  const { runtime, pipelineState, frameState, bindGroupCounts } = c;
5731
+ const layout = probeBuffer === void 0 ? pipelineState.instancesBindGroupLayout : pipelineState.probeInstancesBindGroupLayout;
5732
+ if (layout === void 0) throw new Error("probe instances bind-group layout is unavailable");
6134
5733
  return getOrCreateFromChain(
6135
5734
  frameState.instancesBgShared,
6136
- [pipelineState.instancesBindGroupLayout, instanceBuffer],
6137
- "instances",
5735
+ probeBuffer === void 0 ? [layout, instanceBuffer] : [layout, instanceBuffer, probeBuffer],
5736
+ probeBuffer === void 0 ? "instances-no-probe" : "instances-probe",
6138
5737
  () => {
6139
5738
  const result = runtime.device.createBindGroup({
6140
5739
  label: "pbr-instances-bg",
6141
- layout: pipelineState.instancesBindGroupLayout,
5740
+ layout,
6142
5741
  entries: [
6143
5742
  {
6144
5743
  binding: 0,
@@ -6146,7 +5745,16 @@ function resolveGeometryInstancesBindGroup(c, instanceBuffer) {
6146
5745
  kind: "buffer",
6147
5746
  value: { buffer: instanceBuffer }
6148
5747
  }
6149
- }
5748
+ },
5749
+ ...probeBuffer === void 0 ? [] : [
5750
+ {
5751
+ binding: 1,
5752
+ resource: {
5753
+ kind: "buffer",
5754
+ value: { buffer: probeBuffer, offset: 0, size: PROBE_BLEND_RECORD_BYTE_SIZE }
5755
+ }
5756
+ }
5757
+ ]
6150
5758
  ]
6151
5759
  });
6152
5760
  if (!result.ok) throw result.error;
@@ -6359,7 +5967,7 @@ function recordSpritePass(c, pass, matchedIndices, materialSlotIndices, sampleCo
6359
5967
  return geometryPassEnded;
6360
5968
  }
6361
5969
  function recordSpriteTransparentPbrDraws(c, spritePass, matchedIndices, materialSlotIndices, sampleCount, resolveMaterialBindGroup, meshGroup2) {
6362
- const { runtime, pipelineState, frameState, bindGroupCounts, validatedOrdered } = c;
5970
+ const { runtime, pipelineState, validatedOrdered } = c;
6363
5971
  const isHdrTarget = c.tonemapActive || transparentPassColorFormat(c, pipelineState) === "rgba16float";
6364
5972
  let lastPbrSubPipelineHandle = null;
6365
5973
  let lastPbrSubVertexBuffer = null;
@@ -6382,45 +5990,6 @@ function recordSpriteTransparentPbrDraws(c, spritePass, matchedIndices, material
6382
5990
  spritePass.setIndexBuffer(entry.mesh.indexBuffer.handle, entry.mesh.indexFormat);
6383
5991
  lastPbrSubIndexBuffer = entry.mesh.indexBuffer;
6384
5992
  }
6385
- const identityInstBg = getOrCreatePerEntity(
6386
- frameState.instancesBgPerEntity,
6387
- worldEntityKey(entry.source.worldId, entry.source.entityKey),
6388
- [pipelineState.identityInstanceBuffer],
6389
- "instances",
6390
- () => {
6391
- const result = runtime.device.createBindGroup({
6392
- label: "pbr-transparent-sub-instances-bg",
6393
- layout: pipelineState.instancesBindGroupLayout,
6394
- entries: [
6395
- {
6396
- binding: 0,
6397
- resource: {
6398
- kind: "buffer",
6399
- value: { buffer: pipelineState.identityInstanceBuffer }
6400
- }
6401
- }
6402
- ]
6403
- });
6404
- if (!result.ok) throw result.error;
6405
- return result.value;
6406
- },
6407
- bindGroupCounts
6408
- );
6409
- spritePass.setBindGroup(3, identityInstBg);
6410
- const subVariantSet = standardTopologyVariantSet(
6411
- c.standardLighting,
6412
- runtime.device.caps.storageBuffer,
6413
- entry.mesh.layoutProjection.attributes.some((attribute) => attribute.key === "color")
6414
- );
6415
- const projectionVariantSetResult = variantSetFromVertexLayoutProjection(
6416
- entry.mesh.layoutProjection,
6417
- subVariantSet
6418
- );
6419
- if (!projectionVariantSetResult.ok) {
6420
- runtime.errorRegistry.fire(projectionVariantSetResult.error);
6421
- continue;
6422
- }
6423
- const projectionVariantSet = projectionVariantSetResult.value;
6424
5993
  for (let smIdx = 0; smIdx < entry.mesh.submeshes.length; smIdx++) {
6425
5994
  const sm = entry.mesh.submeshes[smIdx];
6426
5995
  if (sm === void 0) continue;
@@ -6429,6 +5998,34 @@ function recordSpriteTransparentPbrDraws(c, spritePass, matchedIndices, material
6429
5998
  if (submeshMaterial.transparent !== true) continue;
6430
5999
  const smShaderId = submeshMaterial.materialShaderId;
6431
6000
  if (smShaderId === void 0) continue;
6001
+ const probeBlendAvailable = runtime.device.caps.storageBuffer && entry.source.probeBlendRecord !== void 0 && isStandardPbrMaterialShader(smShaderId);
6002
+ const probeBinding = probeBlendAvailable ? resolveProbeBlendBuffer(
6003
+ c,
6004
+ entry.source.probeBlendRecord,
6005
+ worldEntityKey(entry.source.worldId, entry.source.entityKey)
6006
+ ) : void 0;
6007
+ const identityInstBg = resolveGeometryInstancesBindGroup(
6008
+ c,
6009
+ pipelineState.identityInstanceBuffer,
6010
+ probeBinding?.buffer
6011
+ );
6012
+ if (probeBinding === void 0) spritePass.setBindGroup(3, identityInstBg);
6013
+ else spritePass.setBindGroup(3, identityInstBg, [probeBinding.offset]);
6014
+ const subVariantSet = standardTopologyVariantSet(
6015
+ c.standardLighting,
6016
+ runtime.device.caps.storageBuffer,
6017
+ entry.mesh.layoutProjection.attributes.some((attribute) => attribute.key === "color"),
6018
+ probeBlendAvailable
6019
+ );
6020
+ const projectionVariantSetResult = variantSetFromVertexLayoutProjection(
6021
+ entry.mesh.layoutProjection,
6022
+ subVariantSet
6023
+ );
6024
+ if (!projectionVariantSetResult.ok) {
6025
+ runtime.errorRegistry.fire(projectionVariantSetResult.error);
6026
+ continue;
6027
+ }
6028
+ const projectionVariantSet = projectionVariantSetResult.value;
6432
6029
  const subPipelineEntry = c.runtime.getMaterialShaderPipelineEntry?.(
6433
6030
  smShaderId,
6434
6031
  isHdrTarget,
@@ -6599,21 +6196,12 @@ function recordSpriteEntityDraws(c, spritePass, matchedIndices, skylightResource
6599
6196
  );
6600
6197
  spriteInstanceCount = spriteInst.instanceCount;
6601
6198
  spriteInstanceBuffer = pipelineState.identityInstanceBuffer;
6602
- const spriteInstBgResult = runtime.device.createBindGroup({
6603
- label: "sprite-pass-instances-bg",
6604
- layout: pipelineState.instancesBindGroupLayout,
6605
- entries: [
6606
- {
6607
- binding: 0,
6608
- resource: {
6609
- kind: "buffer",
6610
- value: { buffer: spriteInstanceBuffer }
6611
- }
6612
- }
6613
- ]
6614
- });
6615
- if (!spriteInstBgResult.ok) throw spriteInstBgResult.error;
6616
- spritePass.setBindGroup(3, spriteInstBgResult.value);
6199
+ const spriteInstBg = resolveGeometryInstancesBindGroup(
6200
+ c,
6201
+ spriteInstanceBuffer,
6202
+ void 0
6203
+ );
6204
+ spritePass.setBindGroup(3, spriteInstBg);
6617
6205
  spritePass.drawIndexed(spriteEntry.mesh.indexCount, spriteInstanceCount, 0, 0, 0);
6618
6206
  continue;
6619
6207
  }
@@ -6692,30 +6280,7 @@ function recordSpriteEntityDraws(c, spritePass, matchedIndices, skylightResource
6692
6280
  spriteInstanceBuffer = _si.buffer;
6693
6281
  spriteInstanceCount = _si.count;
6694
6282
  const spriteGroup2 = entityShaderId === "forgeax::sprite-lit" && c.standardLighting?.kind === "clustered" ? c.hdrpClusterBindGroup : meshBindGroup;
6695
- const spriteInstancesBg = getOrCreatePerEntity(
6696
- frameState.instancesBgPerEntity,
6697
- worldEntityKey(spriteEntry.source.worldId, spriteEntry.source.entityKey),
6698
- [spriteInstanceBuffer],
6699
- "instances",
6700
- () => {
6701
- const result = runtime.device.createBindGroup({
6702
- label: "sprite-pass-instances-bg",
6703
- layout: pipelineState.instancesBindGroupLayout,
6704
- entries: [
6705
- {
6706
- binding: 0,
6707
- resource: {
6708
- kind: "buffer",
6709
- value: { buffer: spriteInstanceBuffer }
6710
- }
6711
- }
6712
- ]
6713
- });
6714
- if (!result.ok) throw result.error;
6715
- return result.value;
6716
- },
6717
- bindGroupCounts
6718
- );
6283
+ const spriteInstancesBg = resolveGeometryInstancesBindGroup(c, spriteInstanceBuffer, void 0);
6719
6284
  spritePass.setBindGroup(2, spriteGroup2, [i * MESH_PER_ENTITY_STRIDE]);
6720
6285
  const spriteTexHandle = spriteEntry.source.material.baseColorTexture;
6721
6286
  let spriteTexView = pipelineState.defaultWhiteTextureView;
@@ -6833,26 +6398,6 @@ function transparentPassColorFormat(c, pipelineState = c.pipelineState) {
6833
6398
  if (!c.runtime.device.caps.storageBuffer) return pipelineState.colorAttachmentFormat;
6834
6399
  return pipelineState.format;
6835
6400
  }
6836
-
6837
- // src/systems/pass-selector.ts
6838
- function matchPass(tags, selector) {
6839
- if (Object.keys(selector).length === 0) return true;
6840
- for (const [key, allowedValues] of Object.entries(selector)) {
6841
- const passValue = tags[key];
6842
- if (passValue === void 0) return false;
6843
- if (allowedValues.length === 0) return false;
6844
- if (!allowedValues.includes(passValue)) return false;
6845
- }
6846
- return true;
6847
- }
6848
- function selectPasses(passes, selector) {
6849
- if (Object.keys(selector).length === 0) return passes;
6850
- return passes.filter(
6851
- (p) => matchPass(p.renderState?.tags ?? {}, selector)
6852
- );
6853
- }
6854
-
6855
- // src/record/shadow-pass.ts
6856
6401
  var SHADOW_CASTER_SLOT_STRIDE = 256;
6857
6402
  var SHADOW_CASTER_BUFFER_SIZE = SHADOW_CASTER_SLOT_STRIDE * 8;
6858
6403
  function directionalShadowCasterOffset(cascadeIndex) {
@@ -6884,21 +6429,69 @@ function ensureTypedShadowViewBg(c, viewOffset, cascadeOffset, variant) {
6884
6429
  const { runtime, frameState, pipelineState } = c;
6885
6430
  const shadowSampler = pipelineState.perPassResources.shadowSampler;
6886
6431
  if (shadowSampler === null) return null;
6432
+ const extendedLighting = pipelineState.extendedLightingAvailable ?? false;
6433
+ const iesProfileTextureView = pipelineState.iesProfileTextureView;
6434
+ const cookieTextureView = pipelineState.cookieTextureView;
6435
+ const cookieMatrixBuffer = pipelineState.cookieMatrixBuffer;
6436
+ const ltcLambertTextureView = pipelineState.ltcLambertTextureView;
6437
+ const ltcGgxTextureView = pipelineState.ltcGgxTextureView;
6438
+ const extendedLightingCacheKeys = [];
6439
+ const extendedLightingEntries = [];
6440
+ if (extendedLighting) {
6441
+ if (iesProfileTextureView === void 0 || cookieTextureView === void 0 || cookieMatrixBuffer === void 0 || ltcLambertTextureView === void 0 || ltcGgxTextureView === void 0) {
6442
+ return null;
6443
+ }
6444
+ extendedLightingCacheKeys.push(
6445
+ pipelineState.defaultSampler,
6446
+ iesProfileTextureView,
6447
+ cookieTextureView,
6448
+ ltcLambertTextureView,
6449
+ ltcGgxTextureView,
6450
+ cookieMatrixBuffer
6451
+ );
6452
+ extendedLightingEntries.push(
6453
+ {
6454
+ binding: 9,
6455
+ resource: { kind: "sampler", value: pipelineState.defaultSampler }
6456
+ },
6457
+ {
6458
+ binding: 11,
6459
+ resource: { kind: "textureView", value: iesProfileTextureView }
6460
+ },
6461
+ {
6462
+ binding: 12,
6463
+ resource: { kind: "textureView", value: cookieTextureView }
6464
+ },
6465
+ {
6466
+ binding: 13,
6467
+ resource: { kind: "textureView", value: ltcLambertTextureView }
6468
+ },
6469
+ {
6470
+ binding: 14,
6471
+ resource: { kind: "textureView", value: ltcGgxTextureView }
6472
+ },
6473
+ {
6474
+ binding: 15,
6475
+ resource: {
6476
+ kind: "buffer",
6477
+ value: { buffer: cookieMatrixBuffer, size: COOKIE_MATRIX_BYTES }
6478
+ }
6479
+ }
6480
+ );
6481
+ }
6887
6482
  const projectorAvailable = pipelineState.projectorAvailable !== false;
6888
6483
  try {
6889
6484
  return getOrCreateFromChain(
6890
6485
  frameState.viewBindGroupCache,
6891
6486
  [
6892
6487
  pipelineState.viewUniformBuffer,
6893
- pipelineState.pointLightsBuffer,
6894
- pipelineState.spotLightsBuffer,
6895
6488
  pipelineState.shadowFallbackTextureView,
6896
6489
  shadowSampler,
6897
6490
  pipelineState.shadowAtlasFallbackTextureView,
6898
6491
  pipelineState.shadowParamsBuffer,
6899
6492
  pipelineState.shadowCasterCascadeBuffer,
6900
6493
  pipelineState.shadowFallbackTextureView,
6901
- ...projectorAvailable ? [pipelineState.defaultWhiteTextureView, pipelineState.defaultSampler] : [],
6494
+ ...extendedLighting ? extendedLightingCacheKeys : projectorAvailable ? [pipelineState.defaultWhiteTextureView, pipelineState.defaultSampler] : [],
6902
6495
  pipelineState.pointsLinesViewBuffer ?? pipelineState.viewUniformBuffer
6903
6496
  ],
6904
6497
  variant,
@@ -6918,14 +6511,6 @@ function ensureTypedShadowViewBg(c, viewOffset, cascadeOffset, variant) {
6918
6511
  }
6919
6512
  }
6920
6513
  },
6921
- {
6922
- binding: 1,
6923
- resource: { kind: "buffer", value: { buffer: pipelineState.pointLightsBuffer } }
6924
- },
6925
- {
6926
- binding: 2,
6927
- resource: { kind: "buffer", value: { buffer: pipelineState.spotLightsBuffer } }
6928
- },
6929
6514
  {
6930
6515
  binding: 3,
6931
6516
  resource: { kind: "textureView", value: pipelineState.shadowFallbackTextureView }
@@ -6960,6 +6545,7 @@ function ensureTypedShadowViewBg(c, viewOffset, cascadeOffset, variant) {
6960
6545
  binding: 8,
6961
6546
  resource: { kind: "textureView", value: pipelineState.shadowFallbackTextureView }
6962
6547
  },
6548
+ ...extendedLightingEntries,
6963
6549
  {
6964
6550
  binding: 10,
6965
6551
  resource: {
@@ -6970,7 +6556,7 @@ function ensureTypedShadowViewBg(c, viewOffset, cascadeOffset, variant) {
6970
6556
  }
6971
6557
  }
6972
6558
  },
6973
- ...projectorAvailable ? [
6559
+ ...!extendedLighting && projectorAvailable ? [
6974
6560
  {
6975
6561
  binding: 11,
6976
6562
  resource: {
@@ -7299,30 +6885,7 @@ function recordShadowCasterDraws(c, shadowPass, shadowPipeline2, shadowMeshBindG
7299
6885
  }
7300
6886
  }
7301
6887
  }
7302
- const shadowInstancesBg = getOrCreatePerEntity(
7303
- c.frameState.instancesBgPerEntity,
7304
- worldEntityKey(entry.source.worldId, entry.source.entityKey),
7305
- [shadowInstanceBuffer],
7306
- "shadow-instances",
7307
- () => {
7308
- const result = runtime.device.createBindGroup({
7309
- label: "shadow-instances-bg",
7310
- layout: pipelineState.instancesBindGroupLayout,
7311
- entries: [
7312
- {
7313
- binding: 0,
7314
- resource: {
7315
- kind: "buffer",
7316
- value: { buffer: shadowInstanceBuffer }
7317
- }
7318
- }
7319
- ]
7320
- });
7321
- if (!result.ok) throw result.error;
7322
- return result.value;
7323
- },
7324
- c.bindGroupCounts
7325
- );
6888
+ const shadowInstancesBg = resolveGeometryInstancesBindGroup(c, shadowInstanceBuffer);
7326
6889
  shadowPass.setBindGroup(3, shadowInstancesBg);
7327
6890
  for (const sm of shadowSubmeshes) {
7328
6891
  if (sm.topology !== "triangle-list" && sm.topology !== "triangle-strip") {
@@ -9079,6 +8642,7 @@ function addTypedScenePass(graph, options) {
9079
8642
  stencilLoadOp: options.depthLoadOp ?? "clear",
9080
8643
  stencilStoreOp: "store"
9081
8644
  },
8645
+ occlusionQuerySet: options.occlusion?.querySet,
9082
8646
  encode: ({ pass, frame, resources }) => {
9083
8647
  const colorViews = colorTargets.map((target) => resolvedView(resources, target.view));
9084
8648
  const depthView = resolvedView(resources, options.depth.view);
@@ -9108,13 +8672,16 @@ function addTypedScenePass(graph, options) {
9108
8672
  if (groups.viewBindGroup !== null) {
9109
8673
  options.gpuDriven?.encode(groups.viewBindGroup, pass, resources);
9110
8674
  }
8675
+ const activeOcclusion = options.occlusion;
9111
8676
  encodeMainPass(
9112
8677
  {
9113
8678
  ...internal,
8679
+ ...activeOcclusion === void 0 ? {} : { occlusion: activeOcclusion },
9114
8680
  geometryColorView: colorViews[0] ?? null,
9115
8681
  geometryDepthView: depthView,
9116
8682
  geometryColorResolveView: resolveView,
9117
8683
  transparentColorFormat: colorTargets[0]?.format,
8684
+ ...colorTargets[1]?.format === "rgba16float" ? { reflectionFallbackColorFormat: "rgba16float" } : {},
9118
8685
  msaaActive: colorTargets[0]?.sampleCount === 4,
9119
8686
  viewBindGroup: groups.viewBindGroup,
9120
8687
  meshBindGroup: groups.meshBindGroup,
@@ -9134,6 +8701,10 @@ function addTypedScenePass(graph, options) {
9134
8701
  ...options.transmissionBackdrop === void 0 ? {} : { transmissionBackdropView: transmissionBackdrop }
9135
8702
  }
9136
8703
  );
8704
+ if (activeOcclusion !== void 0) {
8705
+ const proxyResult = activeOcclusion.encodeProxyBounds(pass);
8706
+ if (!proxyResult.ok) throw proxyResult.error;
8707
+ }
9137
8708
  }
9138
8709
  });
9139
8710
  }
@@ -9160,6 +8731,29 @@ function addTypedFrameObservationPass(graph, target, pipelineId) {
9160
8731
  }
9161
8732
  });
9162
8733
  }
8734
+ function addReflectionFallbackObservationPass(graph, target) {
8735
+ return graph.addCopyPass("reflection-fallback-observation", {
8736
+ accesses: [{ resource: target.view, usage: "copy-src" }],
8737
+ encode: ({ frame, resources }) => {
8738
+ const internal = frame;
8739
+ const texture = resources.texture(target.texture);
8740
+ if (!texture.ok) throw texture.error;
8741
+ internal.frameState.reflectionFallbackObservationSource = {
8742
+ texture: texture.value,
8743
+ descriptor: {
8744
+ texture: texture.value,
8745
+ format: target.format,
8746
+ size: { width: frame.targetW, height: frame.targetH },
8747
+ usage: GPU_TEXTURE_USAGE_COPY_SRC | GPU_TEXTURE_USAGE_RENDER_ATTACHMENT | GPU_TEXTURE_USAGE_TEXTURE_BINDING,
8748
+ sample: target.sampleCount
8749
+ },
8750
+ frameId: internal.frameState.frameNumber,
8751
+ pipelineId: "forgeax::standard",
8752
+ backendId: internal.runtime.device.caps.backendKind
8753
+ };
8754
+ }
8755
+ });
8756
+ }
9163
8757
  var TYPED_BLOOM_PASS_NAMES = {
9164
8758
  bright: "bloom-bright",
9165
8759
  blurH: "bloom-blur-h",
@@ -9590,6 +9184,6 @@ function addTaaResolvePass(graph, current, currentTemporal, previousColor, previ
9590
9184
  });
9591
9185
  }
9592
9186
 
9593
- export { CAPTURE_VIEW_PROJS, CUBEMAP_FACE_VERTICES, CUBE_CAPTURE_VIEW_SLOT_BASE, DEFERRED_COLOR_FORMATS, DEPTH_MIN_PARAMS_BYTE_SIZE, FALLBACK_BYTES_PER_ROW, GPU_BUFFER_USAGE_COPY_DST, GPU_BUFFER_USAGE_COPY_SRC, GPU_BUFFER_USAGE_INDEX, GPU_BUFFER_USAGE_INDIRECT, GPU_BUFFER_USAGE_MAP_READ, GPU_BUFFER_USAGE_QUERY_RESOLVE, GPU_BUFFER_USAGE_STORAGE, GPU_BUFFER_USAGE_UNIFORM, GPU_BUFFER_USAGE_VERTEX, GPU_SHADER_STAGE_FRAGMENT, GPU_SHADER_STAGE_VERTEX, GpuBuffer, GpuTexture, LIGHT_ARRAY_HEADER_BYTES, LIGHT_ARRAY_MAX_SLOTS, MATERIAL_PER_ENTITY_STRIDE, POINTS_LINES_MATERIAL_SHADER_ID, POINTS_LINES_VIEW_BUFFER_SIZE, POINT_LIGHT_STD430_BYTES, PREFILTER_MIP_LEVELS, PREFILTER_SIZE, PipelineSpecError, PostProcessError, REFLECTION_PROBE_VIEW_SLOT_BASE, SHADOW_CASTER_BUFFER_SIZE, SKIN_MATERIAL_SHADER_ID, SPOT_LIGHT_STD430_BYTES, TYPED_BLOOM_PASS_NAMES, VIEW_UNIFORM_BUFFER_SIZE, VIEW_UNIFORM_BYTES, VIEW_UNIFORM_SLOT_STRIDE, abortTemporalGpuSubmit, addStandardSceneDataPass, addTaaResolvePass, addTypedBloomPasses, addTypedCompositePostEffects, addTypedFrameObservationPass, addTypedFullscreenPass, addTypedOutputTransformPass, addTypedScenePass, addTypedSkyboxPass, addTypedSsaoPasses, addTypedTemporalResolvePass, aggregateTemporalDemand, applyParamSnapshotToUbo, assembleMaterialWithSkylightEntries, assertStorageBufferCap, buildBindGroupLayoutDescriptor, buildFoldDispatchPlan, buildFullscreenPostProcessPass, buildLinearLdrMaterialSpecTable, buildPbrMaterialUserRegionEntries, buildPbrPipelineLayouts, buildPbrSkinLayouts, buildPerFrameBindGroups, buildSpecConstTable, cacheKeyOf, cleanPerEntityCache, colorFormatsForPassKind, commitTemporalGpuSubmit, computeProjectionMatrix, computeSplitLdrSprite, computeViewMatrix, configureSurface, createClusterBinScratch, createFullscreenBindGroup, createHdrpBindGroupLayoutDescriptor, createHdrpClusterMembershipBindGroupLayoutDescriptor, createHdrpSkinBindGroupLayoutDescriptor, createIblPipelines, createPointsLinesLaneAdapter, createPointsLinesLaneContract, createRenderPipelineTarget, createRenderTargetMaterialSource, createSkylightFallback, createStandardSceneDataTarget, deriveRenderDataCubemap, deriveRenderDataMesh, deriveRenderDataTexture, describeTemporalDemand, driveLazyEquirectProjection, encodeDirectionalShadowPass, encodeMainPass, encodePointShadowPass, encodeSpotShadowPass, ensureMeshSsboCapacity, entryHasDepthRead, evaluateFoldBucketUniformCap, foldDispatchBuckets, geometryRenderStateForTopology, getOrBuildPipeline, getOrCreateHdrpBuffers, getOrCreateIblCache, getTemporalGpuState, hasPendingTemporalGpuSubmit, importRenderPipelineSurface, incrementFoldedDrawsMetric, isStandardPbrMaterialShader, isTemporalFullscreenBinding, postProcessShaderEntrySignature, postProcessShaderModuleLabel, postProcessShaderPipelineLabel, prepareFrameLighting, resetHdrpBuffers, residentTextureView, resolveOutputDither, resolvePipelineGroup2Contract, resolveRenderTargetMaterialSource, resolveSkyboxActive, resolveSsaoParameters, resolveSurfaceFormatPair, resolveSurfaceProfile, retireTemporalGpuState, retireTemporalGpuStateAfterFence, runIblPrecompute, selectLazyEquirectHandle, selectPasses, selectSwapChainFormat, setIblComposedShaders, standardTemporalLaneAdmission, standardTemporalPostOrder, temporalReadIndex, temporalWriteIndex, typedFrameClearColor, uploadMeshSsboBatch, variantSetFromDefines, warnMultiSkybox, warnMultiSkylight, warnZeroLightStandard, writeHdrpClusterAndSsaoBuffers, writePointsLinesViewUbo, writeShadowCasterUniforms, writeShadowParamsBuffer, writeViewUbo };
9594
- //# sourceMappingURL=chunk-5YADUCA7.mjs.map
9595
- //# sourceMappingURL=chunk-5YADUCA7.mjs.map
9187
+ export { BYTES_PER_DIRECT_LIGHT_SLOT, CAPTURE_VIEW_PROJS, CUBEMAP_FACE_VERTICES, CUBE_CAPTURE_VIEW_SLOT_BASE, DEFERRED_COLOR_FORMATS, DEPTH_MIN_PARAMS_BYTE_SIZE, FALLBACK_BYTES_PER_ROW, GpuBuffer, GpuTexture, MATERIAL_PER_ENTITY_STRIDE, MESH_SSBO_BYTES, POINTS_LINES_MATERIAL_SHADER_ID, POINTS_LINES_VIEW_BUFFER_SIZE, PREFILTER_MIP_LEVELS, PREFILTER_SIZE, PipelineSpecError, PostProcessError, REFLECTION_PROBE_VIEW_SLOT_BASE, SHADOW_CASTER_BUFFER_SIZE, TYPED_BLOOM_PASS_NAMES, VIEW_UNIFORM_BUFFER_SIZE, VIEW_UNIFORM_BYTES, VIEW_UNIFORM_SLOT_STRIDE, abortTemporalGpuSubmit, addReflectionFallbackObservationPass, addStandardSceneDataPass, addTaaResolvePass, addTypedBloomPasses, addTypedCompositePostEffects, addTypedFrameObservationPass, addTypedFullscreenPass, addTypedOutputTransformPass, addTypedScenePass, addTypedSkyboxPass, addTypedSsaoPasses, addTypedTemporalResolvePass, aggregateTemporalDemand, applyParamSnapshotToUbo, assembleMaterialWithSkylightEntries, assertStorageBufferCap, buildFoldDispatchPlan, buildFullscreenPostProcessPass, buildLinearLdrMaterialSpecTable, buildPerFrameBindGroups, buildSpecConstTable, cacheKeyOf, cleanPerEntityCache, colorFormatsForPassKind, commitTemporalGpuSubmit, computeProjectionMatrix, computeSplitLdrSprite, computeViewMatrix, configureSurface, createClusterBinScratch, createFullscreenBindGroup, createHdrpClusterMembershipBindGroupLayoutDescriptor, createIblPipelines, createPointsLinesLaneAdapter, createPointsLinesLaneContract, createRenderPipelineTarget, createSkylightFallback, createStandardSceneDataTarget, deriveRenderDataCubemap, deriveRenderDataMesh, deriveRenderDataTexture, describeTemporalDemand, driveLazyEquirectProjection, encodeDirectionalShadowPass, encodeMainPass, encodePointShadowPass, encodeSpotShadowPass, ensureMeshSsboCapacity, entryHasDepthRead, evaluateFoldBucketUniformCap, foldDispatchBuckets, geometryRenderStateForTopology, getOrBuildPipeline, getOrCreateHdrpBuffers, getOrCreateIblCache, getTemporalGpuState, hasPendingTemporalGpuSubmit, importRenderPipelineSurface, incrementFoldedDrawsMetric, isTemporalFullscreenBinding, postProcessShaderEntrySignature, postProcessShaderModuleLabel, postProcessShaderPipelineLabel, prepareFrameLighting, resetHdrpBuffers, residentTextureView, resolveOutputDither, resolveSkyboxActive, resolveSsaoParameters, resolveSurfaceFormatPair, resolveSurfaceProfile, retireTemporalGpuState, retireTemporalGpuStateAfterFence, runIblPrecompute, selectLazyEquirectHandle, selectSwapChainFormat, setIblComposedShaders, standardTemporalLaneAdmission, standardTemporalPostOrder, temporalReadIndex, temporalWriteIndex, typedFrameClearColor, uploadMeshSsboBatch, variantSetFromDefines, warnMultiSkybox, warnMultiSkylight, warnZeroLightStandard, writeHdrpClusterAndSsaoBuffers, writePointsLinesViewUbo, writeShadowCasterUniforms, writeShadowParamsBuffer, writeSpotModifierTextures, writeViewUbo };
9188
+ //# sourceMappingURL=chunk-ZUWKAZ2I.mjs.map
9189
+ //# sourceMappingURL=chunk-ZUWKAZ2I.mjs.map