@forgeax/engine-render 0.1.4 → 0.1.7

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 (979) hide show
  1. package/README.md +268 -640
  2. package/dist/.tsbuildinfo +1 -1
  3. package/dist/__tests__/device-scope-lifecycle.unit.test.d.ts +2 -0
  4. package/dist/__tests__/device-scope-lifecycle.unit.test.d.ts.map +1 -0
  5. package/dist/__tests__/device-scope-stale-matrix.unit.test.d.ts +2 -0
  6. package/dist/__tests__/device-scope-stale-matrix.unit.test.d.ts.map +1 -0
  7. package/dist/__tests__/fullscreen-feature-plan.unit.test.d.ts +2 -0
  8. package/dist/__tests__/fullscreen-feature-plan.unit.test.d.ts.map +1 -0
  9. package/dist/__tests__/gpu-driven-indirect-raster-evidence.d.ts.map +1 -1
  10. package/dist/__tests__/gpu-driven-view-gpu-evidence.d.ts +6 -0
  11. package/dist/__tests__/gpu-driven-view-gpu-evidence.d.ts.map +1 -1
  12. package/dist/{gpu-driven/view-reference.d.ts → __tests__/gpu-driven-view-reference.d.ts} +4 -4
  13. package/dist/__tests__/gpu-driven-view-reference.d.ts.map +1 -0
  14. package/dist/__tests__/gpu-scene-render-graph-gpu.d.ts.map +1 -1
  15. package/dist/__tests__/ibl/face-uniforms.unit.test.d.ts +2 -0
  16. package/dist/__tests__/ibl/face-uniforms.unit.test.d.ts.map +1 -0
  17. package/dist/__tests__/morph-feature-plan.unit.test.d.ts +2 -0
  18. package/dist/__tests__/morph-feature-plan.unit.test.d.ts.map +1 -0
  19. package/dist/__tests__/render-feature-plan.test-d.d.ts +2 -0
  20. package/dist/__tests__/render-feature-plan.test-d.d.ts.map +1 -0
  21. package/dist/__tests__/render-feature-plan.unit.test.d.ts +2 -0
  22. package/dist/__tests__/render-feature-plan.unit.test.d.ts.map +1 -0
  23. package/dist/__tests__/ssao-config.unit.test.d.ts +2 -0
  24. package/dist/__tests__/ssao-config.unit.test.d.ts.map +1 -0
  25. package/dist/__tests__/standard-clustered-pipeline.unit.test.d.ts +2 -0
  26. package/dist/__tests__/standard-clustered-pipeline.unit.test.d.ts.map +1 -0
  27. package/dist/__tests__/standard-descriptors.test-d.d.ts +2 -0
  28. package/dist/__tests__/standard-descriptors.test-d.d.ts.map +1 -0
  29. package/dist/__tests__/standard-pipeline.dawn.test.d.ts +2 -0
  30. package/dist/__tests__/standard-pipeline.dawn.test.d.ts.map +1 -0
  31. package/dist/__tests__/standard-pipeline.integration.test.d.ts +2 -0
  32. package/dist/__tests__/standard-pipeline.integration.test.d.ts.map +1 -0
  33. package/dist/__tests__/standard-profile-oracle.unit.test.d.ts +2 -0
  34. package/dist/__tests__/standard-profile-oracle.unit.test.d.ts.map +1 -0
  35. package/dist/__tests__/visibility-resource-short-circuit.unit.test.d.ts +2 -0
  36. package/dist/__tests__/visibility-resource-short-circuit.unit.test.d.ts.map +1 -0
  37. package/dist/{renderer/backend-selection.d.ts → assembly/backend-contract.d.ts} +15 -4
  38. package/dist/assembly/backend-contract.d.ts.map +1 -0
  39. package/dist/assembly/factory.d.ts +214 -0
  40. package/dist/assembly/factory.d.ts.map +1 -0
  41. package/dist/assembly/host-contract.d.ts +84 -0
  42. package/dist/assembly/host-contract.d.ts.map +1 -0
  43. package/dist/{renderer → assembly}/material/assembly.d.ts +0 -1
  44. package/dist/{renderer → assembly}/material/assembly.d.ts.map +1 -1
  45. package/dist/assembly/material/pipeline-projection.d.ts +30 -0
  46. package/dist/assembly/material/pipeline-projection.d.ts.map +1 -0
  47. package/dist/authoring.d.ts +11 -11
  48. package/dist/authoring.d.ts.map +1 -1
  49. package/dist/authoring.mjs +25 -3
  50. package/dist/authoring.mjs.map +1 -1
  51. package/dist/chunk-CQXZC5XI.mjs +182 -0
  52. package/dist/chunk-CQXZC5XI.mjs.map +1 -0
  53. package/dist/chunk-HCOGPHKS.mjs +93 -0
  54. package/dist/chunk-HCOGPHKS.mjs.map +1 -0
  55. package/dist/chunk-YEJIUW7D.mjs +1152 -0
  56. package/dist/chunk-YEJIUW7D.mjs.map +1 -0
  57. package/dist/components/__tests__/points-lines-admission.unit.test.d.ts +2 -0
  58. package/dist/components/__tests__/points-lines-admission.unit.test.d.ts.map +1 -0
  59. package/dist/components/__tests__/points-lines-schema.unit.test.d.ts +2 -0
  60. package/dist/components/__tests__/points-lines-schema.unit.test.d.ts.map +1 -0
  61. package/dist/components/__tests__/schema-contract.unit.test.d.ts +2 -0
  62. package/dist/components/__tests__/schema-contract.unit.test.d.ts.map +1 -0
  63. package/dist/components/glyph-text.d.ts +1 -1
  64. package/dist/components/glyph-text.d.ts.map +1 -1
  65. package/dist/components/index.d.ts +4 -2
  66. package/dist/components/index.d.ts.map +1 -1
  67. package/dist/components/instances.d.ts +1 -1
  68. package/dist/components/instances.d.ts.map +1 -1
  69. package/dist/components/light-helpers.d.ts +1 -1
  70. package/dist/components/light-helpers.d.ts.map +1 -1
  71. package/dist/components/lines.d.ts +5 -0
  72. package/dist/components/lines.d.ts.map +1 -0
  73. package/dist/components/mesh-filter.d.ts +7 -7
  74. package/dist/components/mesh-filter.d.ts.map +1 -1
  75. package/dist/components/points.d.ts +15 -0
  76. package/dist/components/points.d.ts.map +1 -0
  77. package/dist/components/scene-instance.d.ts +11 -11
  78. package/dist/components/skybox-background.d.ts +56 -0
  79. package/dist/components/skybox-background.d.ts.map +1 -0
  80. package/dist/components/skylight.d.ts +55 -0
  81. package/dist/components/skylight.d.ts.map +1 -0
  82. package/dist/components/sprite-animation.d.ts +2 -3
  83. package/dist/components/sprite-animation.d.ts.map +1 -1
  84. package/dist/components/sprite-instances.d.ts +1 -1
  85. package/dist/components/sprite-playback-mode.d.ts +6 -1
  86. package/dist/components/sprite-playback-mode.d.ts.map +1 -1
  87. package/dist/components/sprite-region-override.d.ts +2 -3
  88. package/dist/components/sprite-region-override.d.ts.map +1 -1
  89. package/dist/components/tile-layer.d.ts +5 -0
  90. package/dist/components/tile-layer.d.ts.map +1 -1
  91. package/dist/construct-renderer.d.ts +18 -1
  92. package/dist/construct-renderer.d.ts.map +1 -1
  93. package/dist/construct-renderer.mjs +27463 -4
  94. package/dist/construct-renderer.mjs.map +1 -1
  95. package/dist/debug-draw-glue.d.ts +2 -53
  96. package/dist/debug-draw-glue.d.ts.map +1 -1
  97. package/dist/device/device-scope.d.ts +83 -0
  98. package/dist/device/device-scope.d.ts.map +1 -0
  99. package/dist/{gpu-resource-store.d.ts → device/gpu-residency.d.ts} +91 -48
  100. package/dist/device/gpu-residency.d.ts.map +1 -0
  101. package/dist/device/resource-types.d.ts +8 -0
  102. package/dist/device/resource-types.d.ts.map +1 -0
  103. package/dist/engine-metrics.d.ts +2 -2
  104. package/dist/engine-metrics.d.ts.map +1 -1
  105. package/dist/errors/recover.d.ts +28 -1
  106. package/dist/errors/recover.d.ts.map +1 -1
  107. package/dist/errors/render.d.ts +320 -248
  108. package/dist/errors/render.d.ts.map +1 -1
  109. package/dist/features/fullscreen.d.ts +19 -0
  110. package/dist/features/fullscreen.d.ts.map +1 -0
  111. package/dist/features/host.d.ts +32 -26
  112. package/dist/features/host.d.ts.map +1 -1
  113. package/dist/features/morph/morph-feature.d.ts +39 -5
  114. package/dist/features/morph/morph-feature.d.ts.map +1 -1
  115. package/dist/features/plan.d.ts +182 -0
  116. package/dist/features/plan.d.ts.map +1 -0
  117. package/dist/features/prepared-gpu-work.d.ts +21 -17
  118. package/dist/features/prepared-gpu-work.d.ts.map +1 -1
  119. package/dist/features/prepared-graphics-store.d.ts +2 -1
  120. package/dist/features/prepared-graphics-store.d.ts.map +1 -1
  121. package/dist/features/prepared-graphics.d.ts +11 -21
  122. package/dist/features/prepared-graphics.d.ts.map +1 -1
  123. package/dist/features/render-graph-compute.d.ts +2 -2
  124. package/dist/features/render-graph-compute.d.ts.map +1 -1
  125. package/dist/features/render-graph-contribution.d.ts +4 -7
  126. package/dist/features/render-graph-contribution.d.ts.map +1 -1
  127. package/dist/features/render-graph-raster.d.ts +7 -3
  128. package/dist/features/render-graph-raster.d.ts.map +1 -1
  129. package/dist/features/render-graph-resources.d.ts +6 -6
  130. package/dist/features/render-graph-resources.d.ts.map +1 -1
  131. package/dist/features/targets.d.ts +5 -5
  132. package/dist/features/targets.d.ts.map +1 -1
  133. package/dist/features/types.d.ts +11 -190
  134. package/dist/features/types.d.ts.map +1 -1
  135. package/dist/features/vocabulary.d.ts +14 -0
  136. package/dist/features/vocabulary.d.ts.map +1 -0
  137. package/dist/fullscreen-post-process-pass.d.ts +4 -25
  138. package/dist/fullscreen-post-process-pass.d.ts.map +1 -1
  139. package/dist/glyph-text-layout-system.d.ts +3 -2
  140. package/dist/glyph-text-layout-system.d.ts.map +1 -1
  141. package/dist/gpu-driven/batch-topology.d.ts +6 -75
  142. package/dist/gpu-driven/batch-topology.d.ts.map +1 -1
  143. package/dist/gpu-driven/production-raster.d.ts +13 -112
  144. package/dist/gpu-driven/production-raster.d.ts.map +1 -1
  145. package/dist/gpu-driven/view-gpu.d.ts +10 -66
  146. package/dist/gpu-driven/view-gpu.d.ts.map +1 -1
  147. package/dist/gpu-resource.d.ts +3 -3
  148. package/dist/gpu-scene-schema.d.ts +1 -94
  149. package/dist/gpu-scene-schema.d.ts.map +1 -1
  150. package/dist/gpu-scene.d.ts +7 -33
  151. package/dist/gpu-scene.d.ts.map +1 -1
  152. package/dist/hdrp-buffers.d.ts +3 -53
  153. package/dist/hdrp-buffers.d.ts.map +1 -1
  154. package/dist/ibl/IblPipelineCache.d.ts +74 -180
  155. package/dist/ibl/IblPipelineCache.d.ts.map +1 -1
  156. package/dist/ibl/skylight-bind-group.d.ts +1 -1
  157. package/dist/index.d.ts +17 -43
  158. package/dist/index.d.ts.map +1 -1
  159. package/dist/index.mjs +167 -3
  160. package/dist/index.mjs.map +1 -1
  161. package/dist/inspection-types.d.ts +72 -0
  162. package/dist/inspection-types.d.ts.map +1 -0
  163. package/dist/instance-buffer-cache.d.ts +1 -4
  164. package/dist/instance-buffer-cache.d.ts.map +1 -1
  165. package/dist/internal.d.ts +1 -73
  166. package/dist/internal.d.ts.map +1 -1
  167. package/dist/internal.mjs +1 -43
  168. package/dist/internal.mjs.map +1 -1
  169. package/dist/lifecycle.d.ts +36 -2
  170. package/dist/lifecycle.d.ts.map +1 -1
  171. package/dist/materials.d.ts +0 -3
  172. package/dist/materials.d.ts.map +1 -1
  173. package/dist/mesh-material-bindings.d.ts +0 -1
  174. package/dist/mesh-material-bindings.d.ts.map +1 -1
  175. package/dist/pbr-pipeline.d.ts +77 -29
  176. package/dist/pbr-pipeline.d.ts.map +1 -1
  177. package/dist/pipeline/standard-forward-lane.d.ts +5 -0
  178. package/dist/pipeline/standard-forward-lane.d.ts.map +1 -0
  179. package/dist/pipeline/standard-pipeline.d.ts +31 -0
  180. package/dist/pipeline/standard-pipeline.d.ts.map +1 -0
  181. package/dist/pipeline/standard-profile.d.ts +40 -0
  182. package/dist/pipeline/standard-profile.d.ts.map +1 -0
  183. package/dist/pipeline-builder.d.ts +3 -3
  184. package/dist/pipeline-builder.d.ts.map +1 -1
  185. package/dist/pipeline-spec-types.d.ts +24 -0
  186. package/dist/pipeline-spec-types.d.ts.map +1 -0
  187. package/dist/pipeline-spec.d.ts +16 -155
  188. package/dist/pipeline-spec.d.ts.map +1 -1
  189. package/dist/plugin.d.ts +1 -14
  190. package/dist/plugin.d.ts.map +1 -1
  191. package/dist/points-lines/__tests__/bounds.unit.test.d.ts +2 -0
  192. package/dist/points-lines/__tests__/bounds.unit.test.d.ts.map +1 -0
  193. package/dist/points-lines/__tests__/cache-recovery.unit.test.d.ts +2 -0
  194. package/dist/points-lines/__tests__/cache-recovery.unit.test.d.ts.map +1 -0
  195. package/dist/points-lines/__tests__/inspection-lanes.integration.test.d.ts +2 -0
  196. package/dist/points-lines/__tests__/inspection-lanes.integration.test.d.ts.map +1 -0
  197. package/dist/points-lines/__tests__/inspection.unit.test.d.ts +2 -0
  198. package/dist/points-lines/__tests__/inspection.unit.test.d.ts.map +1 -0
  199. package/dist/points-lines/__tests__/lane-structural.integration.test.d.ts +2 -0
  200. package/dist/points-lines/__tests__/lane-structural.integration.test.d.ts.map +1 -0
  201. package/dist/points-lines/__tests__/points-lines.bench.d.ts +2 -0
  202. package/dist/points-lines/__tests__/points-lines.bench.d.ts.map +1 -0
  203. package/dist/points-lines/__tests__/raster-lane.integration.test.d.ts +2 -0
  204. package/dist/points-lines/__tests__/raster-lane.integration.test.d.ts.map +1 -0
  205. package/dist/points-lines/__tests__/snapshot.unit.test.d.ts +2 -0
  206. package/dist/points-lines/__tests__/snapshot.unit.test.d.ts.map +1 -0
  207. package/dist/points-lines/__tests__/view-ubo.unit.test.d.ts +2 -0
  208. package/dist/points-lines/__tests__/view-ubo.unit.test.d.ts.map +1 -0
  209. package/dist/points-lines/admission.d.ts +36 -0
  210. package/dist/points-lines/admission.d.ts.map +1 -0
  211. package/dist/points-lines/bounds.d.ts +8 -0
  212. package/dist/points-lines/bounds.d.ts.map +1 -0
  213. package/dist/points-lines/expansion-cache.d.ts +28 -0
  214. package/dist/points-lines/expansion-cache.d.ts.map +1 -0
  215. package/dist/points-lines/inspection.d.ts +53 -0
  216. package/dist/points-lines/inspection.d.ts.map +1 -0
  217. package/dist/points-lines/prepare.d.ts +67 -0
  218. package/dist/points-lines/prepare.d.ts.map +1 -0
  219. package/dist/points-lines/record.d.ts +60 -0
  220. package/dist/points-lines/record.d.ts.map +1 -0
  221. package/dist/points-lines/snapshot.d.ts +49 -0
  222. package/dist/points-lines/snapshot.d.ts.map +1 -0
  223. package/dist/post-process-errors.d.ts +18 -18
  224. package/dist/post-process-errors.d.ts.map +1 -1
  225. package/dist/prepare/prepared-graphics-resolver.d.ts +2 -5
  226. package/dist/prepare/prepared-graphics-resolver.d.ts.map +1 -1
  227. package/dist/record/__tests__/typed-frame-graph-plan.unit.test.d.ts +2 -0
  228. package/dist/record/__tests__/typed-frame-graph-plan.unit.test.d.ts.map +1 -0
  229. package/dist/record/frame-lighting.d.ts +7 -73
  230. package/dist/record/frame-lighting.d.ts.map +1 -1
  231. package/dist/record/frame-snapshot.d.ts +44 -44
  232. package/dist/record/frame-snapshot.d.ts.map +1 -1
  233. package/dist/record/frame-targets.d.ts +5 -38
  234. package/dist/record/frame-targets.d.ts.map +1 -1
  235. package/dist/record/frame.d.ts +64 -52
  236. package/dist/record/frame.d.ts.map +1 -1
  237. package/dist/record/helpers.d.ts +3 -2
  238. package/dist/record/helpers.d.ts.map +1 -1
  239. package/dist/record/main-pass-geometry.d.ts +12 -4
  240. package/dist/record/main-pass-geometry.d.ts.map +1 -1
  241. package/dist/record/main-pass-material.d.ts +90 -59
  242. package/dist/record/main-pass-material.d.ts.map +1 -1
  243. package/dist/record/main-pass-sprite-draws.d.ts +28 -3
  244. package/dist/record/main-pass-sprite-draws.d.ts.map +1 -1
  245. package/dist/record/main-pass.d.ts +1 -1
  246. package/dist/record/main-pass.d.ts.map +1 -1
  247. package/dist/record/mesh-ssbo.d.ts +276 -3
  248. package/dist/record/mesh-ssbo.d.ts.map +1 -1
  249. package/dist/record/render-context.d.ts +252 -0
  250. package/dist/record/render-context.d.ts.map +1 -0
  251. package/dist/record/shadow-pass.d.ts +15 -88
  252. package/dist/record/shadow-pass.d.ts.map +1 -1
  253. package/dist/record/skybox-post-pass.d.ts +1 -1
  254. package/dist/record/skybox-post-pass.d.ts.map +1 -1
  255. package/dist/record/typed-frame-graph.d.ts +29 -7
  256. package/dist/record/typed-frame-graph.d.ts.map +1 -1
  257. package/dist/record/view-ubo.d.ts +9 -3
  258. package/dist/record/view-ubo.d.ts.map +1 -1
  259. package/dist/render-contract.d.ts +424 -0
  260. package/dist/render-contract.d.ts.map +1 -0
  261. package/dist/render-data.d.ts.map +1 -1
  262. package/dist/render-graph-primitives.d.ts +14 -362
  263. package/dist/render-graph-primitives.d.ts.map +1 -1
  264. package/dist/render-pipeline.d.ts +25 -64
  265. package/dist/render-pipeline.d.ts.map +1 -1
  266. package/dist/render-system-extract.d.ts +110 -338
  267. package/dist/render-system-extract.d.ts.map +1 -1
  268. package/dist/render-system.d.ts +24 -713
  269. package/dist/render-system.d.ts.map +1 -1
  270. package/dist/scene/render-scene-types.d.ts +61 -0
  271. package/dist/scene/render-scene-types.d.ts.map +1 -0
  272. package/dist/scene/render-scene.d.ts +112 -0
  273. package/dist/scene/render-scene.d.ts.map +1 -0
  274. package/dist/scene-instances/post-spawn-resolve-joints.d.ts +2 -5
  275. package/dist/scene-instances/post-spawn-resolve-joints.d.ts.map +1 -1
  276. package/dist/ssao-buffers.d.ts +22 -3
  277. package/dist/ssao-buffers.d.ts.map +1 -1
  278. package/dist/systems/skin-palette-allocator.d.ts +2 -4
  279. package/dist/systems/skin-palette-allocator.d.ts.map +1 -1
  280. package/dist/systems/skin-palette-types.d.ts +14 -0
  281. package/dist/systems/skin-palette-types.d.ts.map +1 -0
  282. package/dist/systems/transparent-sort-config.d.ts +23 -2
  283. package/dist/systems/transparent-sort-config.d.ts.map +1 -1
  284. package/dist/tilemap-chunk-extract-system.d.ts +4 -3
  285. package/dist/tilemap-chunk-extract-system.d.ts.map +1 -1
  286. package/dist/typed-render-graph-primitives.d.ts +2 -4
  287. package/dist/typed-render-graph-primitives.d.ts.map +1 -1
  288. package/dist/typed-shadow-passes.d.ts +3 -3
  289. package/dist/typed-shadow-passes.d.ts.map +1 -1
  290. package/package.json +23 -23
  291. package/src/__tests__/authoring-path.unit.test.ts +9 -0
  292. package/src/__tests__/backend-selection-rhi-capture.test-d.ts +1 -1
  293. package/src/__tests__/callback-inference.test-d.ts +6 -3
  294. package/src/__tests__/cluster-grid-default-surface.unit.test.ts +7 -4
  295. package/src/__tests__/construct-renderer-identity.unit.test.ts +15 -2
  296. package/src/__tests__/device-scope-lifecycle.unit.test.ts +151 -0
  297. package/src/__tests__/device-scope-stale-matrix.unit.test.ts +42 -0
  298. package/src/__tests__/direct-extract-consumer-contract.test-d.ts +8 -19
  299. package/src/__tests__/direct-light-snapshot.unit.test.ts +3 -13
  300. package/src/__tests__/factory-contract.integration.test.ts +158 -209
  301. package/src/__tests__/fallback-row-stride-surface.unit.test.ts +1 -4
  302. package/src/__tests__/frame-observation.contract.test.ts +17 -8
  303. package/src/__tests__/fullscreen-feature-plan.unit.test.ts +32 -0
  304. package/src/__tests__/glyph-text-layout-recovery.unit.test.ts +6 -11
  305. package/src/__tests__/gpu-driven-indirect-raster-evidence.ts +21 -18
  306. package/src/__tests__/gpu-driven-production.integration.test.ts +32 -205
  307. package/src/__tests__/gpu-driven-scaling.unit.test.ts +4 -7
  308. package/src/__tests__/gpu-driven-view-gpu-evidence.ts +87 -8
  309. package/src/__tests__/gpu-driven-view-graph.integration.test.ts +170 -8
  310. package/src/{gpu-driven/view-reference.ts → __tests__/gpu-driven-view-reference.ts} +4 -3
  311. package/src/__tests__/gpu-driven-view.browser.test.ts +12 -1
  312. package/src/__tests__/gpu-driven-view.dawn.test.ts +12 -1
  313. package/src/__tests__/gpu-driven-view.unit.test.ts +11 -267
  314. package/src/__tests__/gpu-resource-store-stride.unit.test.ts +3 -3
  315. package/src/__tests__/gpu-scene-render-graph-gpu.ts +2 -3
  316. package/src/__tests__/gpu-scene.dawn.test.ts +2 -6
  317. package/src/__tests__/gpu-scene.unit.test.ts +10 -24
  318. package/src/__tests__/ibl/face-uniforms.unit.test.ts +46 -0
  319. package/src/__tests__/infinite-grid-no-vertex-probe.unit.test.ts +34 -66
  320. package/src/__tests__/ktx2-basis-gpu-consumer.dawn.test.ts +14 -5
  321. package/src/__tests__/light-buffer-layout.unit.test.ts +4 -49
  322. package/src/__tests__/material-cooked-projection.unit.test.ts +31 -58
  323. package/src/__tests__/material-snapshot-mutation.integration.test.ts +10 -15
  324. package/src/__tests__/material-static-dynamic-route.unit.test.ts +31 -50
  325. package/src/__tests__/material-stride-surface.unit.test.ts +2 -2
  326. package/src/__tests__/mesh-buffer-usage-surface.unit.test.ts +7 -8
  327. package/src/__tests__/morph-culling-reentry.dawn.test.ts +29 -38
  328. package/src/__tests__/morph-feature-gpu-work.integration.test.ts +45 -43
  329. package/src/__tests__/morph-feature-plan.unit.test.ts +53 -0
  330. package/src/__tests__/morph-visual-evidence.integration.test.ts +47 -33
  331. package/src/__tests__/nineslice-handle-surface.unit.test.ts +11 -6
  332. package/src/__tests__/post-process-error-policy-owner.unit.test.ts +6 -13
  333. package/src/__tests__/prepared-graphics-capability.unit.test.ts +6 -81
  334. package/src/__tests__/prepared-graphics-generation.unit.test.ts +3 -17
  335. package/src/__tests__/prepared-graphics-lifecycle.unit.test.ts +6 -74
  336. package/src/__tests__/prepared-graphics-resolver.unit.test.ts +1 -3
  337. package/src/__tests__/prepared-graphics-snapshot.unit.test.ts +2 -2
  338. package/src/__tests__/profiler-default-off.test.ts +1 -1
  339. package/src/__tests__/profiler-phase-catalog.test.ts +2 -2
  340. package/src/__tests__/profiler-phase-integration.test.ts +5 -13
  341. package/src/__tests__/profiler-phase-token.test.ts +3 -8
  342. package/src/__tests__/public-surface.test-d.ts +65 -3
  343. package/src/__tests__/recover-error-policy-owner.unit.test.ts +1 -21
  344. package/src/__tests__/render-error-code-owner.test-d.ts +24 -23
  345. package/src/__tests__/render-error-detail-ssot.test-d.ts +0 -95
  346. package/src/__tests__/render-error-exhaustive.test-d.ts +27 -1
  347. package/src/__tests__/render-feature-assembly.test-d.ts +8 -16
  348. package/src/__tests__/render-feature-context.test-d.ts +16 -40
  349. package/src/__tests__/render-feature-contract.test-d.ts +9 -18
  350. package/src/__tests__/render-feature-diagnostics.unit.test.ts +6 -8
  351. package/src/__tests__/render-feature-docs.unit.test.ts +8 -7
  352. package/src/__tests__/render-feature-gpu-work.integration.test.ts +14 -75
  353. package/src/__tests__/render-feature-plan.test-d.ts +161 -0
  354. package/src/__tests__/render-feature-plan.unit.test.ts +170 -0
  355. package/src/__tests__/render-feature-prepared-diagnostics.unit.test.ts +8 -19
  356. package/src/__tests__/render-feature-prepared-errors.test-d.ts +3 -6
  357. package/src/__tests__/render-feature-prepared-graphics-docs.unit.test.ts +10 -71
  358. package/src/__tests__/render-feature-prepared-graphics-isolation.unit.test.ts +11 -61
  359. package/src/__tests__/render-feature-prepared-graphics-negative.test-d.ts +20 -43
  360. package/src/__tests__/render-feature-prepared-graphics.test-d.ts +56 -78
  361. package/src/__tests__/render-feature-public-surface.test-d.ts +6 -24
  362. package/src/__tests__/render-feature-retry.unit.test.ts +7 -48
  363. package/src/__tests__/render-feature-scheduling.unit.test.ts +15 -27
  364. package/src/__tests__/render-feature-stage-failed-policy-owner.unit.test.ts +0 -9
  365. package/src/__tests__/render-feature-stage-fault-recovery.unit.test.ts +19 -109
  366. package/src/__tests__/render-feature-visibility-context.test-d.ts +1 -6
  367. package/src/__tests__/render-feature-visibility-context.unit.test.ts +1 -2
  368. package/src/__tests__/render-feature-zero-work.unit.test.ts +14 -20
  369. package/src/__tests__/render-scene-projection.unit.test.ts +73 -111
  370. package/src/__tests__/renderer-factory-material-contract.unit.test.ts +82 -95
  371. package/src/__tests__/renderer-lifecycle.integration.test.ts +49 -1
  372. package/src/__tests__/shader-stage-surface.unit.test.ts +14 -9
  373. package/src/__tests__/ssao-config.unit.test.ts +36 -0
  374. package/src/__tests__/ssao-kernel-surface.unit.test.ts +4 -5
  375. package/src/__tests__/standard-clustered-pipeline.unit.test.ts +28 -0
  376. package/src/__tests__/standard-descriptors.test-d.ts +22 -0
  377. package/src/__tests__/standard-pipeline.dawn.test.ts +61 -0
  378. package/src/__tests__/standard-pipeline.integration.test.ts +124 -0
  379. package/src/__tests__/standard-profile-oracle.unit.test.ts +62 -0
  380. package/src/__tests__/surface-configuration.unit.test.ts +1 -2
  381. package/src/__tests__/texture-usage-surface.unit.test.ts +3 -6
  382. package/src/__tests__/typed-pipeline-topology.unit.test.ts +40 -206
  383. package/src/__tests__/urp-pipeline-targets.unit.test.ts +1 -11
  384. package/src/__tests__/urp-pipeline.unit.test.ts +2 -2
  385. package/src/__tests__/vertex-color-pipeline.unit.test.ts +10 -2
  386. package/src/__tests__/vertex-layout-consumer.unit.test.ts +1 -1
  387. package/src/__tests__/visibility-diagnostics.integration.test.ts +7 -11
  388. package/src/__tests__/visibility-extract.integration.test.ts +20 -11
  389. package/src/__tests__/visibility-extract.perf.test.ts +66 -32
  390. package/src/__tests__/visibility-feature-dedup.integration.test.ts +2 -4
  391. package/src/__tests__/visibility-hidden-report.unit.test.ts +1 -2
  392. package/src/__tests__/visibility-instances.integration.test.ts +7 -11
  393. package/src/__tests__/visibility-multi-world.integration.test.ts +38 -6
  394. package/src/__tests__/visibility-producer-matrix.integration.test.ts +18 -41
  395. package/src/__tests__/visibility-public-surface.test-d.ts +10 -9
  396. package/src/__tests__/visibility-resolver.unit.test.ts +2 -1
  397. package/src/__tests__/visibility-resource-short-circuit.unit.test.ts +80 -0
  398. package/src/__tests__/visibility-snapshot-contract.unit.test.ts +2 -1
  399. package/src/__tests__/vocabulary.unit.test.ts +1 -1
  400. package/src/assembly/backend-contract.ts +57 -0
  401. package/src/{renderer/renderer-factory.ts → assembly/factory.ts} +1741 -2699
  402. package/src/assembly/host-contract.ts +101 -0
  403. package/src/{renderer → assembly}/material/assembly.ts +2 -7
  404. package/src/assembly/material/pipeline-projection.ts +63 -0
  405. package/src/authoring.ts +15 -22
  406. package/src/components/__tests__/points-lines-admission.unit.test.ts +219 -0
  407. package/src/components/__tests__/points-lines-schema.unit.test.ts +56 -0
  408. package/src/components/__tests__/schema-contract.unit.test.ts +10 -0
  409. package/src/components/glyph-text.ts +3 -2
  410. package/src/components/index.ts +14 -9
  411. package/src/components/instances.ts +4 -5
  412. package/src/components/light-helpers.ts +1 -1
  413. package/src/components/lines.ts +18 -0
  414. package/src/components/mesh-filter.ts +11 -10
  415. package/src/components/points.ts +40 -0
  416. package/src/components/post-process-params.ts +3 -3
  417. package/src/components/scene-instance.ts +12 -12
  418. package/src/components/skybox-background.ts +103 -0
  419. package/src/components/{environment.ts → skylight.ts} +2 -110
  420. package/src/components/sprite-animation.ts +3 -4
  421. package/src/components/sprite-instances.ts +2 -2
  422. package/src/components/sprite-playback-mode.ts +7 -1
  423. package/src/components/sprite-region-override.ts +2 -3
  424. package/src/components/tile-layer.ts +8 -2
  425. package/src/construct-renderer.ts +67 -4
  426. package/src/debug-draw-glue.ts +8 -129
  427. package/src/device/device-scope.ts +306 -0
  428. package/src/{gpu-resource-store.ts → device/gpu-residency.ts} +540 -639
  429. package/src/device/resource-types.ts +20 -0
  430. package/src/engine-metrics.ts +12 -19
  431. package/src/errors/recover.ts +45 -3
  432. package/src/errors/render.ts +469 -429
  433. package/src/features/fullscreen.ts +46 -0
  434. package/src/features/host.ts +575 -309
  435. package/src/features/morph/morph-feature.ts +195 -105
  436. package/src/features/plan.ts +447 -0
  437. package/src/features/prepared-gpu-work.ts +72 -15
  438. package/src/features/prepared-graphics-store.ts +20 -6
  439. package/src/features/prepared-graphics.ts +12 -71
  440. package/src/features/render-graph-compute.ts +14 -5
  441. package/src/features/render-graph-contribution.ts +43 -63
  442. package/src/features/render-graph-raster.ts +32 -8
  443. package/src/features/render-graph-resources.ts +25 -23
  444. package/src/features/targets.ts +8 -21
  445. package/src/features/types.ts +39 -227
  446. package/src/features/vocabulary.ts +24 -0
  447. package/src/fullscreen-post-process-pass.ts +14 -57
  448. package/src/glyph-text-layout-system.ts +70 -96
  449. package/src/gpu-driven/batch-topology.ts +24 -202
  450. package/src/gpu-driven/production-raster.ts +99 -1109
  451. package/src/gpu-driven/view-gpu.ts +46 -192
  452. package/src/gpu-resource.ts +4 -4
  453. package/src/gpu-scene-schema.ts +11 -99
  454. package/src/gpu-scene.ts +231 -364
  455. package/src/hdrp-buffers.ts +12 -221
  456. package/src/ibl/IblPipelineCache.ts +471 -711
  457. package/src/ibl/skylight-bind-group.ts +4 -4
  458. package/src/index.ts +75 -217
  459. package/src/inspection-types.ts +80 -0
  460. package/src/instance-buffer-cache.ts +1 -29
  461. package/src/internal.ts +6 -85
  462. package/src/lifecycle.ts +64 -19
  463. package/src/materials.ts +7 -29
  464. package/src/mesh-material-bindings.ts +0 -1
  465. package/src/pbr-pipeline.ts +441 -53
  466. package/src/{urp-pipeline.ts → pipeline/standard-forward-lane.ts} +38 -149
  467. package/src/{hdrp-pipeline.ts → pipeline/standard-pipeline.ts} +221 -191
  468. package/src/pipeline/standard-profile.ts +65 -0
  469. package/src/pipeline-builder.ts +60 -64
  470. package/src/pipeline-spec-types.ts +28 -0
  471. package/src/pipeline-spec.ts +72 -609
  472. package/src/plugin.ts +7 -75
  473. package/src/points-lines/__tests__/bounds.unit.test.ts +21 -0
  474. package/src/points-lines/__tests__/cache-recovery.unit.test.ts +157 -0
  475. package/src/points-lines/__tests__/inspection-lanes.integration.test.ts +146 -0
  476. package/src/points-lines/__tests__/inspection.unit.test.ts +173 -0
  477. package/src/points-lines/__tests__/lane-structural.integration.test.ts +122 -0
  478. package/src/points-lines/__tests__/points-lines.bench.ts +400 -0
  479. package/src/points-lines/__tests__/raster-lane.integration.test.ts +44 -0
  480. package/src/points-lines/__tests__/snapshot.unit.test.ts +101 -0
  481. package/src/points-lines/__tests__/view-ubo.unit.test.ts +73 -0
  482. package/src/points-lines/admission.ts +238 -0
  483. package/src/points-lines/bounds.ts +23 -0
  484. package/src/points-lines/expansion-cache.ts +215 -0
  485. package/src/points-lines/inspection.ts +97 -0
  486. package/src/points-lines/prepare.ts +177 -0
  487. package/src/points-lines/record.ts +125 -0
  488. package/src/points-lines/snapshot.ts +130 -0
  489. package/src/post-process-errors.ts +31 -33
  490. package/src/prepare/prepared-graphics-resolver.ts +5 -4
  491. package/src/record/__tests__/material-slot-plan.unit.test.ts +1 -33
  492. package/src/record/__tests__/typed-frame-graph-plan.unit.test.ts +41 -0
  493. package/src/record/__tests__/video-texture-view.unit.test.ts +1 -1
  494. package/src/record/frame-lighting.ts +88 -197
  495. package/src/record/frame-snapshot.ts +45 -60
  496. package/src/record/frame-targets.ts +8 -243
  497. package/src/record/frame.ts +521 -797
  498. package/src/record/helpers.ts +6 -11
  499. package/src/record/main-pass-geometry.ts +198 -147
  500. package/src/record/main-pass-material.ts +517 -190
  501. package/src/record/main-pass-sprite-draws.ts +199 -118
  502. package/src/record/main-pass.ts +166 -144
  503. package/src/record/mesh-ssbo.ts +517 -38
  504. package/src/record/render-context.ts +384 -0
  505. package/src/record/shadow-pass.ts +154 -1843
  506. package/src/record/skybox-post-pass.ts +14 -15
  507. package/src/record/typed-frame-graph.ts +224 -262
  508. package/src/record/view-ubo.ts +53 -37
  509. package/src/render-contract.ts +582 -0
  510. package/src/render-data.ts +3 -3
  511. package/src/render-graph-primitives.ts +76 -851
  512. package/src/render-pipeline.ts +104 -188
  513. package/src/render-system-extract.ts +1114 -1732
  514. package/src/render-system.ts +614 -1939
  515. package/src/scene/render-scene-types.ts +67 -0
  516. package/src/scene/render-scene.ts +1087 -0
  517. package/src/scene-instances/post-spawn-resolve-joints.ts +4 -7
  518. package/src/ssao-buffers.ts +167 -8
  519. package/src/systems/skin-palette-allocator.ts +21 -64
  520. package/src/systems/skin-palette-types.ts +14 -0
  521. package/src/systems/transparent-sort-config.ts +25 -3
  522. package/src/tilemap-chunk-extract-system.ts +53 -70
  523. package/src/typed-render-graph-primitives.ts +35 -24
  524. package/src/typed-shadow-passes.ts +26 -56
  525. package/dist/__tests__/analytic-sky-contract.test.d.ts +0 -2
  526. package/dist/__tests__/analytic-sky-contract.test.d.ts.map +0 -1
  527. package/dist/__tests__/analytic-sky-falsify.test.d.ts +0 -2
  528. package/dist/__tests__/analytic-sky-falsify.test.d.ts.map +0 -1
  529. package/dist/__tests__/assets-runtime-handoff.integration.test.d.ts +0 -2
  530. package/dist/__tests__/assets-runtime-handoff.integration.test.d.ts.map +0 -1
  531. package/dist/__tests__/backend-selection.integration.test.d.ts +0 -2
  532. package/dist/__tests__/backend-selection.integration.test.d.ts.map +0 -1
  533. package/dist/__tests__/camera-temporal.test-d.d.ts +0 -2
  534. package/dist/__tests__/camera-temporal.test-d.d.ts.map +0 -1
  535. package/dist/__tests__/camera-temporal.test.d.ts +0 -2
  536. package/dist/__tests__/camera-temporal.test.d.ts.map +0 -1
  537. package/dist/__tests__/directional-shadow-probe-atlas-layout.unit.test.d.ts +0 -2
  538. package/dist/__tests__/directional-shadow-probe-atlas-layout.unit.test.d.ts.map +0 -1
  539. package/dist/__tests__/environment-inspection.test.d.ts +0 -2
  540. package/dist/__tests__/environment-inspection.test.d.ts.map +0 -1
  541. package/dist/__tests__/fog-ai-user.fixture.d.ts +0 -2
  542. package/dist/__tests__/fog-ai-user.fixture.d.ts.map +0 -1
  543. package/dist/__tests__/fog-custom-render-feature.fixture.d.ts +0 -16
  544. package/dist/__tests__/fog-custom-render-feature.fixture.d.ts.map +0 -1
  545. package/dist/__tests__/fog-custom-render-feature.integration.test.d.ts +0 -2
  546. package/dist/__tests__/fog-custom-render-feature.integration.test.d.ts.map +0 -1
  547. package/dist/__tests__/fog-inspection.integration.test.d.ts +0 -2
  548. package/dist/__tests__/fog-inspection.integration.test.d.ts.map +0 -1
  549. package/dist/__tests__/fog-owner-state.integration.test.d.ts +0 -2
  550. package/dist/__tests__/fog-owner-state.integration.test.d.ts.map +0 -1
  551. package/dist/__tests__/fog-pipeline-topology.integration.test.d.ts +0 -2
  552. package/dist/__tests__/fog-pipeline-topology.integration.test.d.ts.map +0 -1
  553. package/dist/__tests__/fog-public-surface.integration.test.d.ts +0 -2
  554. package/dist/__tests__/fog-public-surface.integration.test.d.ts.map +0 -1
  555. package/dist/__tests__/fog-ray-contract.integration.test.d.ts +0 -2
  556. package/dist/__tests__/fog-ray-contract.integration.test.d.ts.map +0 -1
  557. package/dist/__tests__/fog-source-absence.integration.test.d.ts +0 -2
  558. package/dist/__tests__/fog-source-absence.integration.test.d.ts.map +0 -1
  559. package/dist/__tests__/fog-temporal.integration.test.d.ts +0 -2
  560. package/dist/__tests__/fog-temporal.integration.test.d.ts.map +0 -1
  561. package/dist/__tests__/frame-chain.unit.test.d.ts +0 -2
  562. package/dist/__tests__/frame-chain.unit.test.d.ts.map +0 -1
  563. package/dist/__tests__/gpu-scene-field-type-owner.test-d.d.ts +0 -2
  564. package/dist/__tests__/gpu-scene-field-type-owner.test-d.d.ts.map +0 -1
  565. package/dist/__tests__/hdrp-pipeline.unit.test.d.ts +0 -2
  566. package/dist/__tests__/hdrp-pipeline.unit.test.d.ts.map +0 -1
  567. package/dist/__tests__/ibl/ibl-fallback.unit.test.d.ts +0 -2
  568. package/dist/__tests__/ibl/ibl-fallback.unit.test.d.ts.map +0 -1
  569. package/dist/__tests__/material-derived-error-stop-draw.integration.test.d.ts +0 -2
  570. package/dist/__tests__/material-derived-error-stop-draw.integration.test.d.ts.map +0 -1
  571. package/dist/__tests__/material-derived-payload.integration.test.d.ts +0 -2
  572. package/dist/__tests__/material-derived-payload.integration.test.d.ts.map +0 -1
  573. package/dist/__tests__/materials.unit.test.d.ts +0 -2
  574. package/dist/__tests__/materials.unit.test.d.ts.map +0 -1
  575. package/dist/__tests__/param-schema-projection-census.unit.test.d.ts +0 -2
  576. package/dist/__tests__/param-schema-projection-census.unit.test.d.ts.map +0 -1
  577. package/dist/__tests__/persistent-render-scene.unit.test.d.ts +0 -2
  578. package/dist/__tests__/persistent-render-scene.unit.test.d.ts.map +0 -1
  579. package/dist/__tests__/pipeline-error-policy-owner.unit.test.d.ts +0 -2
  580. package/dist/__tests__/pipeline-error-policy-owner.unit.test.d.ts.map +0 -1
  581. package/dist/__tests__/pipeline-pass-trace.test.d.ts +0 -2
  582. package/dist/__tests__/pipeline-pass-trace.test.d.ts.map +0 -1
  583. package/dist/__tests__/pipeline-stage-owner.test-d.d.ts +0 -2
  584. package/dist/__tests__/pipeline-stage-owner.test-d.d.ts.map +0 -1
  585. package/dist/__tests__/plugin.test.d.ts +0 -2
  586. package/dist/__tests__/plugin.test.d.ts.map +0 -1
  587. package/dist/__tests__/prepared-graphics-backend-matrix.unit.test.d.ts +0 -2
  588. package/dist/__tests__/prepared-graphics-backend-matrix.unit.test.d.ts.map +0 -1
  589. package/dist/__tests__/prepared-graphics-resolver-recording.unit.test.d.ts +0 -2
  590. package/dist/__tests__/prepared-graphics-resolver-recording.unit.test.d.ts.map +0 -1
  591. package/dist/__tests__/public-pipeline-id.test-d.d.ts +0 -2
  592. package/dist/__tests__/public-pipeline-id.test-d.d.ts.map +0 -1
  593. package/dist/__tests__/render-dispatch-membership.unit.test.d.ts +0 -2
  594. package/dist/__tests__/render-dispatch-membership.unit.test.d.ts.map +0 -1
  595. package/dist/__tests__/render-feature-construction.unit.test.d.ts +0 -2
  596. package/dist/__tests__/render-feature-construction.unit.test.d.ts.map +0 -1
  597. package/dist/__tests__/render-feature-error-code-owner.test-d.d.ts +0 -2
  598. package/dist/__tests__/render-feature-error-code-owner.test-d.d.ts.map +0 -1
  599. package/dist/__tests__/render-feature-gpu-buffer-usage-owner.test-d.d.ts +0 -2
  600. package/dist/__tests__/render-feature-gpu-buffer-usage-owner.test-d.d.ts.map +0 -1
  601. package/dist/__tests__/render-feature-graph.integration.test.d.ts +0 -2
  602. package/dist/__tests__/render-feature-graph.integration.test.d.ts.map +0 -1
  603. package/dist/__tests__/render-feature-graphics-staging.unit.test.d.ts +0 -2
  604. package/dist/__tests__/render-feature-graphics-staging.unit.test.d.ts.map +0 -1
  605. package/dist/__tests__/render-feature-order.unit.test.d.ts +0 -2
  606. package/dist/__tests__/render-feature-order.unit.test.d.ts.map +0 -1
  607. package/dist/__tests__/render-feature-prepared-graphics-recording.unit.test.d.ts +0 -2
  608. package/dist/__tests__/render-feature-prepared-graphics-recording.unit.test.d.ts.map +0 -1
  609. package/dist/__tests__/render-feature-staging.unit.test.d.ts +0 -2
  610. package/dist/__tests__/render-feature-staging.unit.test.d.ts.map +0 -1
  611. package/dist/__tests__/renderer-render-scene-public.test-d.d.ts +0 -2
  612. package/dist/__tests__/renderer-render-scene-public.test-d.d.ts.map +0 -1
  613. package/dist/__tests__/scene-temporal-coverage.unit.test.d.ts +0 -2
  614. package/dist/__tests__/scene-temporal-coverage.unit.test.d.ts.map +0 -1
  615. package/dist/__tests__/sun-snapshot-consumers.test.d.ts +0 -2
  616. package/dist/__tests__/sun-snapshot-consumers.test.d.ts.map +0 -1
  617. package/dist/__tests__/surface-backend-kind-owner.test-d.d.ts +0 -2
  618. package/dist/__tests__/surface-backend-kind-owner.test-d.d.ts.map +0 -1
  619. package/dist/__tests__/taa-history-store.unit.test.d.ts +0 -2
  620. package/dist/__tests__/taa-history-store.unit.test.d.ts.map +0 -1
  621. package/dist/__tests__/temporal-frame-transaction.integration.test.d.ts +0 -2
  622. package/dist/__tests__/temporal-frame-transaction.integration.test.d.ts.map +0 -1
  623. package/dist/__tests__/temporal-inspection.unit.test.d.ts +0 -2
  624. package/dist/__tests__/temporal-inspection.unit.test.d.ts.map +0 -1
  625. package/dist/assets/__tests__/asset-decoders.unit.test.d.ts +0 -2
  626. package/dist/assets/__tests__/asset-decoders.unit.test.d.ts.map +0 -1
  627. package/dist/assets/__tests__/mipmap-generator.unit.test.d.ts +0 -2
  628. package/dist/assets/__tests__/mipmap-generator.unit.test.d.ts.map +0 -1
  629. package/dist/assets/__tests__/render-asset-port.unit.test.d.ts +0 -2
  630. package/dist/assets/__tests__/render-asset-port.unit.test.d.ts.map +0 -1
  631. package/dist/assets/__tests__/resolve-render-asset.unit.test.d.ts +0 -2
  632. package/dist/assets/__tests__/resolve-render-asset.unit.test.d.ts.map +0 -1
  633. package/dist/chunk-DJIMFYX6.mjs +0 -1439
  634. package/dist/chunk-DJIMFYX6.mjs.map +0 -1
  635. package/dist/chunk-F2SIOCRM.mjs +0 -7423
  636. package/dist/chunk-F2SIOCRM.mjs.map +0 -1
  637. package/dist/chunk-JMSB7AR4.mjs +0 -3
  638. package/dist/chunk-JMSB7AR4.mjs.map +0 -1
  639. package/dist/chunk-KHI6K4C6.mjs +0 -659
  640. package/dist/chunk-KHI6K4C6.mjs.map +0 -1
  641. package/dist/chunk-PORZOL2V.mjs +0 -569
  642. package/dist/chunk-PORZOL2V.mjs.map +0 -1
  643. package/dist/chunk-UOJGMDGP.mjs +0 -29913
  644. package/dist/chunk-UOJGMDGP.mjs.map +0 -1
  645. package/dist/components/__tests__/atmosphere-red.test.d.ts +0 -2
  646. package/dist/components/__tests__/atmosphere-red.test.d.ts.map +0 -1
  647. package/dist/components/__tests__/atmosphere.test.d.ts +0 -2
  648. package/dist/components/__tests__/atmosphere.test.d.ts.map +0 -1
  649. package/dist/components/__tests__/fog.test-d.d.ts +0 -2
  650. package/dist/components/__tests__/fog.test-d.d.ts.map +0 -1
  651. package/dist/components/__tests__/fog.test.d.ts +0 -2
  652. package/dist/components/__tests__/fog.test.d.ts.map +0 -1
  653. package/dist/components/atmosphere.d.ts +0 -18
  654. package/dist/components/atmosphere.d.ts.map +0 -1
  655. package/dist/components/environment.d.ts +0 -115
  656. package/dist/components/environment.d.ts.map +0 -1
  657. package/dist/deferred-lighting.d.ts +0 -13
  658. package/dist/deferred-lighting.d.ts.map +0 -1
  659. package/dist/dynamic-texture-store.d.ts +0 -42
  660. package/dist/dynamic-texture-store.d.ts.map +0 -1
  661. package/dist/environment/__tests__/failure-injection.test.d.ts +0 -2
  662. package/dist/environment/__tests__/failure-injection.test.d.ts.map +0 -1
  663. package/dist/environment/__tests__/generation-red.test.d.ts +0 -2
  664. package/dist/environment/__tests__/generation-red.test.d.ts.map +0 -1
  665. package/dist/environment/__tests__/generation.test.d.ts +0 -2
  666. package/dist/environment/__tests__/generation.test.d.ts.map +0 -1
  667. package/dist/environment/__tests__/graph-transaction.test.d.ts +0 -2
  668. package/dist/environment/__tests__/graph-transaction.test.d.ts.map +0 -1
  669. package/dist/environment/__tests__/inspection-red.test.d.ts +0 -2
  670. package/dist/environment/__tests__/inspection-red.test.d.ts.map +0 -1
  671. package/dist/environment/__tests__/lifecycle-evidence.test.d.ts +0 -2
  672. package/dist/environment/__tests__/lifecycle-evidence.test.d.ts.map +0 -1
  673. package/dist/environment/__tests__/pipeline-topology.test.d.ts +0 -2
  674. package/dist/environment/__tests__/pipeline-topology.test.d.ts.map +0 -1
  675. package/dist/environment/__tests__/readiness.test.d.ts +0 -2
  676. package/dist/environment/__tests__/readiness.test.d.ts.map +0 -1
  677. package/dist/environment/__tests__/recovery.test.d.ts +0 -2
  678. package/dist/environment/__tests__/recovery.test.d.ts.map +0 -1
  679. package/dist/environment/__tests__/resize-dispose.test.d.ts +0 -2
  680. package/dist/environment/__tests__/resize-dispose.test.d.ts.map +0 -1
  681. package/dist/environment/__tests__/signature-red.test.d.ts +0 -2
  682. package/dist/environment/__tests__/signature-red.test.d.ts.map +0 -1
  683. package/dist/environment/__tests__/signature.test.d.ts +0 -2
  684. package/dist/environment/__tests__/signature.test.d.ts.map +0 -1
  685. package/dist/environment/descriptors.d.ts +0 -2
  686. package/dist/environment/descriptors.d.ts.map +0 -1
  687. package/dist/environment/extracted-environment.d.ts +0 -53
  688. package/dist/environment/extracted-environment.d.ts.map +0 -1
  689. package/dist/environment/generation.d.ts +0 -62
  690. package/dist/environment/generation.d.ts.map +0 -1
  691. package/dist/environment/gpu-bundle.d.ts +0 -23
  692. package/dist/environment/gpu-bundle.d.ts.map +0 -1
  693. package/dist/environment/graph.d.ts +0 -108
  694. package/dist/environment/graph.d.ts.map +0 -1
  695. package/dist/environment/inspection.d.ts +0 -48
  696. package/dist/environment/inspection.d.ts.map +0 -1
  697. package/dist/environment/lifecycle.d.ts +0 -22
  698. package/dist/environment/lifecycle.d.ts.map +0 -1
  699. package/dist/environment/readiness.d.ts +0 -29
  700. package/dist/environment/readiness.d.ts.map +0 -1
  701. package/dist/environment/signature.d.ts +0 -70
  702. package/dist/environment/signature.d.ts.map +0 -1
  703. package/dist/extract/__tests__/directional-csm-domain.unit.test.d.ts +0 -2
  704. package/dist/extract/__tests__/directional-csm-domain.unit.test.d.ts.map +0 -1
  705. package/dist/extract/__tests__/environment-source.test.d.ts +0 -2
  706. package/dist/extract/__tests__/environment-source.test.d.ts.map +0 -1
  707. package/dist/extract/__tests__/schema-readers.unit.test.d.ts +0 -2
  708. package/dist/extract/__tests__/schema-readers.unit.test.d.ts.map +0 -1
  709. package/dist/extract/directional-csm.d.ts +0 -129
  710. package/dist/extract/directional-csm.d.ts.map +0 -1
  711. package/dist/extract/index.d.ts +0 -5
  712. package/dist/extract/index.d.ts.map +0 -1
  713. package/dist/extract/material-interface.d.ts +0 -56
  714. package/dist/extract/material-interface.d.ts.map +0 -1
  715. package/dist/extract/schema-readers.d.ts +0 -20
  716. package/dist/extract/schema-readers.d.ts.map +0 -1
  717. package/dist/features/graph-contribution.d.ts +0 -64
  718. package/dist/features/graph-contribution.d.ts.map +0 -1
  719. package/dist/features/index.d.ts +0 -21
  720. package/dist/features/index.d.ts.map +0 -1
  721. package/dist/features/morph/index.d.ts +0 -3
  722. package/dist/features/morph/index.d.ts.map +0 -1
  723. package/dist/features/morph/morph-bounds.d.ts +0 -42
  724. package/dist/features/morph/morph-bounds.d.ts.map +0 -1
  725. package/dist/features/scene-temporal.d.ts +0 -45
  726. package/dist/features/scene-temporal.d.ts.map +0 -1
  727. package/dist/features/taa-resolve.d.ts +0 -21
  728. package/dist/features/taa-resolve.d.ts.map +0 -1
  729. package/dist/frame-chain.d.ts +0 -14
  730. package/dist/frame-chain.d.ts.map +0 -1
  731. package/dist/gpu-driven/view-reference.d.ts.map +0 -1
  732. package/dist/gpu-resource-store.d.ts.map +0 -1
  733. package/dist/hdrp-cluster-membership.d.ts +0 -2
  734. package/dist/hdrp-cluster-membership.d.ts.map +0 -1
  735. package/dist/hdrp-pipeline.d.ts +0 -36
  736. package/dist/hdrp-pipeline.d.ts.map +0 -1
  737. package/dist/ibl/cubemap-projection.d.ts +0 -23
  738. package/dist/ibl/cubemap-projection.d.ts.map +0 -1
  739. package/dist/ibl/face-uniforms.d.ts +0 -65
  740. package/dist/ibl/face-uniforms.d.ts.map +0 -1
  741. package/dist/mesh-update-errors.d.ts +0 -71
  742. package/dist/mesh-update-errors.d.ts.map +0 -1
  743. package/dist/mipmap-generator.d.ts +0 -39
  744. package/dist/mipmap-generator.d.ts.map +0 -1
  745. package/dist/param-schema-projection-census.d.ts +0 -18
  746. package/dist/param-schema-projection-census.d.ts.map +0 -1
  747. package/dist/persistent-render-scene.d.ts +0 -158
  748. package/dist/persistent-render-scene.d.ts.map +0 -1
  749. package/dist/pipeline/index.d.ts +0 -11
  750. package/dist/pipeline/index.d.ts.map +0 -1
  751. package/dist/pipeline-errors.d.ts +0 -110
  752. package/dist/pipeline-errors.d.ts.map +0 -1
  753. package/dist/prepare/__tests__/schema-readers.unit.test.d.ts +0 -2
  754. package/dist/prepare/__tests__/schema-readers.unit.test.d.ts.map +0 -1
  755. package/dist/prepare/index.d.ts +0 -4
  756. package/dist/prepare/index.d.ts.map +0 -1
  757. package/dist/prepare/schema-readers.d.ts +0 -11
  758. package/dist/prepare/schema-readers.d.ts.map +0 -1
  759. package/dist/record/__tests__/environment-record.test.d.ts +0 -2
  760. package/dist/record/__tests__/environment-record.test.d.ts.map +0 -1
  761. package/dist/record/__tests__/frame-targets.unit.test.d.ts +0 -2
  762. package/dist/record/__tests__/frame-targets.unit.test.d.ts.map +0 -1
  763. package/dist/record/__tests__/membership-timing.unit.test.d.ts +0 -2
  764. package/dist/record/__tests__/membership-timing.unit.test.d.ts.map +0 -1
  765. package/dist/record/__tests__/render-submission.integration.test.d.ts +0 -2
  766. package/dist/record/__tests__/render-submission.integration.test.d.ts.map +0 -1
  767. package/dist/record/__tests__/render-submission.perf.test.d.ts +0 -2
  768. package/dist/record/__tests__/render-submission.perf.test.d.ts.map +0 -1
  769. package/dist/record/__tests__/shadow-submit-mode.unit.test.d.ts +0 -2
  770. package/dist/record/__tests__/shadow-submit-mode.unit.test.d.ts.map +0 -1
  771. package/dist/record/__tests__/view-ubo-layout.unit.test.d.ts +0 -2
  772. package/dist/record/__tests__/view-ubo-layout.unit.test.d.ts.map +0 -1
  773. package/dist/record/frame-observation.d.ts +0 -38
  774. package/dist/record/frame-observation.d.ts.map +0 -1
  775. package/dist/record/index.d.ts +0 -15
  776. package/dist/record/index.d.ts.map +0 -1
  777. package/dist/record/main-pass-skin.d.ts +0 -46
  778. package/dist/record/main-pass-skin.d.ts.map +0 -1
  779. package/dist/record/main-pass-sprite.d.ts +0 -69
  780. package/dist/record/main-pass-sprite.d.ts.map +0 -1
  781. package/dist/record/material-payload.d.ts +0 -43
  782. package/dist/record/material-payload.d.ts.map +0 -1
  783. package/dist/record/material-slot-plan.d.ts +0 -26
  784. package/dist/record/material-slot-plan.d.ts.map +0 -1
  785. package/dist/record/membership-timing.d.ts +0 -232
  786. package/dist/record/membership-timing.d.ts.map +0 -1
  787. package/dist/record/shadow-caster-uniform.d.ts +0 -8
  788. package/dist/record/shadow-caster-uniform.d.ts.map +0 -1
  789. package/dist/record/shadow-submit-mode.d.ts +0 -66
  790. package/dist/record/shadow-submit-mode.d.ts.map +0 -1
  791. package/dist/render-dispatch-membership.d.ts +0 -47
  792. package/dist/render-dispatch-membership.d.ts.map +0 -1
  793. package/dist/render-pipeline-context.d.ts +0 -289
  794. package/dist/render-pipeline-context.d.ts.map +0 -1
  795. package/dist/render-pipeline-target.d.ts +0 -16
  796. package/dist/render-pipeline-target.d.ts.map +0 -1
  797. package/dist/render-scene-projection.d.ts +0 -174
  798. package/dist/render-scene-projection.d.ts.map +0 -1
  799. package/dist/render-system-fold.d.ts +0 -266
  800. package/dist/render-system-fold.d.ts.map +0 -1
  801. package/dist/renderer/asset-service.d.ts +0 -10
  802. package/dist/renderer/asset-service.d.ts.map +0 -1
  803. package/dist/renderer/backend-selection.d.ts.map +0 -1
  804. package/dist/renderer/environment-classify.d.ts +0 -6
  805. package/dist/renderer/environment-classify.d.ts.map +0 -1
  806. package/dist/renderer/environment-error.d.ts +0 -13
  807. package/dist/renderer/environment-error.d.ts.map +0 -1
  808. package/dist/renderer/material/pipeline-projection.d.ts +0 -91
  809. package/dist/renderer/material/pipeline-projection.d.ts.map +0 -1
  810. package/dist/renderer/renderer-factory.d.ts +0 -289
  811. package/dist/renderer/renderer-factory.d.ts.map +0 -1
  812. package/dist/renderer.d.ts +0 -771
  813. package/dist/renderer.d.ts.map +0 -1
  814. package/dist/scene-utils/collect-subtree.d.ts +0 -11
  815. package/dist/scene-utils/collect-subtree.d.ts.map +0 -1
  816. package/dist/ssao-data.d.ts +0 -34
  817. package/dist/ssao-data.d.ts.map +0 -1
  818. package/dist/surface-format.d.ts +0 -10
  819. package/dist/surface-format.d.ts.map +0 -1
  820. package/dist/taa-history-store.d.ts +0 -88
  821. package/dist/taa-history-store.d.ts.map +0 -1
  822. package/dist/temporal-coverage.d.ts +0 -35
  823. package/dist/temporal-coverage.d.ts.map +0 -1
  824. package/dist/temporal-frame-transaction.d.ts +0 -92
  825. package/dist/temporal-frame-transaction.d.ts.map +0 -1
  826. package/dist/temporal-inspection.d.ts +0 -57
  827. package/dist/temporal-inspection.d.ts.map +0 -1
  828. package/dist/temporal-view.d.ts +0 -43
  829. package/dist/temporal-view.d.ts.map +0 -1
  830. package/dist/tilemap/resolve-tileset-runtime.d.ts +0 -23
  831. package/dist/tilemap/resolve-tileset-runtime.d.ts.map +0 -1
  832. package/dist/urp-pipeline.d.ts +0 -4
  833. package/dist/urp-pipeline.d.ts.map +0 -1
  834. package/src/__tests__/analytic-sky-contract.test.ts +0 -27
  835. package/src/__tests__/analytic-sky-falsify-carriers.mjs +0 -43
  836. package/src/__tests__/analytic-sky-falsify.test.ts +0 -94
  837. package/src/__tests__/assets-runtime-handoff.integration.test.ts +0 -36
  838. package/src/__tests__/backend-selection.integration.test.ts +0 -11
  839. package/src/__tests__/camera-temporal.test-d.ts +0 -8
  840. package/src/__tests__/camera-temporal.test.ts +0 -188
  841. package/src/__tests__/directional-shadow-probe-atlas-layout.unit.test.ts +0 -18
  842. package/src/__tests__/environment-inspection.test.ts +0 -45
  843. package/src/__tests__/fog-ai-user.fixture.ts +0 -350
  844. package/src/__tests__/fog-custom-render-feature.fixture.ts +0 -33
  845. package/src/__tests__/fog-custom-render-feature.integration.test.ts +0 -76
  846. package/src/__tests__/fog-inspection.integration.test.ts +0 -127
  847. package/src/__tests__/fog-owner-state.integration.test.ts +0 -112
  848. package/src/__tests__/fog-pipeline-topology.integration.test.ts +0 -93
  849. package/src/__tests__/fog-public-surface.integration.test.ts +0 -60
  850. package/src/__tests__/fog-ray-contract.integration.test.ts +0 -73
  851. package/src/__tests__/fog-source-absence.integration.test.ts +0 -51
  852. package/src/__tests__/fog-temporal.integration.test.ts +0 -115
  853. package/src/__tests__/frame-chain.unit.test.ts +0 -26
  854. package/src/__tests__/gpu-scene-field-type-owner.test-d.ts +0 -27
  855. package/src/__tests__/hdrp-pipeline.unit.test.ts +0 -100
  856. package/src/__tests__/ibl/ibl-fallback.unit.test.ts +0 -23
  857. package/src/__tests__/material-derived-error-stop-draw.integration.test.ts +0 -69
  858. package/src/__tests__/material-derived-payload.integration.test.ts +0 -164
  859. package/src/__tests__/materials.unit.test.ts +0 -25
  860. package/src/__tests__/param-schema-projection-census.unit.test.ts +0 -40
  861. package/src/__tests__/persistent-render-scene.unit.test.ts +0 -1311
  862. package/src/__tests__/pipeline-error-policy-owner.unit.test.ts +0 -167
  863. package/src/__tests__/pipeline-pass-trace.test.ts +0 -92
  864. package/src/__tests__/pipeline-stage-owner.test-d.ts +0 -13
  865. package/src/__tests__/plugin.test.ts +0 -25
  866. package/src/__tests__/prepared-graphics-backend-matrix.unit.test.ts +0 -129
  867. package/src/__tests__/prepared-graphics-resolver-recording.unit.test.ts +0 -180
  868. package/src/__tests__/public-pipeline-id.test-d.ts +0 -6
  869. package/src/__tests__/render-dispatch-membership.unit.test.ts +0 -117
  870. package/src/__tests__/render-feature-construction.unit.test.ts +0 -124
  871. package/src/__tests__/render-feature-error-code-owner.test-d.ts +0 -27
  872. package/src/__tests__/render-feature-gpu-buffer-usage-owner.test-d.ts +0 -46
  873. package/src/__tests__/render-feature-graph.integration.test.ts +0 -205
  874. package/src/__tests__/render-feature-graphics-staging.unit.test.ts +0 -200
  875. package/src/__tests__/render-feature-order.unit.test.ts +0 -66
  876. package/src/__tests__/render-feature-prepared-graphics-recording.unit.test.ts +0 -107
  877. package/src/__tests__/render-feature-staging.unit.test.ts +0 -94
  878. package/src/__tests__/renderer-render-scene-public.test-d.ts +0 -27
  879. package/src/__tests__/scene-temporal-coverage.unit.test.ts +0 -259
  880. package/src/__tests__/sun-snapshot-consumers.test.ts +0 -35
  881. package/src/__tests__/surface-backend-kind-owner.test-d.ts +0 -42
  882. package/src/__tests__/taa-history-store.unit.test.ts +0 -196
  883. package/src/__tests__/temporal-frame-transaction.integration.test.ts +0 -537
  884. package/src/__tests__/temporal-inspection.unit.test.ts +0 -138
  885. package/src/assets/__tests__/asset-decoders.unit.test.ts +0 -92
  886. package/src/assets/__tests__/mipmap-generator.unit.test.ts +0 -52
  887. package/src/assets/__tests__/render-asset-port.unit.test.ts +0 -54
  888. package/src/assets/__tests__/resolve-render-asset.unit.test.ts +0 -47
  889. package/src/components/__tests__/atmosphere-red.test.ts +0 -51
  890. package/src/components/__tests__/atmosphere.test.ts +0 -79
  891. package/src/components/__tests__/fog.test-d.ts +0 -49
  892. package/src/components/__tests__/fog.test.ts +0 -60
  893. package/src/components/atmosphere.ts +0 -64
  894. package/src/deferred-lighting.ts +0 -92
  895. package/src/dynamic-texture-store.ts +0 -111
  896. package/src/environment/README.md +0 -76
  897. package/src/environment/__tests__/failure-injection.test.ts +0 -50
  898. package/src/environment/__tests__/generation-red.test.ts +0 -64
  899. package/src/environment/__tests__/generation.test.ts +0 -37
  900. package/src/environment/__tests__/graph-transaction.test.ts +0 -85
  901. package/src/environment/__tests__/inspection-red.test.ts +0 -53
  902. package/src/environment/__tests__/lifecycle-evidence.test.ts +0 -40
  903. package/src/environment/__tests__/pipeline-topology.test.ts +0 -33
  904. package/src/environment/__tests__/readiness.test.ts +0 -42
  905. package/src/environment/__tests__/recovery.test.ts +0 -62
  906. package/src/environment/__tests__/resize-dispose.test.ts +0 -30
  907. package/src/environment/__tests__/signature-red.test.ts +0 -45
  908. package/src/environment/__tests__/signature.test.ts +0 -60
  909. package/src/environment/descriptors.ts +0 -7
  910. package/src/environment/extracted-environment.ts +0 -239
  911. package/src/environment/generation.ts +0 -158
  912. package/src/environment/gpu-bundle.ts +0 -144
  913. package/src/environment/graph.ts +0 -588
  914. package/src/environment/inspection.ts +0 -107
  915. package/src/environment/lifecycle.ts +0 -124
  916. package/src/environment/readiness.ts +0 -76
  917. package/src/environment/signature.ts +0 -185
  918. package/src/extract/__tests__/directional-csm-domain.unit.test.ts +0 -391
  919. package/src/extract/__tests__/environment-source.test.ts +0 -105
  920. package/src/extract/__tests__/schema-readers.unit.test.ts +0 -16
  921. package/src/extract/directional-csm.ts +0 -959
  922. package/src/extract/index.ts +0 -10
  923. package/src/extract/material-interface.ts +0 -604
  924. package/src/extract/schema-readers.ts +0 -27
  925. package/src/features/graph-contribution.ts +0 -577
  926. package/src/features/index.ts +0 -100
  927. package/src/features/morph/index.ts +0 -24
  928. package/src/features/morph/morph-bounds.ts +0 -123
  929. package/src/features/scene-temporal.ts +0 -274
  930. package/src/features/taa-resolve.ts +0 -244
  931. package/src/frame-chain.ts +0 -21
  932. package/src/hdrp-cluster-membership.ts +0 -70
  933. package/src/ibl/cubemap-projection.ts +0 -60
  934. package/src/ibl/face-uniforms.ts +0 -150
  935. package/src/mesh-update-errors.ts +0 -113
  936. package/src/mipmap-generator.ts +0 -244
  937. package/src/param-schema-projection-census.ts +0 -73
  938. package/src/persistent-render-scene.ts +0 -1752
  939. package/src/pipeline/index.ts +0 -40
  940. package/src/pipeline-errors.ts +0 -172
  941. package/src/prepare/__tests__/schema-readers.unit.test.ts +0 -16
  942. package/src/prepare/index.ts +0 -8
  943. package/src/prepare/schema-readers.ts +0 -20
  944. package/src/record/__tests__/environment-record.test.ts +0 -35
  945. package/src/record/__tests__/frame-targets.unit.test.ts +0 -54
  946. package/src/record/__tests__/membership-timing.unit.test.ts +0 -524
  947. package/src/record/__tests__/render-submission.integration.test.ts +0 -76
  948. package/src/record/__tests__/render-submission.perf.test.ts +0 -141
  949. package/src/record/__tests__/shadow-submit-mode.unit.test.ts +0 -88
  950. package/src/record/__tests__/view-ubo-layout.unit.test.ts +0 -101
  951. package/src/record/frame-observation.ts +0 -122
  952. package/src/record/index.ts +0 -15
  953. package/src/record/main-pass-skin.ts +0 -51
  954. package/src/record/main-pass-sprite.ts +0 -166
  955. package/src/record/material-payload.ts +0 -292
  956. package/src/record/material-slot-plan.ts +0 -68
  957. package/src/record/membership-timing.ts +0 -1012
  958. package/src/record/shadow-caster-uniform.ts +0 -37
  959. package/src/record/shadow-submit-mode.ts +0 -277
  960. package/src/render-dispatch-membership.ts +0 -155
  961. package/src/render-pipeline-context.ts +0 -332
  962. package/src/render-pipeline-target.ts +0 -96
  963. package/src/render-scene-projection.ts +0 -1738
  964. package/src/render-system-fold.ts +0 -531
  965. package/src/renderer/asset-service.ts +0 -32
  966. package/src/renderer/backend-selection.ts +0 -121
  967. package/src/renderer/environment-classify.ts +0 -30
  968. package/src/renderer/environment-error.ts +0 -19
  969. package/src/renderer/material/pipeline-projection.ts +0 -140
  970. package/src/renderer.ts +0 -940
  971. package/src/scene-utils/collect-subtree.ts +0 -40
  972. package/src/ssao-data.ts +0 -106
  973. package/src/surface-format.ts +0 -37
  974. package/src/taa-history-store.ts +0 -429
  975. package/src/temporal-coverage.ts +0 -106
  976. package/src/temporal-frame-transaction.ts +0 -301
  977. package/src/temporal-inspection.ts +0 -194
  978. package/src/temporal-view.ts +0 -174
  979. package/src/tilemap/resolve-tileset-runtime.ts +0 -72
@@ -1,1752 +0,0 @@
1
- import type { Component, EntityHandle, World } from '@forgeax/engine-ecs';
2
- import { Disabled } from '@forgeax/engine-ecs';
3
- import { createWorldProjection, type WorldProjection } from '@forgeax/engine-ecs/projection';
4
- import { box3, frustum, mat4 } from '@forgeax/engine-math';
5
- import type { RhiDevice, RhiError } from '@forgeax/engine-rhi';
6
- import { ChildOf, MorphWeights, Transform } from '@forgeax/engine-scene';
7
- import { Skin } from '@forgeax/engine-skinning';
8
- import {
9
- Camera,
10
- DirectionalLight,
11
- Fog,
12
- Instances,
13
- Layer,
14
- MeshFilter,
15
- MeshRenderer,
16
- PointLight,
17
- PointLightShadow,
18
- PostProcessParams,
19
- SkyboxBackground,
20
- Skylight,
21
- SpotLight,
22
- SpriteInstances,
23
- SpriteRegionOverride,
24
- Visibility,
25
- } from './components';
26
- import {
27
- type CsmCameraData,
28
- computeDirectionalCsm,
29
- type DirectionalCsmCandidateBroadphase,
30
- } from './extract/directional-csm';
31
- import {
32
- BatchTopology,
33
- type BatchTopologyInspection,
34
- type SubmissionPlan,
35
- } from './gpu-driven/batch-topology';
36
- import { GpuScene, type GpuSceneInspection } from './gpu-scene';
37
- import {
38
- buildRenderCandidateDomain,
39
- buildRenderCandidateIdentityIndex,
40
- type RenderCandidateDomain,
41
- renderCandidateCsmCandidates,
42
- reuseRenderCandidateDomain,
43
- } from './render-dispatch-membership';
44
- import type {
45
- RenderSceneApplyResult,
46
- RenderSceneOperation,
47
- RenderSceneSubmissionDelta,
48
- } from './render-scene-projection';
49
- import { RenderSceneProjection } from './render-scene-projection';
50
- import type {
51
- CameraSnapshot,
52
- DispatchEntry,
53
- ExtractedFrame,
54
- FogSelection,
55
- FogSnapshot,
56
- RenderableSnapshot,
57
- } from './render-system-extract';
58
- import { sortDispatchByQueue } from './render-system-extract';
59
- import { ACTIVE_CAMERA_KEY } from './systems/active-camera';
60
-
61
- export type RenderSceneResyncReason =
62
- | 'attach'
63
- | 'asset-catalog-changed'
64
- | 'shared-ref-changed'
65
- | 'journal-overflow'
66
- | 'unsupported-change'
67
- | 'non-rigid-lane'
68
- | 'explicit-invalidate';
69
-
70
- export type PersistentFogFailureCode = 'fog-owner-conflict' | 'fog-parameters-invalid';
71
-
72
- export interface PersistentFogInspection {
73
- readonly enabled: boolean;
74
- readonly resourceOwner: number | undefined;
75
- readonly entity: number | undefined;
76
- readonly revision: number | undefined;
77
- readonly reactive: boolean;
78
- readonly failure: PersistentFogFailureCode | undefined;
79
- }
80
-
81
- export interface PersistentFogFailure {
82
- readonly code: PersistentFogFailureCode;
83
- readonly resourceOwner: number;
84
- }
85
-
86
- export interface PersistentRenderSceneInspection {
87
- readonly worldEntitiesScanned: number;
88
- readonly fullRebuilds: number;
89
- readonly noChangeFrames: number;
90
- readonly deltaFrames: number;
91
- readonly transformUpdates: number;
92
- readonly materialUpdates: number;
93
- readonly instanceUpdates: number;
94
- readonly cameraUpdates: number;
95
- readonly resourceUpdates: number;
96
- /** Number of journal entities admitted to the local topology reconciler. */
97
- readonly topologyEntitiesReconciled: number;
98
- /** Number of identity-addressed production render extractions requested. */
99
- readonly singleEntityExtractions: number;
100
- readonly removals: number;
101
- readonly lastResyncReason: RenderSceneResyncReason | undefined;
102
- /** @internal M0 attribution for a rebuild that otherwise only says unsupported-change. */
103
- readonly lastResyncDetail: string | undefined;
104
- readonly cursor: number | undefined;
105
- readonly projectionRecords: number;
106
- readonly spatialIndex: import('./render-scene-projection').SpatialIndexInspection | undefined;
107
- readonly topology: BatchTopologyInspection;
108
- readonly gpu:
109
- | { readonly status: 'inactive' }
110
- | { readonly status: 'unsupported'; readonly reason: 'storage-buffer-unavailable' }
111
- | ({ readonly status: 'resident' } & GpuSceneInspection)
112
- | { readonly status: 'rebuild-pending' }
113
- | { readonly status: 'error' };
114
- readonly fog: PersistentFogInspection;
115
- }
116
-
117
- export interface PersistentRenderSceneOptions {
118
- readonly getDevice?: (() => RhiDevice) | undefined;
119
- readonly onGpuError?: ((error: RhiError) => void) | undefined;
120
- /** @internal Collect complete per-candidate CSM decisions for debug capture. */
121
- readonly collectShadowDebugCandidates?: (() => boolean) | undefined;
122
- }
123
-
124
- /**
125
- * Complete facts produced by the render-domain admission owner for one ECS
126
- * entity. Dispatch entries use the local candidate index from that extraction;
127
- * PersistentRenderScene rebases them onto its slot-owned candidate domain.
128
- */
129
- export interface PersistentRenderableExtraction {
130
- readonly snapshot: RenderableSnapshot;
131
- readonly candidateDispatch: readonly DispatchEntry[];
132
- }
133
-
134
- export interface PersistentGpuDrivenState {
135
- readonly scene: GpuScene;
136
- readonly plan: SubmissionPlan;
137
- readonly slots: readonly import('./render-scene-projection').RenderSceneProjectionSlot[];
138
- /**
139
- * The same projection that owns `slots` and the spatial index. Visibility
140
- * must query this owner; a revision number copied into GpuScene is only
141
- * diagnostic metadata and cannot select a candidate domain by itself.
142
- */
143
- /** Present for the production owner; optional keeps older test doubles honest. */
144
- readonly projection?: RenderSceneProjection;
145
- }
146
-
147
- type PersistentGpuSceneInspection = PersistentRenderSceneInspection['gpu'];
148
-
149
- interface PersistentWorldEntry {
150
- readonly worldId: number;
151
- readonly projection: RenderSceneProjection;
152
- readonly topology: BatchTopology;
153
- candidateFrame: ExtractedFrame;
154
- visibleFrame: ExtractedFrame;
155
- readonly changeProjection: WorldProjection;
156
- cursor: number;
157
- catalogEpoch: number;
158
- sharedRefEpoch: number;
159
- activeCameraEpoch: number;
160
- cameraEntities: ReadonlySet<EntityHandle>;
161
- readonly rigidOnly: boolean;
162
- gpuDrivenCoverageKey: string | undefined;
163
- gpuDrivenOwnsAll: boolean;
164
- }
165
-
166
- interface PersistentCompositionEntry {
167
- readonly token: object;
168
- readonly worlds: readonly World[];
169
- readonly worldIds: readonly number[];
170
- readonly cameraOwner: number;
171
- readonly resourceOwner: number;
172
- readonly projection: RenderSceneProjection;
173
- readonly topology: BatchTopology;
174
- readonly changeProjections: readonly WorldProjection[];
175
- candidateFrame: ExtractedFrame;
176
- visibleFrame: ExtractedFrame;
177
- readonly cursors: number[];
178
- readonly sharedRefEpochs: number[];
179
- readonly cameraEntities: readonly ReadonlySet<EntityHandle>[];
180
- catalogEpoch: number;
181
- readonly rigidOnly: boolean;
182
- gpuDrivenCoverageKey: string | undefined;
183
- gpuDrivenOwnsAll: boolean;
184
- }
185
-
186
- const RENDER_RELEVANT_COMPONENTS = [
187
- Transform,
188
- ChildOf,
189
- MeshFilter,
190
- MeshRenderer,
191
- Instances,
192
- SpriteInstances,
193
- SpriteRegionOverride,
194
- Skin,
195
- MorphWeights,
196
- Layer,
197
- Visibility,
198
- Disabled,
199
- Camera,
200
- DirectionalLight,
201
- PointLight,
202
- PointLightShadow,
203
- SpotLight,
204
- Skylight,
205
- Fog,
206
- SkyboxBackground,
207
- PostProcessParams,
208
- ] as const;
209
- const RENDER_RELEVANT_COMPONENT_SET = new Set<Component>(RENDER_RELEVANT_COMPONENTS);
210
-
211
- const NON_RENDERABLE_TRANSFORM_CONSUMERS = [
212
- Camera,
213
- DirectionalLight,
214
- PointLight,
215
- SpotLight,
216
- ] as const;
217
-
218
- function cameraFrusta(cameras: readonly CameraSnapshot[]): readonly Float32Array[] {
219
- const planes: Float32Array[] = [];
220
- for (const camera of cameras) {
221
- if (
222
- (camera.projection === 'perspective' && (camera.fov <= 0 || camera.aspect <= 0)) ||
223
- camera.near >= camera.far
224
- ) {
225
- planes.push(new Float32Array(0));
226
- continue;
227
- }
228
- const projection = mat4.create();
229
- if (camera.projection === 'orthographic') {
230
- mat4.orthographic(
231
- projection,
232
- camera.orthoLeft,
233
- camera.orthoRight,
234
- camera.orthoBottom,
235
- camera.orthoTop,
236
- camera.near,
237
- camera.far,
238
- );
239
- } else {
240
- mat4.perspective(projection, camera.fov, camera.aspect, camera.near, camera.far);
241
- }
242
- const view = mat4.create();
243
- mat4.invert(view, camera.world as unknown as mat4.Mat4Like);
244
- const viewProjection = mat4.create();
245
- mat4.multiply(viewProjection, projection, view);
246
- const cameraPlanes = frustum.create();
247
- frustum.fromViewProjection(cameraPlanes, viewProjection);
248
- planes.push(cameraPlanes);
249
- }
250
- return planes;
251
- }
252
-
253
- function candidateBroadphaseForProjection(
254
- projection: RenderSceneProjection,
255
- candidateDomain: RenderCandidateDomain,
256
- ): DirectionalCsmCandidateBroadphase {
257
- return (worldAabb) =>
258
- projection.querySpatialIndex(worldAabb).hits.flatMap((hit) => {
259
- const candidateIndex = candidateDomain.indexByIdentity.get(`${hit.worldId}:${hit.entityKey}`);
260
- return candidateIndex === undefined ? [] : [candidateIndex];
261
- });
262
- }
263
-
264
- function rebaseCandidateDomain(
265
- frame: ExtractedFrame,
266
- candidates: readonly RenderableSnapshot[],
267
- patch?: {
268
- readonly worldId: number;
269
- readonly dispatch: readonly DispatchEntry[];
270
- readonly replaceIdentities: ReadonlySet<string>;
271
- },
272
- ): ExtractedFrame {
273
- const previousCandidates =
274
- frame.candidateDomain?.renderables ?? frame.candidateRenderables ?? frame.renderables;
275
- const previousDispatch =
276
- frame.candidateDomain?.dispatch ?? frame.candidateDispatch ?? frame.dispatch;
277
- const previousDomain =
278
- frame.candidateDomain ?? buildRenderCandidateDomain(previousCandidates, previousDispatch);
279
- const candidateDomainUnchanged =
280
- previousCandidates.length === candidates.length &&
281
- previousCandidates.every(
282
- (candidate, candidateIndex) =>
283
- candidate === candidates[candidateIndex] &&
284
- (candidate.candidateIndex === undefined || candidate.candidateIndex === candidateIndex),
285
- );
286
- if (candidateDomainUnchanged && frame.candidateDomain !== undefined) {
287
- // Camera-only refreshes must not manufacture a new candidate array, index
288
- // map, dispatch array, or membership Set when the domain is unchanged.
289
- return frame;
290
- }
291
- const candidateRenderables = candidates.map((candidate, candidateIndex) =>
292
- candidate.candidateIndex === candidateIndex ? candidate : { ...candidate, candidateIndex },
293
- );
294
- const nextIndexByIdentity = buildRenderCandidateIdentityIndex(candidateRenderables);
295
-
296
- const candidateDispatch = previousDomain.dispatch.flatMap((entry) => {
297
- const previousCandidate = previousCandidates[entry.renderableIndex];
298
- if (previousCandidate === undefined) return [];
299
- if (
300
- patch?.replaceIdentities.has(
301
- `${previousCandidate.worldId}:${previousCandidate.entityKey}`,
302
- ) === true
303
- ) {
304
- return [];
305
- }
306
- const candidateIndex = nextIndexByIdentity.get(
307
- `${previousCandidate.worldId}:${previousCandidate.entityKey}`,
308
- );
309
- return candidateIndex === undefined ? [] : [{ ...entry, renderableIndex: candidateIndex }];
310
- });
311
- if (patch !== undefined) {
312
- for (const entry of patch.dispatch) {
313
- const candidateIndex = nextIndexByIdentity.get(`${patch.worldId}:${entry.entityIndex}`);
314
- if (candidateIndex === undefined) continue;
315
- candidateDispatch.push({ ...entry, renderableIndex: candidateIndex });
316
- }
317
- }
318
- const candidateDomain = buildRenderCandidateDomain(
319
- candidateRenderables,
320
- sortDispatchByQueue(candidateDispatch),
321
- nextIndexByIdentity,
322
- );
323
-
324
- return {
325
- ...frame,
326
- candidateRenderables: candidateDomain.renderables,
327
- candidateDispatch: candidateDomain.dispatch,
328
- candidateDispatchMembership: candidateDomain.membership,
329
- candidateDomain,
330
- };
331
- }
332
-
333
- function cullPersistentFrame(
334
- frame: ExtractedFrame,
335
- candidates: readonly RenderableSnapshot[],
336
- collectShadowDebugCandidates = false,
337
- projection?: RenderSceneProjection,
338
- ): ExtractedFrame {
339
- const planes = cameraFrusta(frame.cameras);
340
- const candidateSnapshots =
341
- frame.candidateDomain?.renderables ?? frame.candidateRenderables ?? candidates;
342
- const candidateDispatch =
343
- frame.candidateDomain?.dispatch ?? frame.candidateDispatch ?? frame.dispatch;
344
- const candidateDomain = reuseRenderCandidateDomain(
345
- candidateSnapshots,
346
- candidateDispatch,
347
- frame.candidateDomain,
348
- );
349
- const mainVisible = new Set<number>();
350
- let total = 0;
351
- let culled = 0;
352
-
353
- for (let index = 0; index < candidateSnapshots.length; index += 1) {
354
- const candidate = candidateSnapshots[index];
355
- if (candidate === undefined) continue;
356
- let isVisible = true;
357
- if (candidate.localAabb !== undefined) {
358
- total += 1;
359
- const worldAabb = box3.create();
360
- box3.transformBox3(
361
- worldAabb,
362
- candidate.localAabb,
363
- candidate.transform.world as unknown as Parameters<typeof box3.transformBox3>[2],
364
- );
365
- isVisible = planes.length === 0;
366
- for (const cameraPlanes of planes) {
367
- if (
368
- cameraPlanes.length === 0 ||
369
- frustum.intersectsBox(cameraPlanes as frustum.Frustum, worldAabb as box3.Box3Like)
370
- ) {
371
- isVisible = true;
372
- break;
373
- }
374
- }
375
- }
376
- if (!isVisible) {
377
- culled += 1;
378
- continue;
379
- }
380
- mainVisible.add(index);
381
- }
382
-
383
- const camera = frame.cameras[0];
384
- const csmConfig = frame.lights.directionalCsmConfig;
385
- const csmDirection = frame.lights.directionalCsmDirection;
386
- const csmCamera: CsmCameraData | undefined =
387
- camera === undefined
388
- ? undefined
389
- : {
390
- world: camera.world,
391
- fov: camera.fov,
392
- aspect: camera.aspect,
393
- near: camera.near,
394
- far: camera.far,
395
- projection: camera.projection,
396
- orthoLeft: camera.orthoLeft,
397
- orthoRight: camera.orthoRight,
398
- orthoBottom: camera.orthoBottom,
399
- orthoTop: camera.orthoTop,
400
- };
401
- const candidateDispatchMembership = candidateDomain.membership;
402
- const recomputedCsm =
403
- csmConfig !== undefined && csmDirection !== undefined
404
- ? computeDirectionalCsm(
405
- csmDirection,
406
- { ...csmConfig, collectCandidateDecisions: collectShadowDebugCandidates },
407
- csmCamera,
408
- renderCandidateCsmCandidates(candidateDomain),
409
- projection === undefined
410
- ? undefined
411
- : candidateBroadphaseForProjection(projection, candidateDomain),
412
- )
413
- : undefined;
414
- const csm = recomputedCsm ?? frame.lights.directionalCsm;
415
- if (csm !== undefined) {
416
- for (const cascade of csm.cascades) {
417
- for (const index of cascade.casterRenderableIndices) {
418
- // Keep the candidate index stable across main-view culling.
419
- if (index >= 0) mainVisible.add(index);
420
- }
421
- }
422
- }
423
-
424
- const unionIndices = [...mainVisible].sort((left, right) => left - right);
425
- const projectedIndex = new Int32Array(candidateSnapshots.length);
426
- projectedIndex.fill(-1);
427
- const visible: RenderableSnapshot[] = [];
428
- for (const candidateIndex of unionIndices) {
429
- const candidate = candidateSnapshots[candidateIndex];
430
- if (candidate === undefined) continue;
431
- projectedIndex[candidateIndex] = visible.length;
432
- visible.push(candidate);
433
- }
434
-
435
- const dispatch: DispatchEntry[] = [];
436
- for (const entry of candidateDispatch) {
437
- const renderableIndex = projectedIndex[entry.renderableIndex];
438
- if (renderableIndex === undefined || renderableIndex < 0) continue;
439
- dispatch.push({ ...entry, renderableIndex });
440
- }
441
- const finalizedCsm = csm;
442
- const nextLights =
443
- finalizedCsm === undefined
444
- ? frame.lights
445
- : {
446
- ...frame.lights,
447
- // The CSM plan owns receiver matrices and cascade volumes. Camera
448
- // refresh can first produce a no-candidate fit; once the candidate
449
- // domain is available here, publish every light field from the same
450
- // finalized plan so four-view visibility and the View UBO cannot use
451
- // different cascade spaces.
452
- lightViewProj: finalizedCsm.lightViewProj,
453
- splitPlanes: finalizedCsm.splitPlanes,
454
- cascadeCount: finalizedCsm.cascadeCount,
455
- cascadeBlend: finalizedCsm.cascadeBlend,
456
- shadowMapSize: finalizedCsm.shadowMapSize,
457
- directionalCsm: finalizedCsm,
458
- cascades: finalizedCsm.cascades,
459
- };
460
- return {
461
- ...frame,
462
- renderables: visible,
463
- dispatch,
464
- candidateRenderables: candidateDomain.renderables,
465
- candidateDispatch: candidateDomain.dispatch,
466
- candidateDispatchMembership,
467
- candidateDomain,
468
- lights: nextLights,
469
- frustumStats: { culled, total },
470
- };
471
- }
472
-
473
- /** Persistent single-World rigid scene used by the renderer's ordinary path. */
474
- export class PersistentRenderScene {
475
- private readonly entries = new WeakMap<World, PersistentWorldEntry>();
476
- private readonly worldIds = new WeakMap<World, number>();
477
- private readonly worldsById = new Map<number, World>();
478
- private nextWorldId = 0;
479
- private fullRebuilds = 0;
480
- private worldEntitiesScanned = 0;
481
- private noChangeFrames = 0;
482
- private deltaFrames = 0;
483
- private transformUpdates = 0;
484
- private materialUpdates = 0;
485
- private instanceUpdates = 0;
486
- private cameraUpdates = 0;
487
- private resourceUpdates = 0;
488
- private topologyEntitiesReconciled = 0;
489
- private singleEntityExtractions = 0;
490
- private removals = 0;
491
- private lastResyncReason: RenderSceneResyncReason | undefined;
492
- private lastResyncDetail: string | undefined;
493
- private lastWorld: World | undefined;
494
- private composition: PersistentCompositionEntry | undefined;
495
- private gpuScene: GpuScene | undefined;
496
- private gpuOwner: object | undefined;
497
- private gpuDevice: RhiDevice | undefined;
498
- private gpuStatus: 'inactive' | 'unsupported' | 'resident' | 'rebuild-pending' | 'error' =
499
- 'inactive';
500
- private fogCandidate: FogSelection | undefined;
501
- private fogLastKnownGood: FogSelection | undefined;
502
- private fogFailure: PersistentFogFailureCode | undefined;
503
- private fogFailureOwner: number | undefined;
504
- private fogReactive = false;
505
-
506
- constructor(private readonly options: PersistentRenderSceneOptions = {}) {}
507
-
508
- readonly worldForRenderId = (worldId: number): World | undefined => this.worldsById.get(worldId);
509
-
510
- extract(
511
- world: World,
512
- catalogEpoch: number,
513
- buildCandidateFrame: () => ExtractedFrame,
514
- refreshMaterial?: (
515
- snapshot: RenderableSnapshot,
516
- materialHandle: number,
517
- ) => RenderableSnapshot | undefined,
518
- refreshCameras?: (frame: ExtractedFrame) => ExtractedFrame,
519
- gpuDrivenCoverageKey?: string,
520
- refreshPostProcessParams?: (frame: ExtractedFrame) => ExtractedFrame,
521
- refreshLights?: (frame: ExtractedFrame) => ExtractedFrame,
522
- refreshRenderable?: (
523
- entity: EntityHandle,
524
- currentFrame: ExtractedFrame,
525
- ) => PersistentRenderableExtraction | undefined,
526
- ): ExtractedFrame {
527
- this.worldEntitiesScanned = 0;
528
- this.lastWorld = world;
529
- this.attachWorld(world);
530
- const entry = this.entries.get(world);
531
- if (entry === undefined) {
532
- return this.rebuild(world, catalogEpoch, buildCandidateFrame, 'attach');
533
- }
534
- if (entry.catalogEpoch !== catalogEpoch) {
535
- return this.rebuild(world, catalogEpoch, buildCandidateFrame, 'asset-catalog-changed');
536
- }
537
- const sharedRefChanges = world.sharedRefs.readChangesSince(entry.sharedRefEpoch);
538
- if (sharedRefChanges.status === 'overflow') {
539
- return this.rebuild(world, catalogEpoch, buildCandidateFrame, 'shared-ref-changed');
540
- }
541
-
542
- const changes = entry.changeProjection.poll();
543
- if (changes.status === 'rebuild') {
544
- return this.rebuild(world, catalogEpoch, buildCandidateFrame, 'journal-overflow');
545
- }
546
- const refreshedBySlot = new Map<number, RenderableSnapshot>();
547
- for (const change of sharedRefChanges.records) {
548
- const affected = entry.projection.slotsForMaterial(change.handle);
549
- if (affected.length > 0 && refreshMaterial === undefined) {
550
- return this.rebuild(world, catalogEpoch, buildCandidateFrame, 'shared-ref-changed');
551
- }
552
- for (const slot of affected) {
553
- const current = refreshedBySlot.get(slot.slot) ?? slot.snapshot;
554
- const refreshed = refreshMaterial?.(current, change.handle);
555
- if (refreshed === undefined) {
556
- return this.rebuild(world, catalogEpoch, buildCandidateFrame, 'shared-ref-changed');
557
- }
558
- refreshedBySlot.set(slot.slot, refreshed);
559
- }
560
- }
561
- const materialOperations: RenderSceneOperation[] = [...refreshedBySlot.entries()].map(
562
- ([slot, snapshot]) => {
563
- const liveSlot = entry.projection.slotByIndex(slot);
564
- return {
565
- kind: 'create',
566
- snapshot,
567
- ...(liveSlot === undefined ? {} : { expectedGeneration: liveSlot.generation }),
568
- };
569
- },
570
- );
571
- let postProcessParamsChanged = false;
572
- let lightsChanged = false;
573
- const activeCameraEpoch = world.getResourceChange(ACTIVE_CAMERA_KEY)?.changed ?? 0;
574
- let cameraChanged = activeCameraEpoch !== entry.activeCameraEpoch;
575
- if (
576
- !entry.rigidOnly &&
577
- (changes.changes.length > 0 || materialOperations.length > 0 || cameraChanged)
578
- ) {
579
- return this.rebuild(world, catalogEpoch, buildCandidateFrame, 'non-rigid-lane');
580
- }
581
- if (changes.changes.length === 0 && materialOperations.length === 0 && !cameraChanged) {
582
- entry.cursor = changes.cursor;
583
- entry.sharedRefEpoch = sharedRefChanges.cursor;
584
- this.noChangeFrames += 1;
585
- this.syncGpu(world, entry.projection);
586
- return entry.visibleFrame;
587
- }
588
-
589
- const derivedTransforms = new Set<EntityHandle>();
590
- const removedRenderables = new Set<EntityHandle>();
591
- const instanceOperations: RenderSceneOperation[] = [];
592
- const topologyEntities = new Set<EntityHandle>();
593
- const topologyDispatch: DispatchEntry[] = [];
594
- const topologyIdentities = new Set<string>();
595
- for (const record of changes.changes) {
596
- if (record.kind === 'derived-component-changed' && record.component === Transform) {
597
- derivedTransforms.add(record.entity as EntityHandle);
598
- }
599
- }
600
- for (const record of changes.changes) {
601
- const authoredTransform =
602
- record.kind === 'component-changed' && record.component === Transform;
603
- const derivedTransform =
604
- record.kind === 'derived-component-changed' && record.component === Transform;
605
- const wasCamera = entry.cameraEntities.has(record.entity as EntityHandle);
606
- const isCamera = world.hasComponent(record.entity as EntityHandle, Camera);
607
- if (
608
- record.component === Camera ||
609
- ((authoredTransform || derivedTransform) && (wasCamera || isCamera))
610
- ) {
611
- cameraChanged = true;
612
- continue;
613
- }
614
- if (record.component === PostProcessParams && record.kind !== 'entity-removed') {
615
- if (refreshPostProcessParams === undefined) {
616
- return this.rebuild(
617
- world,
618
- catalogEpoch,
619
- buildCandidateFrame,
620
- 'unsupported-change',
621
- 'post-process-refresh-unavailable',
622
- );
623
- }
624
- // PostProcessParams is a resource-owner input, not a render-domain
625
- // slot. Refresh its compact map without invalidating the candidate,
626
- // dispatch, topology, or GPU scene owner.
627
- postProcessParamsChanged = true;
628
- continue;
629
- }
630
- if (record.kind === 'entity-removed' && wasCamera) {
631
- cameraChanged = true;
632
- if (refreshLights !== undefined) lightsChanged = true;
633
- if (entry.projection.has(entry.worldId, record.entity)) {
634
- removedRenderables.add(record.entity as EntityHandle);
635
- }
636
- continue;
637
- }
638
- if (record.kind === 'entity-removed') {
639
- if (refreshLights !== undefined) lightsChanged = true;
640
- if (entry.projection.has(entry.worldId, record.entity)) {
641
- removedRenderables.add(record.entity as EntityHandle);
642
- }
643
- continue;
644
- }
645
- if (
646
- record.component === DirectionalLight ||
647
- record.component === PointLight ||
648
- record.component === PointLightShadow ||
649
- record.component === SpotLight ||
650
- record.component === Skylight ||
651
- record.component === Fog ||
652
- record.component === SkyboxBackground
653
- ) {
654
- if (refreshLights === undefined) {
655
- return this.rebuild(
656
- world,
657
- catalogEpoch,
658
- buildCandidateFrame,
659
- 'unsupported-change',
660
- `light-refresh-unavailable:${record.kind}:${record.componentId}:${record.entity}`,
661
- );
662
- }
663
- // Light and shadow components feed compact extracted resources. A
664
- // mutation there must not invalidate render-domain slots, dispatch,
665
- // candidate membership, topology, or the GPU scene owner.
666
- lightsChanged = true;
667
- continue;
668
- }
669
- if (derivedTransform) continue;
670
- if (authoredTransform && derivedTransforms.has(record.entity as EntityHandle)) continue;
671
- if (record.component === Instances && entry.projection.has(entry.worldId, record.entity)) {
672
- const current = entry.projection.snapshot(entry.worldId, record.entity);
673
- if (current === undefined) continue;
674
- const instances = world.get(record.entity, Instances);
675
- const transforms = instances.ok ? instances.value.transforms : undefined;
676
- if (transforms === undefined) {
677
- const { instances: _instances, ...withoutInstances } = current;
678
- const liveRecord = entry.projection.record(entry.worldId, record.entity);
679
- instanceOperations.push({
680
- kind: 'create',
681
- snapshot: withoutInstances,
682
- ...(liveRecord === undefined ? {} : { expectedGeneration: liveRecord.generation }),
683
- });
684
- continue;
685
- }
686
- if (transforms.length % 16 !== 0) {
687
- return this.rebuild(
688
- world,
689
- catalogEpoch,
690
- buildCandidateFrame,
691
- 'unsupported-change',
692
- `instance-transform-length:${record.entity}:${transforms.length}`,
693
- );
694
- }
695
- const liveRecord = entry.projection.record(entry.worldId, record.entity);
696
- instanceOperations.push({
697
- kind: 'create',
698
- snapshot: {
699
- ...current,
700
- instances: {
701
- transforms: new Float32Array(transforms),
702
- instanceCount: Math.max(1, transforms.length / 16),
703
- cacheKey: record.entity,
704
- archVersion: (current.instances?.archVersion ?? 0) + 1,
705
- },
706
- },
707
- ...(liveRecord === undefined ? {} : { expectedGeneration: liveRecord.generation }),
708
- });
709
- continue;
710
- }
711
- if (record.component !== undefined && !RENDER_RELEVANT_COMPONENT_SET.has(record.component)) {
712
- continue;
713
- }
714
- if (
715
- refreshRenderable !== undefined &&
716
- record.component !== ChildOf &&
717
- record.component !== Visibility &&
718
- record.component !== Skin
719
- ) {
720
- // Reconcile the final entity state once after all journal records have
721
- // been classified. This is the generic admission path for a new or
722
- // materially changed renderable; hierarchy, inherited visibility, and
723
- // skin changes stay on their existing conservative lanes.
724
- topologyEntities.add(record.entity as EntityHandle);
725
- continue;
726
- }
727
- return this.rebuild(
728
- world,
729
- catalogEpoch,
730
- buildCandidateFrame,
731
- 'unsupported-change',
732
- `change-record:${record.kind}:${record.componentId ?? 'none'}:${record.entity}`,
733
- );
734
- }
735
-
736
- const operations: RenderSceneOperation[] = [
737
- ...materialOperations,
738
- ...instanceOperations.filter((operation) => {
739
- return !(
740
- operation.kind === 'create' &&
741
- topologyEntities.has(operation.snapshot.entityKey as EntityHandle)
742
- );
743
- }),
744
- ...[...removedRenderables].map((entity): RenderSceneOperation => {
745
- const liveRecord = entry.projection.record(entry.worldId, entity);
746
- return {
747
- kind: 'remove',
748
- worldId: entry.worldId,
749
- entityKey: entity,
750
- ...(liveRecord === undefined ? {} : { expectedGeneration: liveRecord.generation }),
751
- };
752
- }),
753
- ];
754
- let transformOperationCount = 0;
755
- for (const entity of derivedTransforms) {
756
- if (topologyEntities.has(entity)) continue;
757
- // A FixedUpdate can derive Transform and despawn the same entity before
758
- // the render projection polls its journal. The entity-removed record is
759
- // already authoritative for the projection; do not turn that stale
760
- // derived record into a full rebuild or read a component that no longer
761
- // exists.
762
- if (removedRenderables.has(entity)) continue;
763
- if (!entry.projection.has(entry.worldId, entity)) {
764
- if (entry.cameraEntities.has(entity) || world.hasComponent(entity, Camera)) continue;
765
- if (
766
- NON_RENDERABLE_TRANSFORM_CONSUMERS.some((component) =>
767
- world.hasComponent(entity, component),
768
- )
769
- ) {
770
- if (refreshLights === undefined) {
771
- return this.rebuild(
772
- world,
773
- catalogEpoch,
774
- buildCandidateFrame,
775
- 'unsupported-change',
776
- `non-renderable-transform-consumer:${entity}`,
777
- );
778
- }
779
- lightsChanged = true;
780
- continue;
781
- }
782
- continue;
783
- }
784
- const transform = world.get(entity, Transform);
785
- if (!transform.ok) {
786
- return this.rebuild(
787
- world,
788
- catalogEpoch,
789
- buildCandidateFrame,
790
- 'unsupported-change',
791
- `derived-transform-unavailable:${entity}`,
792
- );
793
- }
794
- const liveRecord = entry.projection.record(entry.worldId, entity);
795
- operations.push({
796
- kind: 'update-transform',
797
- worldId: entry.worldId,
798
- entityKey: entity,
799
- world: new Float32Array(transform.value.world),
800
- ...(liveRecord === undefined ? {} : { expectedGeneration: liveRecord.generation }),
801
- });
802
- transformOperationCount += 1;
803
- }
804
- if (refreshRenderable !== undefined) {
805
- this.topologyEntitiesReconciled += topologyEntities.size;
806
- for (const entity of topologyEntities) {
807
- const liveRecord = entry.projection.record(entry.worldId, entity);
808
- topologyIdentities.add(`${entry.worldId}:${entity}`);
809
- const hasRenderableComponents =
810
- world.hasComponent(entity, Transform) &&
811
- world.hasComponent(entity, MeshFilter) &&
812
- world.hasComponent(entity, MeshRenderer) &&
813
- !world.hasComponent(entity, Disabled);
814
- const extracted = hasRenderableComponents
815
- ? (() => {
816
- this.singleEntityExtractions += 1;
817
- return refreshRenderable(entity, entry.candidateFrame);
818
- })()
819
- : undefined;
820
- if (extracted === undefined) {
821
- if (liveRecord !== undefined && !removedRenderables.has(entity)) {
822
- operations.push({
823
- kind: 'remove',
824
- worldId: entry.worldId,
825
- entityKey: entity,
826
- expectedGeneration: liveRecord.generation,
827
- });
828
- }
829
- continue;
830
- }
831
- const snapshot =
832
- extracted.snapshot.worldId === entry.worldId
833
- ? extracted.snapshot
834
- : { ...extracted.snapshot, worldId: entry.worldId };
835
- operations.push({
836
- kind: 'create',
837
- snapshot,
838
- ...(liveRecord === undefined ? {} : { expectedGeneration: liveRecord.generation }),
839
- });
840
- topologyDispatch.push(...extracted.candidateDispatch);
841
- }
842
- }
843
- // A stale derived Transform record can discover that the Transform column
844
- // disappeared after the initial operation list was assembled. Materialize
845
- // that late remove before the projection apply; otherwise the diagnostic
846
- // set says "removed" while the retained slot remains live for one frame.
847
- const removeOperations = new Set(
848
- operations.flatMap((operation) =>
849
- operation.kind === 'remove' ? [`${operation.worldId}:${operation.entityKey}`] : [],
850
- ),
851
- );
852
- for (const entity of removedRenderables) {
853
- const liveRecord = entry.projection.record(entry.worldId, entity);
854
- const identity = `${entry.worldId}:${entity}`;
855
- if (liveRecord === undefined || removeOperations.has(identity)) continue;
856
- operations.push({
857
- kind: 'remove',
858
- worldId: entry.worldId,
859
- entityKey: entity,
860
- expectedGeneration: liveRecord.generation,
861
- });
862
- removeOperations.add(identity);
863
- }
864
- if (operations.length === 0 && !cameraChanged && !postProcessParamsChanged && !lightsChanged) {
865
- entry.cursor = changes.cursor;
866
- entry.sharedRefEpoch = sharedRefChanges.cursor;
867
- this.noChangeFrames += 1;
868
- this.syncGpu(world, entry.projection);
869
- return entry.visibleFrame;
870
- }
871
- if (operations.length > 0) {
872
- const delta = entry.projection.apply(operations);
873
- entry.topology.apply(delta);
874
- this.syncGpu(world, entry.projection, delta);
875
- const candidates = entry.projection.materialize();
876
- const rebased = rebaseCandidateDomain(
877
- entry.candidateFrame,
878
- candidates,
879
- topologyEntities.size === 0
880
- ? undefined
881
- : {
882
- worldId: entry.worldId,
883
- dispatch: topologyDispatch,
884
- replaceIdentities: topologyIdentities,
885
- },
886
- );
887
- entry.candidateFrame = { ...rebased, renderables: [...candidates] };
888
- } else {
889
- this.syncGpu(world, entry.projection);
890
- }
891
- if (cameraChanged) {
892
- if (refreshCameras === undefined) {
893
- return this.rebuild(
894
- world,
895
- catalogEpoch,
896
- buildCandidateFrame,
897
- 'unsupported-change',
898
- 'camera-refresh-unavailable',
899
- );
900
- }
901
- const candidates = entry.projection.materialize();
902
- const refreshed = rebaseCandidateDomain(refreshCameras(entry.candidateFrame), candidates);
903
- entry.candidateFrame = { ...refreshed, renderables: [...candidates] };
904
- entry.cameraEntities = this.cameraEntities(world);
905
- entry.activeCameraEpoch = activeCameraEpoch;
906
- this.cameraUpdates += 1;
907
- }
908
- if (postProcessParamsChanged && refreshPostProcessParams !== undefined) {
909
- // Refresh candidate and visible frames separately because the latter is
910
- // the cull projection of the former and may be returned without a cull
911
- // pass when this is the only changed lane.
912
- entry.candidateFrame = refreshPostProcessParams(entry.candidateFrame);
913
- entry.visibleFrame = refreshPostProcessParams(entry.visibleFrame);
914
- }
915
- if (lightsChanged && refreshLights !== undefined) {
916
- // Refresh candidate and visible frames separately so a light-only
917
- // update preserves the existing visible projection while publishing
918
- // the new light/CSM/point-shadow snapshot to both frame owners.
919
- entry.candidateFrame = refreshLights(entry.candidateFrame);
920
- entry.visibleFrame = refreshLights(entry.visibleFrame);
921
- }
922
- if (postProcessParamsChanged || lightsChanged) this.resourceUpdates += 1;
923
- if (operations.length > 0 || cameraChanged) {
924
- const candidates = entry.projection.materialize();
925
- entry.visibleFrame =
926
- operations.length === 0 &&
927
- cameraChanged &&
928
- entry.gpuDrivenOwnsAll &&
929
- entry.gpuDrivenCoverageKey === gpuDrivenCoverageKey
930
- ? entry.candidateFrame
931
- : cullPersistentFrame(
932
- entry.candidateFrame,
933
- candidates,
934
- this.options.collectShadowDebugCandidates?.() === true,
935
- entry.projection,
936
- );
937
- }
938
- entry.cursor = changes.cursor;
939
- entry.sharedRefEpoch = sharedRefChanges.cursor;
940
- this.deltaFrames += 1;
941
- this.transformUpdates += transformOperationCount;
942
- this.materialUpdates += materialOperations.length;
943
- this.instanceUpdates += instanceOperations.length;
944
- this.removals += removedRenderables.size;
945
- return entry.visibleFrame;
946
- }
947
-
948
- extractComposition(
949
- worlds: readonly World[],
950
- owner: { readonly cameraOwner: number; readonly resourceOwner: number },
951
- catalogEpoch: number,
952
- buildCandidateFrame: () => ExtractedFrame,
953
- refreshRenderable?: (
954
- world: World,
955
- worldId: number,
956
- entity: EntityHandle,
957
- currentFrame: ExtractedFrame,
958
- ) => PersistentRenderableExtraction | undefined,
959
- ): ExtractedFrame {
960
- this.worldEntitiesScanned = 0;
961
- const worldIds = worlds.map((world) => this.attachWorld(world));
962
- const entry = this.composition;
963
- if (
964
- entry === undefined ||
965
- entry.catalogEpoch !== catalogEpoch ||
966
- entry.cameraOwner !== owner.cameraOwner ||
967
- entry.resourceOwner !== owner.resourceOwner ||
968
- entry.worlds.length !== worlds.length ||
969
- entry.worlds.some((world, index) => world !== worlds[index]) ||
970
- entry.worldIds.some((worldId, index) => worldId !== worldIds[index])
971
- ) {
972
- return this.rebuildComposition(worlds, worldIds, owner, catalogEpoch, buildCandidateFrame);
973
- }
974
- if (!entry.rigidOnly) {
975
- return this.rebuildComposition(worlds, worldIds, owner, catalogEpoch, buildCandidateFrame);
976
- }
977
-
978
- const operations: RenderSceneOperation[] = [];
979
- const topologyEntities = new Map<
980
- string,
981
- { readonly world: World; readonly worldId: number; readonly entity: EntityHandle }
982
- >();
983
- const topologyDispatchByWorld = new Map<number, DispatchEntry[]>();
984
- const topologyIdentitiesByWorld = new Map<number, Set<string>>();
985
- const removalIdentities = new Set<string>();
986
- let transformOperationCount = 0;
987
- let removalOperationCount = 0;
988
- let requiresRebuild = false;
989
- for (let worldId = 0; worldId < worlds.length; worldId += 1) {
990
- const world = worlds[worldId];
991
- if (world === undefined) continue;
992
- const renderWorldId = entry.worldIds[worldId];
993
- if (renderWorldId === undefined) {
994
- requiresRebuild = true;
995
- break;
996
- }
997
- const changeProjection = entry.changeProjections[worldId];
998
- if (changeProjection === undefined) {
999
- requiresRebuild = true;
1000
- break;
1001
- }
1002
- const changes = changeProjection.poll();
1003
- const shared = world.sharedRefs.readChangesSince(entry.sharedRefEpochs[worldId] ?? 0);
1004
- if (changes.status === 'rebuild' || shared.status === 'overflow') {
1005
- requiresRebuild = true;
1006
- break;
1007
- }
1008
- if (shared.records.length > 0) {
1009
- requiresRebuild = true;
1010
- break;
1011
- }
1012
- const derivedTransforms = new Set<EntityHandle>();
1013
- for (const record of changes.changes) {
1014
- if (record.kind === 'derived-component-changed' && record.component === Transform) {
1015
- derivedTransforms.add(record.entity as EntityHandle);
1016
- }
1017
- }
1018
- for (const record of changes.changes) {
1019
- if (
1020
- record.kind !== 'entity-removed' &&
1021
- record.component !== undefined &&
1022
- !RENDER_RELEVANT_COMPONENT_SET.has(record.component)
1023
- ) {
1024
- continue;
1025
- }
1026
- const authoredTransform =
1027
- record.kind === 'component-changed' && record.component === Transform;
1028
- const derivedTransform =
1029
- record.kind === 'derived-component-changed' && record.component === Transform;
1030
- if (derivedTransform) continue;
1031
- if (authoredTransform && derivedTransforms.has(record.entity as EntityHandle)) continue;
1032
- const entity = record.entity as EntityHandle;
1033
- const identity = `${renderWorldId}:${entity}`;
1034
- const wasCamera = entry.cameraEntities[worldId]?.has(entity) === true;
1035
- if (record.kind === 'entity-removed') {
1036
- // Camera/light/resource removal changes the composed frame-level
1037
- // owner. Keep that path conservative; ordinary renderable removal
1038
- // can be addressed directly by the projection owner.
1039
- if (wasCamera || !entry.projection.has(renderWorldId, entity)) {
1040
- if (wasCamera) requiresRebuild = true;
1041
- continue;
1042
- }
1043
- if (!removalIdentities.has(identity)) {
1044
- const liveRecord = entry.projection.record(renderWorldId, entity);
1045
- operations.push({
1046
- kind: 'remove',
1047
- worldId: renderWorldId,
1048
- entityKey: entity,
1049
- ...(liveRecord === undefined ? {} : { expectedGeneration: liveRecord.generation }),
1050
- });
1051
- removalIdentities.add(identity);
1052
- removalOperationCount += 1;
1053
- }
1054
- continue;
1055
- }
1056
- if (
1057
- record.component === Camera ||
1058
- record.component === DirectionalLight ||
1059
- record.component === PointLight ||
1060
- record.component === PointLightShadow ||
1061
- record.component === SpotLight ||
1062
- record.component === Skylight ||
1063
- record.component === Fog ||
1064
- record.component === SkyboxBackground ||
1065
- record.component === PostProcessParams ||
1066
- wasCamera
1067
- ) {
1068
- requiresRebuild = true;
1069
- break;
1070
- }
1071
- if (
1072
- (authoredTransform || record.component === Transform) &&
1073
- entry.projection.has(renderWorldId, entity)
1074
- ) {
1075
- const transform = world.get(record.entity, Transform);
1076
- if (!transform.ok) {
1077
- requiresRebuild = true;
1078
- break;
1079
- }
1080
- const liveRecord = entry.projection.record(renderWorldId, entity);
1081
- operations.push({
1082
- kind: 'update-transform',
1083
- worldId: renderWorldId,
1084
- entityKey: record.entity,
1085
- world: new Float32Array(transform.value.world),
1086
- ...(liveRecord === undefined ? {} : { expectedGeneration: liveRecord.generation }),
1087
- });
1088
- transformOperationCount += 1;
1089
- continue;
1090
- }
1091
- if (
1092
- refreshRenderable !== undefined &&
1093
- record.component !== ChildOf &&
1094
- record.component !== Visibility &&
1095
- record.component !== Skin
1096
- ) {
1097
- topologyEntities.set(identity, { world, worldId: renderWorldId, entity });
1098
- continue;
1099
- }
1100
- requiresRebuild = true;
1101
- break;
1102
- }
1103
- if (!requiresRebuild) {
1104
- for (const entity of derivedTransforms) {
1105
- const identity = `${renderWorldId}:${entity}`;
1106
- if (topologyEntities.has(identity)) continue;
1107
- if (entry.projection.has(renderWorldId, entity)) {
1108
- const transform = world.get(entity, Transform);
1109
- if (!transform.ok) {
1110
- requiresRebuild = true;
1111
- break;
1112
- }
1113
- const liveRecord = entry.projection.record(renderWorldId, entity);
1114
- operations.push({
1115
- kind: 'update-transform',
1116
- worldId: renderWorldId,
1117
- entityKey: entity,
1118
- world: new Float32Array(transform.value.world),
1119
- ...(liveRecord === undefined ? {} : { expectedGeneration: liveRecord.generation }),
1120
- });
1121
- transformOperationCount += 1;
1122
- continue;
1123
- }
1124
- if (
1125
- NON_RENDERABLE_TRANSFORM_CONSUMERS.some((component) =>
1126
- world.hasComponent(entity, component),
1127
- )
1128
- ) {
1129
- requiresRebuild = true;
1130
- break;
1131
- }
1132
- }
1133
- }
1134
- if (requiresRebuild) break;
1135
- entry.cursors[worldId] = changes.cursor;
1136
- entry.sharedRefEpochs[worldId] = shared.cursor;
1137
- }
1138
- if (requiresRebuild) {
1139
- return this.rebuildComposition(worlds, worldIds, owner, catalogEpoch, buildCandidateFrame);
1140
- }
1141
- if (refreshRenderable !== undefined && topologyEntities.size > 0) {
1142
- this.topologyEntitiesReconciled += topologyEntities.size;
1143
- for (const { world, worldId, entity } of topologyEntities.values()) {
1144
- const identity = `${worldId}:${entity}`;
1145
- const identities = topologyIdentitiesByWorld.get(worldId) ?? new Set<string>();
1146
- identities.add(identity);
1147
- topologyIdentitiesByWorld.set(worldId, identities);
1148
- const hasRenderableComponents =
1149
- world.hasComponent(entity, Transform) &&
1150
- world.hasComponent(entity, MeshFilter) &&
1151
- world.hasComponent(entity, MeshRenderer) &&
1152
- !world.hasComponent(entity, Disabled);
1153
- const extracted = hasRenderableComponents
1154
- ? (() => {
1155
- this.singleEntityExtractions += 1;
1156
- return refreshRenderable(world, worldId, entity, entry.candidateFrame);
1157
- })()
1158
- : undefined;
1159
- const liveRecord = entry.projection.record(worldId, entity);
1160
- if (extracted === undefined) {
1161
- if (liveRecord !== undefined && !removalIdentities.has(identity)) {
1162
- operations.push({
1163
- kind: 'remove',
1164
- worldId,
1165
- entityKey: entity,
1166
- expectedGeneration: liveRecord.generation,
1167
- });
1168
- removalIdentities.add(identity);
1169
- removalOperationCount += 1;
1170
- }
1171
- continue;
1172
- }
1173
- const snapshot =
1174
- extracted.snapshot.worldId === worldId
1175
- ? extracted.snapshot
1176
- : { ...extracted.snapshot, worldId };
1177
- operations.push({
1178
- kind: 'create',
1179
- snapshot,
1180
- ...(liveRecord === undefined ? {} : { expectedGeneration: liveRecord.generation }),
1181
- });
1182
- const dispatch = topologyDispatchByWorld.get(worldId) ?? [];
1183
- dispatch.push(...extracted.candidateDispatch);
1184
- topologyDispatchByWorld.set(worldId, dispatch);
1185
- }
1186
- }
1187
- if (topologyEntities.size > 0) {
1188
- const topologyIdentitySet = new Set(topologyEntities.keys());
1189
- for (let index = operations.length - 1; index >= 0; index -= 1) {
1190
- const operation = operations[index];
1191
- if (
1192
- operation?.kind === 'update-transform' &&
1193
- topologyIdentitySet.has(`${operation.worldId}:${operation.entityKey}`)
1194
- ) {
1195
- operations.splice(index, 1);
1196
- }
1197
- }
1198
- }
1199
- if (operations.length === 0) {
1200
- this.noChangeFrames += 1;
1201
- this.syncGpuOwner(entry.token, entry.projection);
1202
- return entry.visibleFrame;
1203
- }
1204
- const delta = entry.projection.apply(operations);
1205
- entry.topology.apply(delta);
1206
- this.syncGpuOwner(entry.token, entry.projection, delta);
1207
- const candidates = entry.projection.materialize();
1208
- let rebased = entry.candidateFrame;
1209
- for (const [worldId, dispatch] of topologyDispatchByWorld) {
1210
- rebased = rebaseCandidateDomain(rebased, candidates, {
1211
- worldId,
1212
- dispatch,
1213
- replaceIdentities: topologyIdentitiesByWorld.get(worldId) ?? new Set<string>(),
1214
- });
1215
- }
1216
- if (topologyDispatchByWorld.size === 0 && topologyEntities.size > 0) {
1217
- for (const [worldId, replaceIdentities] of topologyIdentitiesByWorld) {
1218
- rebased = rebaseCandidateDomain(rebased, candidates, {
1219
- worldId,
1220
- dispatch: [],
1221
- replaceIdentities,
1222
- });
1223
- }
1224
- }
1225
- entry.candidateFrame = { ...rebased, renderables: [...candidates] };
1226
- entry.visibleFrame = cullPersistentFrame(
1227
- entry.candidateFrame,
1228
- candidates,
1229
- this.options.collectShadowDebugCandidates?.() === true,
1230
- entry.projection,
1231
- );
1232
- this.deltaFrames += 1;
1233
- this.transformUpdates += transformOperationCount;
1234
- this.removals += removalOperationCount;
1235
- return entry.visibleFrame;
1236
- }
1237
-
1238
- invalidate(world?: World): void {
1239
- if (world !== undefined) this.entries.delete(world);
1240
- else if (this.lastWorld !== undefined) this.entries.delete(this.lastWorld);
1241
- this.composition = undefined;
1242
- this.lastResyncReason = 'explicit-invalidate';
1243
- this.lastResyncDetail = undefined;
1244
- }
1245
-
1246
- setGpuDrivenCoverage(world: World, key: string, ownsAll: boolean): void {
1247
- const entry = this.entries.get(world);
1248
- if (entry === undefined) return;
1249
- entry.gpuDrivenCoverageKey = key;
1250
- entry.gpuDrivenOwnsAll = ownsAll;
1251
- }
1252
-
1253
- setCompositionGpuDrivenCoverage(key: string, ownsAll: boolean): void {
1254
- const entry = this.composition;
1255
- if (entry === undefined) return;
1256
- entry.gpuDrivenCoverageKey = key;
1257
- entry.gpuDrivenOwnsAll = ownsAll;
1258
- }
1259
-
1260
- detach(world: World): void {
1261
- const detachedEntry = this.entries.get(world);
1262
- detachedEntry?.projection.reset([]);
1263
- this.entries.delete(world);
1264
- const worldId = this.worldIds.get(world);
1265
- if (worldId !== undefined) {
1266
- this.worldIds.delete(world);
1267
- this.worldsById.delete(worldId);
1268
- }
1269
- const detachedComposition = this.composition?.worlds.includes(world)
1270
- ? this.composition
1271
- : undefined;
1272
- if (detachedComposition !== undefined) this.composition = undefined;
1273
- if (this.fogLastKnownGood?.resourceOwner === worldId) {
1274
- this.fogCandidate = undefined;
1275
- this.fogLastKnownGood = undefined;
1276
- this.fogFailure = undefined;
1277
- this.fogFailureOwner = undefined;
1278
- this.fogReactive = false;
1279
- }
1280
- if (this.lastWorld === world) this.lastWorld = undefined;
1281
- if (this.gpuOwner !== world && this.gpuOwner !== detachedComposition?.token) return;
1282
- this.gpuScene?.dispose();
1283
- this.gpuScene = undefined;
1284
- this.gpuOwner = undefined;
1285
- this.gpuDevice = undefined;
1286
- this.gpuStatus = 'inactive';
1287
- }
1288
-
1289
- /** Drop only device-owned tables; the CPU projection remains the recovery authority. */
1290
- resetGpuForRecover(): void {
1291
- if (this.lastWorld !== undefined) {
1292
- const entry = this.entries.get(this.lastWorld);
1293
- if (entry !== undefined) entry.gpuDrivenOwnsAll = false;
1294
- }
1295
- if (this.composition !== undefined) this.composition.gpuDrivenOwnsAll = false;
1296
- this.gpuScene = undefined;
1297
- this.gpuOwner = undefined;
1298
- this.gpuDevice = undefined;
1299
- this.gpuStatus = this.options.getDevice === undefined ? 'inactive' : 'rebuild-pending';
1300
- }
1301
-
1302
- dispose(): void {
1303
- this.gpuScene?.dispose();
1304
- this.gpuScene = undefined;
1305
- this.gpuOwner = undefined;
1306
- this.gpuDevice = undefined;
1307
- this.gpuStatus = 'inactive';
1308
- this.composition = undefined;
1309
- this.fogCandidate = undefined;
1310
- this.fogLastKnownGood = undefined;
1311
- this.fogFailure = undefined;
1312
- this.fogFailureOwner = undefined;
1313
- this.fogReactive = false;
1314
- }
1315
-
1316
- inspect(world = this.lastWorld): PersistentRenderSceneInspection {
1317
- const entry = (world === undefined ? undefined : this.entries.get(world)) ?? this.composition;
1318
- return {
1319
- worldEntitiesScanned: this.worldEntitiesScanned,
1320
- fullRebuilds: this.fullRebuilds,
1321
- noChangeFrames: this.noChangeFrames,
1322
- deltaFrames: this.deltaFrames,
1323
- transformUpdates: this.transformUpdates,
1324
- materialUpdates: this.materialUpdates,
1325
- instanceUpdates: this.instanceUpdates,
1326
- cameraUpdates: this.cameraUpdates,
1327
- resourceUpdates: this.resourceUpdates,
1328
- topologyEntitiesReconciled: this.topologyEntitiesReconciled,
1329
- singleEntityExtractions: this.singleEntityExtractions,
1330
- removals: this.removals,
1331
- lastResyncReason: this.lastResyncReason,
1332
- lastResyncDetail: this.lastResyncDetail,
1333
- cursor: 'cursor' in (entry ?? {}) ? (entry as PersistentWorldEntry).cursor : undefined,
1334
- projectionRecords: entry?.projection.inspect().current.length ?? 0,
1335
- spatialIndex: entry?.projection.inspect().spatialIndex,
1336
- topology:
1337
- entry?.topology.inspect() ??
1338
- ({
1339
- revision: 0,
1340
- batchCount: 0,
1341
- candidateCount: 0,
1342
- rebuilds: 0,
1343
- patches: 0,
1344
- ineligible: 0,
1345
- } satisfies BatchTopologyInspection),
1346
- gpu: this.inspectGpu(),
1347
- fog: this.inspectFog(),
1348
- };
1349
- }
1350
-
1351
- /** Stage a resource-owner Fog candidate; publication waits for submit. */
1352
- stageFogCandidate(candidate: FogSelection): void {
1353
- this.fogCandidate = candidate;
1354
- this.fogFailure = undefined;
1355
- this.fogFailureOwner = undefined;
1356
- this.fogReactive = false;
1357
- }
1358
-
1359
- /** Return the accepted Fog payload for failed-candidate frame reuse. */
1360
- fogSnapshot(): FogSnapshot | undefined {
1361
- return this.fogLastKnownGood?.snapshot;
1362
- }
1363
-
1364
- /** Retain the previous accepted Fog when extraction or validation fails. */
1365
- stageFogFailure(failure: PersistentFogFailure): void {
1366
- this.fogCandidate = undefined;
1367
- this.fogFailure = failure.code;
1368
- this.fogFailureOwner = failure.resourceOwner;
1369
- this.fogReactive = false;
1370
- }
1371
-
1372
- /** Drop an unsubmitted candidate without mutating the accepted snapshot. */
1373
- discardFogCandidate(): void {
1374
- this.fogCandidate = undefined;
1375
- this.fogReactive = false;
1376
- }
1377
-
1378
- /** Commit the staged Fog candidate at the existing successful-submit seam. */
1379
- stageFogSubmission(): void {
1380
- const candidate = this.fogCandidate;
1381
- if (candidate === undefined) return;
1382
- const previous = this.fogLastKnownGood;
1383
- this.fogReactive =
1384
- previous === undefined || previous.snapshot?.revision !== candidate.snapshot?.revision;
1385
- this.fogLastKnownGood = candidate;
1386
- this.fogCandidate = undefined;
1387
- this.fogFailure = undefined;
1388
- this.fogFailureOwner = undefined;
1389
- }
1390
-
1391
- private inspectFog(): PersistentFogInspection {
1392
- const accepted = this.fogLastKnownGood;
1393
- return {
1394
- enabled: accepted?.snapshot !== undefined,
1395
- resourceOwner: accepted?.resourceOwner ?? this.fogFailureOwner,
1396
- entity: accepted?.entity as number | undefined,
1397
- revision: accepted?.snapshot?.revision,
1398
- reactive: this.fogReactive,
1399
- failure: this.fogFailure,
1400
- };
1401
- }
1402
-
1403
- gpuDrivenState(world = this.lastWorld): PersistentGpuDrivenState | undefined {
1404
- if (world === undefined || world !== this.gpuOwner || this.gpuScene === undefined) {
1405
- return undefined;
1406
- }
1407
- const entry = this.entries.get(world);
1408
- if (entry === undefined) return undefined;
1409
- return {
1410
- scene: this.gpuScene,
1411
- plan: entry.topology.plan(),
1412
- slots: entry.projection.slotsSnapshot(),
1413
- projection: entry.projection,
1414
- };
1415
- }
1416
-
1417
- compositionGpuDrivenState(): PersistentGpuDrivenState | undefined {
1418
- const entry = this.composition;
1419
- if (entry === undefined || this.gpuOwner !== entry.token || this.gpuScene === undefined) {
1420
- return undefined;
1421
- }
1422
- return {
1423
- scene: this.gpuScene,
1424
- plan: entry.topology.plan(),
1425
- slots: entry.projection.slotsSnapshot(),
1426
- projection: entry.projection,
1427
- };
1428
- }
1429
-
1430
- temporalProjection(worlds: readonly World[]): RenderSceneProjection | undefined {
1431
- if (worlds.length === 1) {
1432
- const world = worlds[0];
1433
- return world === undefined ? undefined : this.entries.get(world)?.projection;
1434
- }
1435
- const composition = this.composition;
1436
- if (
1437
- composition === undefined ||
1438
- composition.worlds.length !== worlds.length ||
1439
- composition.worlds.some((world, index) => world !== worlds[index])
1440
- ) {
1441
- return undefined;
1442
- }
1443
- return composition.projection;
1444
- }
1445
-
1446
- stageTemporalSubmission(delta: RenderSceneSubmissionDelta): void {
1447
- this.gpuScene?.stageSubmitted(delta);
1448
- this.stageFogSubmission();
1449
- }
1450
-
1451
- private inspectGpu(): PersistentGpuSceneInspection {
1452
- if (this.gpuStatus === 'resident' && this.gpuScene !== undefined) {
1453
- return { status: 'resident', ...this.gpuScene.inspect() };
1454
- }
1455
- if (this.gpuStatus === 'unsupported') {
1456
- return { status: 'unsupported', reason: 'storage-buffer-unavailable' };
1457
- }
1458
- if (this.gpuStatus === 'rebuild-pending') return { status: 'rebuild-pending' };
1459
- if (this.gpuStatus === 'error') return { status: 'error' };
1460
- return { status: 'inactive' };
1461
- }
1462
-
1463
- private rebuild(
1464
- world: World,
1465
- catalogEpoch: number,
1466
- buildCandidateFrame: () => ExtractedFrame,
1467
- reason: RenderSceneResyncReason,
1468
- detail?: string,
1469
- ): ExtractedFrame {
1470
- const worldId = this.attachWorld(world);
1471
- const previousEntry = this.entries.get(world);
1472
- const sourceCandidateFrame = this.remapWorldIds(buildCandidateFrame(), [worldId]);
1473
- const projectionCandidates =
1474
- sourceCandidateFrame.candidateRenderables ?? sourceCandidateFrame.renderables;
1475
- this.worldEntitiesScanned = projectionCandidates.length;
1476
- const projection = previousEntry?.projection ?? new RenderSceneProjection();
1477
- if (previousEntry === undefined) projection.reset(projectionCandidates);
1478
- else projection.replaceCurrent(projectionCandidates);
1479
- const topology = new BatchTopology();
1480
- topology.rebuild(projection.slotsSnapshot());
1481
- const candidates = projection.materialize();
1482
- const candidateFrame = {
1483
- ...rebaseCandidateDomain(sourceCandidateFrame, candidates),
1484
- renderables: [...candidates],
1485
- };
1486
- const visibleFrame = cullPersistentFrame(
1487
- candidateFrame,
1488
- candidates,
1489
- this.options.collectShadowDebugCandidates?.() === true,
1490
- projection,
1491
- );
1492
- const changeProjection = createWorldProjection(world, {
1493
- components: RENDER_RELEVANT_COMPONENTS,
1494
- });
1495
- this.entries.set(world, {
1496
- worldId,
1497
- projection,
1498
- topology,
1499
- candidateFrame,
1500
- visibleFrame,
1501
- changeProjection,
1502
- cursor: changeProjection.cursor,
1503
- catalogEpoch,
1504
- sharedRefEpoch: world.sharedRefs.getMutationEpoch(),
1505
- activeCameraEpoch: world.getResourceChange(ACTIVE_CAMERA_KEY)?.changed ?? 0,
1506
- cameraEntities: this.cameraEntities(world),
1507
- rigidOnly: candidates.every(
1508
- (renderable) => renderable.skin === undefined && renderable.morphWeights === undefined,
1509
- ),
1510
- gpuDrivenCoverageKey: undefined,
1511
- gpuDrivenOwnsAll: false,
1512
- });
1513
- this.syncGpu(world, projection, undefined, true);
1514
- this.fullRebuilds += 1;
1515
- this.lastResyncReason = reason;
1516
- this.lastResyncDetail = detail;
1517
- return visibleFrame;
1518
- }
1519
-
1520
- private rebuildComposition(
1521
- worlds: readonly World[],
1522
- worldIds: readonly number[],
1523
- owner: { readonly cameraOwner: number; readonly resourceOwner: number },
1524
- catalogEpoch: number,
1525
- buildCandidateFrame: () => ExtractedFrame,
1526
- ): ExtractedFrame {
1527
- const previousComposition = this.composition;
1528
- const canReuseProjection =
1529
- previousComposition !== undefined &&
1530
- previousComposition.cameraOwner === owner.cameraOwner &&
1531
- previousComposition.resourceOwner === owner.resourceOwner &&
1532
- previousComposition.worlds.length === worlds.length &&
1533
- previousComposition.worlds.every((world, index) => world === worlds[index]) &&
1534
- previousComposition.worldIds.every((worldId, index) => worldId === worldIds[index]);
1535
- const sourceCandidateFrame = this.remapWorldIds(buildCandidateFrame(), worldIds);
1536
- const projectionCandidates =
1537
- sourceCandidateFrame.candidateRenderables ?? sourceCandidateFrame.renderables;
1538
- this.worldEntitiesScanned = projectionCandidates.length;
1539
- const projection = canReuseProjection
1540
- ? previousComposition.projection
1541
- : new RenderSceneProjection();
1542
- if (canReuseProjection) projection.replaceCurrent(projectionCandidates);
1543
- else projection.reset(projectionCandidates);
1544
- const topology = new BatchTopology();
1545
- topology.rebuild(projection.slotsSnapshot());
1546
- const candidates = projection.materialize();
1547
- const candidateFrame = {
1548
- ...rebaseCandidateDomain(sourceCandidateFrame, candidates),
1549
- renderables: [...candidates],
1550
- };
1551
- const visibleFrame = cullPersistentFrame(
1552
- candidateFrame,
1553
- candidates,
1554
- this.options.collectShadowDebugCandidates?.() === true,
1555
- projection,
1556
- );
1557
- const token = {};
1558
- const changeProjections = worlds.map((world) =>
1559
- createWorldProjection(world, { components: RENDER_RELEVANT_COMPONENTS }),
1560
- );
1561
- const entry: PersistentCompositionEntry = {
1562
- token,
1563
- worlds: [...worlds],
1564
- worldIds: [...worldIds],
1565
- cameraOwner: owner.cameraOwner,
1566
- resourceOwner: owner.resourceOwner,
1567
- projection,
1568
- topology,
1569
- candidateFrame,
1570
- visibleFrame,
1571
- changeProjections,
1572
- cursors: changeProjections.map((projection) => projection.cursor),
1573
- sharedRefEpochs: worlds.map((world) => world.sharedRefs.getMutationEpoch()),
1574
- cameraEntities: worlds.map((world) => this.cameraEntities(world)),
1575
- catalogEpoch,
1576
- rigidOnly: candidates.every(
1577
- (renderable) => renderable.skin === undefined && renderable.morphWeights === undefined,
1578
- ),
1579
- gpuDrivenCoverageKey: undefined,
1580
- gpuDrivenOwnsAll: false,
1581
- };
1582
- this.composition = entry;
1583
- this.syncGpuOwner(token, projection, undefined, true);
1584
- this.fullRebuilds += 1;
1585
- this.lastResyncReason = 'attach';
1586
- return visibleFrame;
1587
- }
1588
-
1589
- private syncGpu(
1590
- world: World,
1591
- projection: RenderSceneProjection,
1592
- delta?: RenderSceneApplyResult,
1593
- full = false,
1594
- ): void {
1595
- this.syncGpuOwner(world, projection, delta, full);
1596
- }
1597
-
1598
- private syncGpuOwner(
1599
- owner: object,
1600
- projection: RenderSceneProjection,
1601
- delta?: RenderSceneApplyResult,
1602
- full = false,
1603
- ): void {
1604
- const acquired = this.acquireGpuScene(owner, projection);
1605
- if (acquired === undefined || acquired.rebuilt) return;
1606
- const result = full
1607
- ? acquired.scene.rebuild(projection)
1608
- : delta === undefined
1609
- ? acquired.scene.sync(projection, {
1610
- created: 0,
1611
- updated: 0,
1612
- removed: 0,
1613
- recreated: 0,
1614
- ignoredLateUpdates: 0,
1615
- createdSlots: [],
1616
- updatedSlots: [],
1617
- removedSlots: [],
1618
- recreatedSlots: [],
1619
- factDeltas: [],
1620
- diagnostics: [],
1621
- })
1622
- : acquired.scene.sync(projection, delta);
1623
- if (!result.ok) this.failGpu(result.error);
1624
- }
1625
-
1626
- private acquireGpuScene(
1627
- owner: object,
1628
- projection: RenderSceneProjection,
1629
- ): { readonly scene: GpuScene; readonly rebuilt: boolean } | undefined {
1630
- const getDevice = this.options.getDevice;
1631
- if (getDevice === undefined) return undefined;
1632
- const device = getDevice();
1633
- if (this.gpuDevice !== undefined && this.gpuDevice !== device) {
1634
- this.gpuScene = undefined;
1635
- this.gpuOwner = undefined;
1636
- this.gpuStatus = 'rebuild-pending';
1637
- }
1638
- if (this.gpuStatus === 'error' && this.gpuDevice === device) return undefined;
1639
- if (this.gpuStatus === 'unsupported' && this.gpuDevice === device) return undefined;
1640
- if (this.gpuScene !== undefined && this.gpuOwner === owner) {
1641
- return { scene: this.gpuScene, rebuilt: false };
1642
- }
1643
- if (this.gpuScene !== undefined) this.gpuScene.dispose();
1644
- this.gpuScene = undefined;
1645
- this.gpuOwner = undefined;
1646
- this.gpuDevice = device;
1647
- const created = GpuScene.create(device, Math.max(256, projection.inspect().slotCapacity));
1648
- if (!created.ok) {
1649
- this.failGpu(created.error);
1650
- return undefined;
1651
- }
1652
- if (created.value.status === 'unavailable') {
1653
- this.gpuStatus = 'unsupported';
1654
- return undefined;
1655
- }
1656
- const scene = created.value.scene;
1657
- const rebuilt = scene.rebuild(projection);
1658
- if (!rebuilt.ok) {
1659
- scene.dispose();
1660
- this.failGpu(rebuilt.error);
1661
- return undefined;
1662
- }
1663
- this.gpuScene = scene;
1664
- this.gpuOwner = owner;
1665
- this.gpuStatus = 'resident';
1666
- return { scene, rebuilt: true };
1667
- }
1668
-
1669
- private failGpu(error: RhiError): void {
1670
- this.gpuScene?.dispose();
1671
- this.gpuScene = undefined;
1672
- this.gpuOwner = undefined;
1673
- this.gpuStatus = 'error';
1674
- this.options.onGpuError?.(error);
1675
- }
1676
-
1677
- private cameraEntities(world: World): ReadonlySet<EntityHandle> {
1678
- const entities = new Set<EntityHandle>();
1679
- for (const row of world.query({ read: [Camera], with: [Transform] }).unwrap()) {
1680
- entities.add(row.entity as EntityHandle);
1681
- }
1682
- return entities;
1683
- }
1684
-
1685
- private attachWorld(world: World): number {
1686
- const attached = this.worldIds.get(world);
1687
- if (attached !== undefined) return attached;
1688
- if (this.nextWorldId >= 0x20_0000) {
1689
- throw new RangeError('renderer exhausted the 21-bit WorldRenderId space');
1690
- }
1691
- const worldId = this.nextWorldId;
1692
- this.nextWorldId += 1;
1693
- this.worldIds.set(world, worldId);
1694
- this.worldsById.set(worldId, world);
1695
- return worldId;
1696
- }
1697
-
1698
- private remapWorldIds(frame: ExtractedFrame, worldIds: readonly number[]): ExtractedFrame {
1699
- let changed = false;
1700
- const cameras = frame.cameras.map((camera) => {
1701
- const worldId = worldIds[camera.worldId];
1702
- if (worldId === undefined) {
1703
- throw new RangeError(`camera references unattached world index ${camera.worldId}`);
1704
- }
1705
- if (worldId === camera.worldId) return camera;
1706
- changed = true;
1707
- return { ...camera, worldId };
1708
- });
1709
- const renderables = frame.renderables.map((renderable) => {
1710
- const worldId = worldIds[renderable.worldId];
1711
- if (worldId === undefined) {
1712
- throw new RangeError(`renderable references unattached world index ${renderable.worldId}`);
1713
- }
1714
- if (worldId === renderable.worldId) return renderable;
1715
- changed = true;
1716
- return { ...renderable, worldId };
1717
- });
1718
- const sourceCandidateRenderables =
1719
- frame.candidateDomain?.renderables ?? frame.candidateRenderables;
1720
- const candidateRenderables = sourceCandidateRenderables?.map((renderable) => {
1721
- const worldId = worldIds[renderable.worldId];
1722
- if (worldId === undefined) {
1723
- throw new RangeError(`candidate references unattached world index ${renderable.worldId}`);
1724
- }
1725
- if (worldId === renderable.worldId) return renderable;
1726
- changed = true;
1727
- return { ...renderable, worldId };
1728
- });
1729
- if (!changed) return frame;
1730
- if (frame.candidateDomain === undefined || candidateRenderables === undefined) {
1731
- return {
1732
- ...frame,
1733
- cameras,
1734
- renderables,
1735
- ...(candidateRenderables === undefined ? {} : { candidateRenderables }),
1736
- };
1737
- }
1738
- const candidateDomain = buildRenderCandidateDomain(
1739
- candidateRenderables,
1740
- frame.candidateDomain.dispatch,
1741
- );
1742
- return {
1743
- ...frame,
1744
- cameras,
1745
- renderables,
1746
- candidateRenderables: candidateDomain.renderables,
1747
- candidateDispatch: candidateDomain.dispatch,
1748
- candidateDispatchMembership: candidateDomain.membership,
1749
- candidateDomain,
1750
- };
1751
- }
1752
- }