@forgeax/engine-render 0.1.3 → 0.1.6

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 (918) hide show
  1. package/README.md +130 -641
  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 +207 -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 +1 -2
  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 +10 -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-QC4VW3XJ.mjs +79 -0
  54. package/dist/chunk-QC4VW3XJ.mjs.map +1 -0
  55. package/dist/chunk-SCRSAK5B.mjs +480 -0
  56. package/dist/chunk-SCRSAK5B.mjs.map +1 -0
  57. package/dist/components/__tests__/schema-contract.unit.test.d.ts +2 -0
  58. package/dist/components/__tests__/schema-contract.unit.test.d.ts.map +1 -0
  59. package/dist/components/glyph-text.d.ts +1 -1
  60. package/dist/components/glyph-text.d.ts.map +1 -1
  61. package/dist/components/index.d.ts +2 -2
  62. package/dist/components/index.d.ts.map +1 -1
  63. package/dist/components/instances.d.ts +1 -1
  64. package/dist/components/instances.d.ts.map +1 -1
  65. package/dist/components/light-helpers.d.ts +1 -1
  66. package/dist/components/light-helpers.d.ts.map +1 -1
  67. package/dist/components/mesh-filter.d.ts +7 -7
  68. package/dist/components/mesh-filter.d.ts.map +1 -1
  69. package/dist/components/scene-instance.d.ts +11 -11
  70. package/dist/components/skybox-background.d.ts +56 -0
  71. package/dist/components/skybox-background.d.ts.map +1 -0
  72. package/dist/components/skylight.d.ts +55 -0
  73. package/dist/components/skylight.d.ts.map +1 -0
  74. package/dist/components/sprite-animation.d.ts +2 -3
  75. package/dist/components/sprite-animation.d.ts.map +1 -1
  76. package/dist/components/sprite-instances.d.ts +1 -1
  77. package/dist/components/sprite-playback-mode.d.ts +6 -1
  78. package/dist/components/sprite-playback-mode.d.ts.map +1 -1
  79. package/dist/components/sprite-region-override.d.ts +2 -3
  80. package/dist/components/sprite-region-override.d.ts.map +1 -1
  81. package/dist/components/tile-layer.d.ts +5 -0
  82. package/dist/components/tile-layer.d.ts.map +1 -1
  83. package/dist/construct-renderer.d.ts +18 -1
  84. package/dist/construct-renderer.d.ts.map +1 -1
  85. package/dist/construct-renderer.mjs +27008 -4
  86. package/dist/construct-renderer.mjs.map +1 -1
  87. package/dist/debug-draw-glue.d.ts +2 -53
  88. package/dist/debug-draw-glue.d.ts.map +1 -1
  89. package/dist/device/device-scope.d.ts +83 -0
  90. package/dist/device/device-scope.d.ts.map +1 -0
  91. package/dist/{gpu-resource-store.d.ts → device/gpu-residency.d.ts} +91 -48
  92. package/dist/device/gpu-residency.d.ts.map +1 -0
  93. package/dist/device/resource-types.d.ts +8 -0
  94. package/dist/device/resource-types.d.ts.map +1 -0
  95. package/dist/engine-metrics.d.ts +2 -2
  96. package/dist/engine-metrics.d.ts.map +1 -1
  97. package/dist/errors/recover.d.ts +28 -1
  98. package/dist/errors/recover.d.ts.map +1 -1
  99. package/dist/errors/render.d.ts +249 -258
  100. package/dist/errors/render.d.ts.map +1 -1
  101. package/dist/features/fullscreen.d.ts +19 -0
  102. package/dist/features/fullscreen.d.ts.map +1 -0
  103. package/dist/features/host.d.ts +32 -26
  104. package/dist/features/host.d.ts.map +1 -1
  105. package/dist/features/morph/morph-feature.d.ts +39 -5
  106. package/dist/features/morph/morph-feature.d.ts.map +1 -1
  107. package/dist/features/plan.d.ts +182 -0
  108. package/dist/features/plan.d.ts.map +1 -0
  109. package/dist/features/prepared-gpu-work.d.ts +21 -17
  110. package/dist/features/prepared-gpu-work.d.ts.map +1 -1
  111. package/dist/features/prepared-graphics-store.d.ts +2 -1
  112. package/dist/features/prepared-graphics-store.d.ts.map +1 -1
  113. package/dist/features/prepared-graphics.d.ts +11 -21
  114. package/dist/features/prepared-graphics.d.ts.map +1 -1
  115. package/dist/features/render-graph-compute.d.ts +2 -2
  116. package/dist/features/render-graph-compute.d.ts.map +1 -1
  117. package/dist/features/render-graph-contribution.d.ts +4 -7
  118. package/dist/features/render-graph-contribution.d.ts.map +1 -1
  119. package/dist/features/render-graph-raster.d.ts +2 -2
  120. package/dist/features/render-graph-raster.d.ts.map +1 -1
  121. package/dist/features/render-graph-resources.d.ts +6 -6
  122. package/dist/features/render-graph-resources.d.ts.map +1 -1
  123. package/dist/features/targets.d.ts +5 -5
  124. package/dist/features/targets.d.ts.map +1 -1
  125. package/dist/features/types.d.ts +11 -190
  126. package/dist/features/types.d.ts.map +1 -1
  127. package/dist/features/vocabulary.d.ts +14 -0
  128. package/dist/features/vocabulary.d.ts.map +1 -0
  129. package/dist/fullscreen-post-process-pass.d.ts +4 -25
  130. package/dist/fullscreen-post-process-pass.d.ts.map +1 -1
  131. package/dist/glyph-text-layout-system.d.ts +3 -2
  132. package/dist/glyph-text-layout-system.d.ts.map +1 -1
  133. package/dist/gpu-driven/batch-topology.d.ts +6 -75
  134. package/dist/gpu-driven/batch-topology.d.ts.map +1 -1
  135. package/dist/gpu-driven/production-raster.d.ts +13 -112
  136. package/dist/gpu-driven/production-raster.d.ts.map +1 -1
  137. package/dist/gpu-driven/view-gpu.d.ts +10 -66
  138. package/dist/gpu-driven/view-gpu.d.ts.map +1 -1
  139. package/dist/gpu-resource.d.ts +3 -3
  140. package/dist/gpu-scene-schema.d.ts +1 -94
  141. package/dist/gpu-scene-schema.d.ts.map +1 -1
  142. package/dist/gpu-scene.d.ts +7 -33
  143. package/dist/gpu-scene.d.ts.map +1 -1
  144. package/dist/hdrp-buffers.d.ts +3 -53
  145. package/dist/hdrp-buffers.d.ts.map +1 -1
  146. package/dist/ibl/IblPipelineCache.d.ts +74 -180
  147. package/dist/ibl/IblPipelineCache.d.ts.map +1 -1
  148. package/dist/ibl/skylight-bind-group.d.ts +1 -1
  149. package/dist/index.d.ts +13 -43
  150. package/dist/index.d.ts.map +1 -1
  151. package/dist/index.mjs +165 -3
  152. package/dist/index.mjs.map +1 -1
  153. package/dist/inspection-types.d.ts +69 -0
  154. package/dist/inspection-types.d.ts.map +1 -0
  155. package/dist/instance-buffer-cache.d.ts +1 -4
  156. package/dist/instance-buffer-cache.d.ts.map +1 -1
  157. package/dist/internal.d.ts +1 -73
  158. package/dist/internal.d.ts.map +1 -1
  159. package/dist/internal.mjs +1 -43
  160. package/dist/internal.mjs.map +1 -1
  161. package/dist/lifecycle.d.ts +36 -2
  162. package/dist/lifecycle.d.ts.map +1 -1
  163. package/dist/materials.d.ts +0 -3
  164. package/dist/materials.d.ts.map +1 -1
  165. package/dist/mesh-material-bindings.d.ts +0 -1
  166. package/dist/mesh-material-bindings.d.ts.map +1 -1
  167. package/dist/pbr-pipeline.d.ts +75 -29
  168. package/dist/pbr-pipeline.d.ts.map +1 -1
  169. package/dist/pipeline/standard-forward-lane.d.ts +5 -0
  170. package/dist/pipeline/standard-forward-lane.d.ts.map +1 -0
  171. package/dist/pipeline/standard-pipeline.d.ts +31 -0
  172. package/dist/pipeline/standard-pipeline.d.ts.map +1 -0
  173. package/dist/pipeline/standard-profile.d.ts +40 -0
  174. package/dist/pipeline/standard-profile.d.ts.map +1 -0
  175. package/dist/pipeline-builder.d.ts +3 -3
  176. package/dist/pipeline-builder.d.ts.map +1 -1
  177. package/dist/pipeline-spec-types.d.ts +24 -0
  178. package/dist/pipeline-spec-types.d.ts.map +1 -0
  179. package/dist/pipeline-spec.d.ts +16 -155
  180. package/dist/pipeline-spec.d.ts.map +1 -1
  181. package/dist/plugin.d.ts +1 -14
  182. package/dist/plugin.d.ts.map +1 -1
  183. package/dist/post-process-errors.d.ts +18 -18
  184. package/dist/post-process-errors.d.ts.map +1 -1
  185. package/dist/prepare/prepared-graphics-resolver.d.ts +2 -5
  186. package/dist/prepare/prepared-graphics-resolver.d.ts.map +1 -1
  187. package/dist/record/__tests__/typed-frame-graph-plan.unit.test.d.ts +2 -0
  188. package/dist/record/__tests__/typed-frame-graph-plan.unit.test.d.ts.map +1 -0
  189. package/dist/record/frame-lighting.d.ts +7 -73
  190. package/dist/record/frame-lighting.d.ts.map +1 -1
  191. package/dist/record/frame-snapshot.d.ts +44 -44
  192. package/dist/record/frame-snapshot.d.ts.map +1 -1
  193. package/dist/record/frame-targets.d.ts +5 -38
  194. package/dist/record/frame-targets.d.ts.map +1 -1
  195. package/dist/record/frame.d.ts +64 -52
  196. package/dist/record/frame.d.ts.map +1 -1
  197. package/dist/record/helpers.d.ts +3 -2
  198. package/dist/record/helpers.d.ts.map +1 -1
  199. package/dist/record/main-pass-geometry.d.ts +5 -4
  200. package/dist/record/main-pass-geometry.d.ts.map +1 -1
  201. package/dist/record/main-pass-material.d.ts +90 -59
  202. package/dist/record/main-pass-material.d.ts.map +1 -1
  203. package/dist/record/main-pass-sprite-draws.d.ts +28 -3
  204. package/dist/record/main-pass-sprite-draws.d.ts.map +1 -1
  205. package/dist/record/main-pass.d.ts +1 -1
  206. package/dist/record/main-pass.d.ts.map +1 -1
  207. package/dist/record/mesh-ssbo.d.ts +276 -3
  208. package/dist/record/mesh-ssbo.d.ts.map +1 -1
  209. package/dist/record/render-context.d.ts +235 -0
  210. package/dist/record/render-context.d.ts.map +1 -0
  211. package/dist/record/shadow-pass.d.ts +15 -88
  212. package/dist/record/shadow-pass.d.ts.map +1 -1
  213. package/dist/record/skybox-post-pass.d.ts +1 -1
  214. package/dist/record/skybox-post-pass.d.ts.map +1 -1
  215. package/dist/record/typed-frame-graph.d.ts +29 -7
  216. package/dist/record/typed-frame-graph.d.ts.map +1 -1
  217. package/dist/record/view-ubo.d.ts +3 -3
  218. package/dist/record/view-ubo.d.ts.map +1 -1
  219. package/dist/render-contract.d.ts +416 -0
  220. package/dist/render-contract.d.ts.map +1 -0
  221. package/dist/render-data.d.ts.map +1 -1
  222. package/dist/render-graph-primitives.d.ts +14 -362
  223. package/dist/render-graph-primitives.d.ts.map +1 -1
  224. package/dist/render-pipeline.d.ts +25 -64
  225. package/dist/render-pipeline.d.ts.map +1 -1
  226. package/dist/render-system-extract.d.ts +107 -338
  227. package/dist/render-system-extract.d.ts.map +1 -1
  228. package/dist/render-system.d.ts +21 -713
  229. package/dist/render-system.d.ts.map +1 -1
  230. package/dist/scene/render-scene-types.d.ts +58 -0
  231. package/dist/scene/render-scene-types.d.ts.map +1 -0
  232. package/dist/scene/render-scene.d.ts +105 -0
  233. package/dist/scene/render-scene.d.ts.map +1 -0
  234. package/dist/scene-instances/post-spawn-resolve-joints.d.ts +2 -5
  235. package/dist/scene-instances/post-spawn-resolve-joints.d.ts.map +1 -1
  236. package/dist/ssao-buffers.d.ts +22 -3
  237. package/dist/ssao-buffers.d.ts.map +1 -1
  238. package/dist/systems/skin-palette-allocator.d.ts +2 -4
  239. package/dist/systems/skin-palette-allocator.d.ts.map +1 -1
  240. package/dist/systems/skin-palette-types.d.ts +14 -0
  241. package/dist/systems/skin-palette-types.d.ts.map +1 -0
  242. package/dist/systems/transparent-sort-config.d.ts +23 -2
  243. package/dist/systems/transparent-sort-config.d.ts.map +1 -1
  244. package/dist/tilemap-chunk-extract-system.d.ts +4 -3
  245. package/dist/tilemap-chunk-extract-system.d.ts.map +1 -1
  246. package/dist/typed-render-graph-primitives.d.ts +2 -4
  247. package/dist/typed-render-graph-primitives.d.ts.map +1 -1
  248. package/dist/typed-shadow-passes.d.ts +3 -3
  249. package/dist/typed-shadow-passes.d.ts.map +1 -1
  250. package/package.json +23 -23
  251. package/src/__tests__/backend-selection-rhi-capture.test-d.ts +1 -1
  252. package/src/__tests__/callback-inference.test-d.ts +6 -3
  253. package/src/__tests__/cluster-grid-default-surface.unit.test.ts +7 -4
  254. package/src/__tests__/construct-renderer-identity.unit.test.ts +15 -2
  255. package/src/__tests__/device-scope-lifecycle.unit.test.ts +151 -0
  256. package/src/__tests__/device-scope-stale-matrix.unit.test.ts +42 -0
  257. package/src/__tests__/direct-extract-consumer-contract.test-d.ts +8 -19
  258. package/src/__tests__/direct-light-snapshot.unit.test.ts +3 -13
  259. package/src/__tests__/factory-contract.integration.test.ts +158 -209
  260. package/src/__tests__/fallback-row-stride-surface.unit.test.ts +1 -4
  261. package/src/__tests__/frame-observation.contract.test.ts +17 -8
  262. package/src/__tests__/fullscreen-feature-plan.unit.test.ts +32 -0
  263. package/src/__tests__/glyph-text-layout-recovery.unit.test.ts +6 -11
  264. package/src/__tests__/gpu-driven-indirect-raster-evidence.ts +9 -16
  265. package/src/__tests__/gpu-driven-production.integration.test.ts +32 -205
  266. package/src/__tests__/gpu-driven-scaling.unit.test.ts +4 -7
  267. package/src/__tests__/gpu-driven-view-gpu-evidence.ts +87 -8
  268. package/src/__tests__/gpu-driven-view-graph.integration.test.ts +170 -8
  269. package/src/{gpu-driven/view-reference.ts → __tests__/gpu-driven-view-reference.ts} +4 -3
  270. package/src/__tests__/gpu-driven-view.browser.test.ts +12 -1
  271. package/src/__tests__/gpu-driven-view.dawn.test.ts +12 -1
  272. package/src/__tests__/gpu-driven-view.unit.test.ts +11 -267
  273. package/src/__tests__/gpu-resource-store-stride.unit.test.ts +3 -3
  274. package/src/__tests__/gpu-scene-render-graph-gpu.ts +2 -3
  275. package/src/__tests__/gpu-scene.dawn.test.ts +2 -6
  276. package/src/__tests__/gpu-scene.unit.test.ts +10 -24
  277. package/src/__tests__/ibl/face-uniforms.unit.test.ts +46 -0
  278. package/src/__tests__/infinite-grid-no-vertex-probe.unit.test.ts +34 -66
  279. package/src/__tests__/ktx2-basis-gpu-consumer.dawn.test.ts +14 -5
  280. package/src/__tests__/light-buffer-layout.unit.test.ts +4 -49
  281. package/src/__tests__/material-cooked-projection.unit.test.ts +2 -51
  282. package/src/__tests__/material-snapshot-mutation.integration.test.ts +10 -15
  283. package/src/__tests__/material-static-dynamic-route.unit.test.ts +4 -23
  284. package/src/__tests__/material-stride-surface.unit.test.ts +2 -2
  285. package/src/__tests__/mesh-buffer-usage-surface.unit.test.ts +7 -8
  286. package/src/__tests__/morph-culling-reentry.dawn.test.ts +29 -38
  287. package/src/__tests__/morph-feature-gpu-work.integration.test.ts +45 -43
  288. package/src/__tests__/morph-feature-plan.unit.test.ts +53 -0
  289. package/src/__tests__/morph-visual-evidence.integration.test.ts +47 -33
  290. package/src/__tests__/nineslice-handle-surface.unit.test.ts +11 -6
  291. package/src/__tests__/post-process-error-policy-owner.unit.test.ts +6 -13
  292. package/src/__tests__/prepared-graphics-capability.unit.test.ts +6 -81
  293. package/src/__tests__/prepared-graphics-generation.unit.test.ts +3 -17
  294. package/src/__tests__/prepared-graphics-lifecycle.unit.test.ts +6 -74
  295. package/src/__tests__/prepared-graphics-resolver.unit.test.ts +1 -3
  296. package/src/__tests__/prepared-graphics-snapshot.unit.test.ts +2 -2
  297. package/src/__tests__/profiler-default-off.test.ts +1 -1
  298. package/src/__tests__/profiler-phase-catalog.test.ts +2 -2
  299. package/src/__tests__/profiler-phase-integration.test.ts +5 -13
  300. package/src/__tests__/profiler-phase-token.test.ts +3 -8
  301. package/src/__tests__/public-surface.test-d.ts +65 -3
  302. package/src/__tests__/recover-error-policy-owner.unit.test.ts +1 -21
  303. package/src/__tests__/render-error-code-owner.test-d.ts +18 -23
  304. package/src/__tests__/render-error-detail-ssot.test-d.ts +0 -95
  305. package/src/__tests__/render-error-exhaustive.test-d.ts +8 -1
  306. package/src/__tests__/render-feature-assembly.test-d.ts +8 -16
  307. package/src/__tests__/render-feature-context.test-d.ts +16 -40
  308. package/src/__tests__/render-feature-contract.test-d.ts +9 -18
  309. package/src/__tests__/render-feature-diagnostics.unit.test.ts +6 -8
  310. package/src/__tests__/render-feature-docs.unit.test.ts +8 -7
  311. package/src/__tests__/render-feature-gpu-work.integration.test.ts +14 -75
  312. package/src/__tests__/render-feature-plan.test-d.ts +161 -0
  313. package/src/__tests__/render-feature-plan.unit.test.ts +170 -0
  314. package/src/__tests__/render-feature-prepared-diagnostics.unit.test.ts +8 -19
  315. package/src/__tests__/render-feature-prepared-errors.test-d.ts +3 -6
  316. package/src/__tests__/render-feature-prepared-graphics-docs.unit.test.ts +10 -71
  317. package/src/__tests__/render-feature-prepared-graphics-isolation.unit.test.ts +11 -61
  318. package/src/__tests__/render-feature-prepared-graphics-negative.test-d.ts +20 -43
  319. package/src/__tests__/render-feature-prepared-graphics.test-d.ts +56 -78
  320. package/src/__tests__/render-feature-public-surface.test-d.ts +6 -24
  321. package/src/__tests__/render-feature-retry.unit.test.ts +7 -48
  322. package/src/__tests__/render-feature-scheduling.unit.test.ts +15 -27
  323. package/src/__tests__/render-feature-stage-failed-policy-owner.unit.test.ts +0 -9
  324. package/src/__tests__/render-feature-stage-fault-recovery.unit.test.ts +19 -109
  325. package/src/__tests__/render-feature-visibility-context.test-d.ts +1 -6
  326. package/src/__tests__/render-feature-visibility-context.unit.test.ts +1 -2
  327. package/src/__tests__/render-feature-zero-work.unit.test.ts +14 -20
  328. package/src/__tests__/render-scene-projection.unit.test.ts +73 -111
  329. package/src/__tests__/renderer-factory-material-contract.unit.test.ts +46 -50
  330. package/src/__tests__/renderer-lifecycle.integration.test.ts +49 -1
  331. package/src/__tests__/shader-stage-surface.unit.test.ts +14 -9
  332. package/src/__tests__/ssao-config.unit.test.ts +36 -0
  333. package/src/__tests__/ssao-kernel-surface.unit.test.ts +4 -5
  334. package/src/__tests__/standard-clustered-pipeline.unit.test.ts +28 -0
  335. package/src/__tests__/standard-descriptors.test-d.ts +22 -0
  336. package/src/__tests__/standard-pipeline.dawn.test.ts +61 -0
  337. package/src/__tests__/standard-pipeline.integration.test.ts +124 -0
  338. package/src/__tests__/standard-profile-oracle.unit.test.ts +62 -0
  339. package/src/__tests__/surface-configuration.unit.test.ts +1 -2
  340. package/src/__tests__/texture-usage-surface.unit.test.ts +3 -6
  341. package/src/__tests__/typed-pipeline-topology.unit.test.ts +40 -206
  342. package/src/__tests__/urp-pipeline-targets.unit.test.ts +1 -11
  343. package/src/__tests__/urp-pipeline.unit.test.ts +2 -2
  344. package/src/__tests__/vertex-color-pipeline.unit.test.ts +10 -2
  345. package/src/__tests__/vertex-layout-consumer.unit.test.ts +1 -1
  346. package/src/__tests__/visibility-diagnostics.integration.test.ts +7 -11
  347. package/src/__tests__/visibility-extract.integration.test.ts +20 -11
  348. package/src/__tests__/visibility-extract.perf.test.ts +66 -32
  349. package/src/__tests__/visibility-feature-dedup.integration.test.ts +2 -4
  350. package/src/__tests__/visibility-hidden-report.unit.test.ts +1 -2
  351. package/src/__tests__/visibility-instances.integration.test.ts +7 -11
  352. package/src/__tests__/visibility-multi-world.integration.test.ts +38 -6
  353. package/src/__tests__/visibility-producer-matrix.integration.test.ts +18 -41
  354. package/src/__tests__/visibility-public-surface.test-d.ts +10 -9
  355. package/src/__tests__/visibility-resolver.unit.test.ts +2 -1
  356. package/src/__tests__/visibility-resource-short-circuit.unit.test.ts +80 -0
  357. package/src/__tests__/visibility-snapshot-contract.unit.test.ts +2 -1
  358. package/src/__tests__/vocabulary.unit.test.ts +1 -1
  359. package/src/assembly/backend-contract.ts +57 -0
  360. package/src/{renderer/renderer-factory.ts → assembly/factory.ts} +1709 -2693
  361. package/src/assembly/host-contract.ts +101 -0
  362. package/src/{renderer → assembly}/material/assembly.ts +1 -3
  363. package/src/assembly/material/pipeline-projection.ts +63 -0
  364. package/src/authoring.ts +14 -22
  365. package/src/components/__tests__/schema-contract.unit.test.ts +10 -0
  366. package/src/components/glyph-text.ts +3 -2
  367. package/src/components/index.ts +7 -9
  368. package/src/components/instances.ts +4 -5
  369. package/src/components/light-helpers.ts +1 -1
  370. package/src/components/mesh-filter.ts +11 -10
  371. package/src/components/post-process-params.ts +3 -3
  372. package/src/components/scene-instance.ts +12 -12
  373. package/src/components/skybox-background.ts +103 -0
  374. package/src/components/{environment.ts → skylight.ts} +2 -111
  375. package/src/components/sprite-animation.ts +3 -4
  376. package/src/components/sprite-instances.ts +2 -2
  377. package/src/components/sprite-playback-mode.ts +7 -1
  378. package/src/components/sprite-region-override.ts +2 -3
  379. package/src/components/tile-layer.ts +8 -2
  380. package/src/construct-renderer.ts +67 -4
  381. package/src/debug-draw-glue.ts +8 -129
  382. package/src/device/device-scope.ts +306 -0
  383. package/src/{gpu-resource-store.ts → device/gpu-residency.ts} +540 -639
  384. package/src/device/resource-types.ts +20 -0
  385. package/src/engine-metrics.ts +12 -19
  386. package/src/errors/recover.ts +45 -3
  387. package/src/errors/render.ts +357 -460
  388. package/src/features/fullscreen.ts +46 -0
  389. package/src/features/host.ts +575 -309
  390. package/src/features/morph/morph-feature.ts +195 -105
  391. package/src/features/plan.ts +447 -0
  392. package/src/features/prepared-gpu-work.ts +72 -15
  393. package/src/features/prepared-graphics-store.ts +20 -6
  394. package/src/features/prepared-graphics.ts +12 -71
  395. package/src/features/render-graph-compute.ts +14 -5
  396. package/src/features/render-graph-contribution.ts +43 -63
  397. package/src/features/render-graph-raster.ts +11 -6
  398. package/src/features/render-graph-resources.ts +25 -23
  399. package/src/features/targets.ts +8 -21
  400. package/src/features/types.ts +39 -227
  401. package/src/features/vocabulary.ts +24 -0
  402. package/src/fullscreen-post-process-pass.ts +14 -57
  403. package/src/glyph-text-layout-system.ts +70 -96
  404. package/src/gpu-driven/batch-topology.ts +24 -202
  405. package/src/gpu-driven/production-raster.ts +93 -1108
  406. package/src/gpu-driven/view-gpu.ts +46 -192
  407. package/src/gpu-resource.ts +4 -4
  408. package/src/gpu-scene-schema.ts +11 -99
  409. package/src/gpu-scene.ts +231 -364
  410. package/src/hdrp-buffers.ts +12 -221
  411. package/src/ibl/IblPipelineCache.ts +471 -711
  412. package/src/ibl/skylight-bind-group.ts +4 -4
  413. package/src/index.ts +58 -217
  414. package/src/inspection-types.ts +76 -0
  415. package/src/instance-buffer-cache.ts +1 -29
  416. package/src/internal.ts +6 -85
  417. package/src/lifecycle.ts +64 -19
  418. package/src/materials.ts +7 -29
  419. package/src/mesh-material-bindings.ts +0 -1
  420. package/src/pbr-pipeline.ts +434 -53
  421. package/src/{urp-pipeline.ts → pipeline/standard-forward-lane.ts} +38 -149
  422. package/src/{hdrp-pipeline.ts → pipeline/standard-pipeline.ts} +221 -191
  423. package/src/pipeline/standard-profile.ts +65 -0
  424. package/src/pipeline-builder.ts +60 -64
  425. package/src/pipeline-spec-types.ts +28 -0
  426. package/src/pipeline-spec.ts +72 -609
  427. package/src/plugin.ts +3 -75
  428. package/src/post-process-errors.ts +31 -33
  429. package/src/prepare/prepared-graphics-resolver.ts +5 -4
  430. package/src/record/__tests__/material-slot-plan.unit.test.ts +1 -33
  431. package/src/record/__tests__/typed-frame-graph-plan.unit.test.ts +41 -0
  432. package/src/record/__tests__/video-texture-view.unit.test.ts +1 -1
  433. package/src/record/frame-lighting.ts +74 -195
  434. package/src/record/frame-snapshot.ts +45 -60
  435. package/src/record/frame-targets.ts +8 -243
  436. package/src/record/frame.ts +509 -796
  437. package/src/record/helpers.ts +6 -11
  438. package/src/record/main-pass-geometry.ts +106 -147
  439. package/src/record/main-pass-material.ts +517 -190
  440. package/src/record/main-pass-sprite-draws.ts +198 -117
  441. package/src/record/main-pass.ts +162 -143
  442. package/src/record/mesh-ssbo.ts +517 -38
  443. package/src/record/render-context.ts +364 -0
  444. package/src/record/shadow-pass.ts +138 -1838
  445. package/src/record/skybox-post-pass.ts +12 -14
  446. package/src/record/typed-frame-graph.ts +215 -254
  447. package/src/record/view-ubo.ts +6 -37
  448. package/src/render-contract.ts +571 -0
  449. package/src/render-data.ts +3 -3
  450. package/src/render-graph-primitives.ts +76 -851
  451. package/src/render-pipeline.ts +104 -188
  452. package/src/render-system-extract.ts +1048 -1729
  453. package/src/render-system.ts +330 -1957
  454. package/src/scene/render-scene-types.ts +64 -0
  455. package/src/scene/render-scene.ts +1032 -0
  456. package/src/scene-instances/post-spawn-resolve-joints.ts +4 -7
  457. package/src/ssao-buffers.ts +167 -8
  458. package/src/systems/skin-palette-allocator.ts +21 -64
  459. package/src/systems/skin-palette-types.ts +14 -0
  460. package/src/systems/transparent-sort-config.ts +25 -3
  461. package/src/tilemap-chunk-extract-system.ts +53 -70
  462. package/src/typed-render-graph-primitives.ts +35 -24
  463. package/src/typed-shadow-passes.ts +26 -56
  464. package/dist/__tests__/analytic-sky-contract.test.d.ts +0 -2
  465. package/dist/__tests__/analytic-sky-contract.test.d.ts.map +0 -1
  466. package/dist/__tests__/analytic-sky-falsify.test.d.ts +0 -2
  467. package/dist/__tests__/analytic-sky-falsify.test.d.ts.map +0 -1
  468. package/dist/__tests__/assets-runtime-handoff.integration.test.d.ts +0 -2
  469. package/dist/__tests__/assets-runtime-handoff.integration.test.d.ts.map +0 -1
  470. package/dist/__tests__/backend-selection.integration.test.d.ts +0 -2
  471. package/dist/__tests__/backend-selection.integration.test.d.ts.map +0 -1
  472. package/dist/__tests__/camera-temporal.test-d.d.ts +0 -2
  473. package/dist/__tests__/camera-temporal.test-d.d.ts.map +0 -1
  474. package/dist/__tests__/camera-temporal.test.d.ts +0 -2
  475. package/dist/__tests__/camera-temporal.test.d.ts.map +0 -1
  476. package/dist/__tests__/directional-shadow-probe-atlas-layout.unit.test.d.ts +0 -2
  477. package/dist/__tests__/directional-shadow-probe-atlas-layout.unit.test.d.ts.map +0 -1
  478. package/dist/__tests__/environment-inspection.test.d.ts +0 -2
  479. package/dist/__tests__/environment-inspection.test.d.ts.map +0 -1
  480. package/dist/__tests__/fog-ai-user.fixture.d.ts +0 -2
  481. package/dist/__tests__/fog-ai-user.fixture.d.ts.map +0 -1
  482. package/dist/__tests__/fog-custom-render-feature.fixture.d.ts +0 -16
  483. package/dist/__tests__/fog-custom-render-feature.fixture.d.ts.map +0 -1
  484. package/dist/__tests__/fog-custom-render-feature.integration.test.d.ts +0 -2
  485. package/dist/__tests__/fog-custom-render-feature.integration.test.d.ts.map +0 -1
  486. package/dist/__tests__/fog-inspection.integration.test.d.ts +0 -2
  487. package/dist/__tests__/fog-inspection.integration.test.d.ts.map +0 -1
  488. package/dist/__tests__/fog-owner-state.integration.test.d.ts +0 -2
  489. package/dist/__tests__/fog-owner-state.integration.test.d.ts.map +0 -1
  490. package/dist/__tests__/fog-pipeline-topology.integration.test.d.ts +0 -2
  491. package/dist/__tests__/fog-pipeline-topology.integration.test.d.ts.map +0 -1
  492. package/dist/__tests__/fog-public-surface.integration.test.d.ts +0 -2
  493. package/dist/__tests__/fog-public-surface.integration.test.d.ts.map +0 -1
  494. package/dist/__tests__/fog-ray-contract.integration.test.d.ts +0 -2
  495. package/dist/__tests__/fog-ray-contract.integration.test.d.ts.map +0 -1
  496. package/dist/__tests__/fog-source-absence.integration.test.d.ts +0 -2
  497. package/dist/__tests__/fog-source-absence.integration.test.d.ts.map +0 -1
  498. package/dist/__tests__/fog-temporal.integration.test.d.ts +0 -2
  499. package/dist/__tests__/fog-temporal.integration.test.d.ts.map +0 -1
  500. package/dist/__tests__/frame-chain.unit.test.d.ts +0 -2
  501. package/dist/__tests__/frame-chain.unit.test.d.ts.map +0 -1
  502. package/dist/__tests__/gpu-scene-field-type-owner.test-d.d.ts +0 -2
  503. package/dist/__tests__/gpu-scene-field-type-owner.test-d.d.ts.map +0 -1
  504. package/dist/__tests__/hdrp-pipeline.unit.test.d.ts +0 -2
  505. package/dist/__tests__/hdrp-pipeline.unit.test.d.ts.map +0 -1
  506. package/dist/__tests__/ibl/ibl-fallback.unit.test.d.ts +0 -2
  507. package/dist/__tests__/ibl/ibl-fallback.unit.test.d.ts.map +0 -1
  508. package/dist/__tests__/material-derived-error-stop-draw.integration.test.d.ts +0 -2
  509. package/dist/__tests__/material-derived-error-stop-draw.integration.test.d.ts.map +0 -1
  510. package/dist/__tests__/material-derived-payload.integration.test.d.ts +0 -2
  511. package/dist/__tests__/material-derived-payload.integration.test.d.ts.map +0 -1
  512. package/dist/__tests__/materials.unit.test.d.ts +0 -2
  513. package/dist/__tests__/materials.unit.test.d.ts.map +0 -1
  514. package/dist/__tests__/param-schema-projection-census.unit.test.d.ts +0 -2
  515. package/dist/__tests__/param-schema-projection-census.unit.test.d.ts.map +0 -1
  516. package/dist/__tests__/persistent-render-scene.unit.test.d.ts +0 -2
  517. package/dist/__tests__/persistent-render-scene.unit.test.d.ts.map +0 -1
  518. package/dist/__tests__/pipeline-error-policy-owner.unit.test.d.ts +0 -2
  519. package/dist/__tests__/pipeline-error-policy-owner.unit.test.d.ts.map +0 -1
  520. package/dist/__tests__/pipeline-pass-trace.test.d.ts +0 -2
  521. package/dist/__tests__/pipeline-pass-trace.test.d.ts.map +0 -1
  522. package/dist/__tests__/pipeline-stage-owner.test-d.d.ts +0 -2
  523. package/dist/__tests__/pipeline-stage-owner.test-d.d.ts.map +0 -1
  524. package/dist/__tests__/plugin.test.d.ts +0 -2
  525. package/dist/__tests__/plugin.test.d.ts.map +0 -1
  526. package/dist/__tests__/prepared-graphics-backend-matrix.unit.test.d.ts +0 -2
  527. package/dist/__tests__/prepared-graphics-backend-matrix.unit.test.d.ts.map +0 -1
  528. package/dist/__tests__/prepared-graphics-resolver-recording.unit.test.d.ts +0 -2
  529. package/dist/__tests__/prepared-graphics-resolver-recording.unit.test.d.ts.map +0 -1
  530. package/dist/__tests__/public-pipeline-id.test-d.d.ts +0 -2
  531. package/dist/__tests__/public-pipeline-id.test-d.d.ts.map +0 -1
  532. package/dist/__tests__/render-dispatch-membership.unit.test.d.ts +0 -2
  533. package/dist/__tests__/render-dispatch-membership.unit.test.d.ts.map +0 -1
  534. package/dist/__tests__/render-feature-construction.unit.test.d.ts +0 -2
  535. package/dist/__tests__/render-feature-construction.unit.test.d.ts.map +0 -1
  536. package/dist/__tests__/render-feature-error-code-owner.test-d.d.ts +0 -2
  537. package/dist/__tests__/render-feature-error-code-owner.test-d.d.ts.map +0 -1
  538. package/dist/__tests__/render-feature-gpu-buffer-usage-owner.test-d.d.ts +0 -2
  539. package/dist/__tests__/render-feature-gpu-buffer-usage-owner.test-d.d.ts.map +0 -1
  540. package/dist/__tests__/render-feature-graph.integration.test.d.ts +0 -2
  541. package/dist/__tests__/render-feature-graph.integration.test.d.ts.map +0 -1
  542. package/dist/__tests__/render-feature-graphics-staging.unit.test.d.ts +0 -2
  543. package/dist/__tests__/render-feature-graphics-staging.unit.test.d.ts.map +0 -1
  544. package/dist/__tests__/render-feature-order.unit.test.d.ts +0 -2
  545. package/dist/__tests__/render-feature-order.unit.test.d.ts.map +0 -1
  546. package/dist/__tests__/render-feature-prepared-graphics-recording.unit.test.d.ts +0 -2
  547. package/dist/__tests__/render-feature-prepared-graphics-recording.unit.test.d.ts.map +0 -1
  548. package/dist/__tests__/render-feature-staging.unit.test.d.ts +0 -2
  549. package/dist/__tests__/render-feature-staging.unit.test.d.ts.map +0 -1
  550. package/dist/__tests__/renderer-render-scene-public.test-d.d.ts +0 -2
  551. package/dist/__tests__/renderer-render-scene-public.test-d.d.ts.map +0 -1
  552. package/dist/__tests__/scene-temporal-coverage.unit.test.d.ts +0 -2
  553. package/dist/__tests__/scene-temporal-coverage.unit.test.d.ts.map +0 -1
  554. package/dist/__tests__/sun-snapshot-consumers.test.d.ts +0 -2
  555. package/dist/__tests__/sun-snapshot-consumers.test.d.ts.map +0 -1
  556. package/dist/__tests__/surface-backend-kind-owner.test-d.d.ts +0 -2
  557. package/dist/__tests__/surface-backend-kind-owner.test-d.d.ts.map +0 -1
  558. package/dist/__tests__/taa-history-store.unit.test.d.ts +0 -2
  559. package/dist/__tests__/taa-history-store.unit.test.d.ts.map +0 -1
  560. package/dist/__tests__/temporal-frame-transaction.integration.test.d.ts +0 -2
  561. package/dist/__tests__/temporal-frame-transaction.integration.test.d.ts.map +0 -1
  562. package/dist/__tests__/temporal-inspection.unit.test.d.ts +0 -2
  563. package/dist/__tests__/temporal-inspection.unit.test.d.ts.map +0 -1
  564. package/dist/assets/__tests__/asset-decoders.unit.test.d.ts +0 -2
  565. package/dist/assets/__tests__/asset-decoders.unit.test.d.ts.map +0 -1
  566. package/dist/assets/__tests__/mipmap-generator.unit.test.d.ts +0 -2
  567. package/dist/assets/__tests__/mipmap-generator.unit.test.d.ts.map +0 -1
  568. package/dist/assets/__tests__/render-asset-port.unit.test.d.ts +0 -2
  569. package/dist/assets/__tests__/render-asset-port.unit.test.d.ts.map +0 -1
  570. package/dist/assets/__tests__/resolve-render-asset.unit.test.d.ts +0 -2
  571. package/dist/assets/__tests__/resolve-render-asset.unit.test.d.ts.map +0 -1
  572. package/dist/chunk-33UF5SAO.mjs +0 -7397
  573. package/dist/chunk-33UF5SAO.mjs.map +0 -1
  574. package/dist/chunk-A5QCJSNL.mjs +0 -29913
  575. package/dist/chunk-A5QCJSNL.mjs.map +0 -1
  576. package/dist/chunk-JMSB7AR4.mjs +0 -3
  577. package/dist/chunk-JMSB7AR4.mjs.map +0 -1
  578. package/dist/chunk-LXNGO6AO.mjs +0 -569
  579. package/dist/chunk-LXNGO6AO.mjs.map +0 -1
  580. package/dist/chunk-QRXPSX4X.mjs +0 -659
  581. package/dist/chunk-QRXPSX4X.mjs.map +0 -1
  582. package/dist/chunk-YAKEQPWO.mjs +0 -1439
  583. package/dist/chunk-YAKEQPWO.mjs.map +0 -1
  584. package/dist/components/__tests__/atmosphere-red.test.d.ts +0 -2
  585. package/dist/components/__tests__/atmosphere-red.test.d.ts.map +0 -1
  586. package/dist/components/__tests__/atmosphere.test.d.ts +0 -2
  587. package/dist/components/__tests__/atmosphere.test.d.ts.map +0 -1
  588. package/dist/components/__tests__/fog.test-d.d.ts +0 -2
  589. package/dist/components/__tests__/fog.test-d.d.ts.map +0 -1
  590. package/dist/components/__tests__/fog.test.d.ts +0 -2
  591. package/dist/components/__tests__/fog.test.d.ts.map +0 -1
  592. package/dist/components/atmosphere.d.ts +0 -18
  593. package/dist/components/atmosphere.d.ts.map +0 -1
  594. package/dist/components/environment.d.ts +0 -116
  595. package/dist/components/environment.d.ts.map +0 -1
  596. package/dist/deferred-lighting.d.ts +0 -13
  597. package/dist/deferred-lighting.d.ts.map +0 -1
  598. package/dist/dynamic-texture-store.d.ts +0 -42
  599. package/dist/dynamic-texture-store.d.ts.map +0 -1
  600. package/dist/environment/__tests__/failure-injection.test.d.ts +0 -2
  601. package/dist/environment/__tests__/failure-injection.test.d.ts.map +0 -1
  602. package/dist/environment/__tests__/generation-red.test.d.ts +0 -2
  603. package/dist/environment/__tests__/generation-red.test.d.ts.map +0 -1
  604. package/dist/environment/__tests__/generation.test.d.ts +0 -2
  605. package/dist/environment/__tests__/generation.test.d.ts.map +0 -1
  606. package/dist/environment/__tests__/graph-transaction.test.d.ts +0 -2
  607. package/dist/environment/__tests__/graph-transaction.test.d.ts.map +0 -1
  608. package/dist/environment/__tests__/inspection-red.test.d.ts +0 -2
  609. package/dist/environment/__tests__/inspection-red.test.d.ts.map +0 -1
  610. package/dist/environment/__tests__/lifecycle-evidence.test.d.ts +0 -2
  611. package/dist/environment/__tests__/lifecycle-evidence.test.d.ts.map +0 -1
  612. package/dist/environment/__tests__/pipeline-topology.test.d.ts +0 -2
  613. package/dist/environment/__tests__/pipeline-topology.test.d.ts.map +0 -1
  614. package/dist/environment/__tests__/readiness.test.d.ts +0 -2
  615. package/dist/environment/__tests__/readiness.test.d.ts.map +0 -1
  616. package/dist/environment/__tests__/recovery.test.d.ts +0 -2
  617. package/dist/environment/__tests__/recovery.test.d.ts.map +0 -1
  618. package/dist/environment/__tests__/resize-dispose.test.d.ts +0 -2
  619. package/dist/environment/__tests__/resize-dispose.test.d.ts.map +0 -1
  620. package/dist/environment/__tests__/signature-red.test.d.ts +0 -2
  621. package/dist/environment/__tests__/signature-red.test.d.ts.map +0 -1
  622. package/dist/environment/__tests__/signature.test.d.ts +0 -2
  623. package/dist/environment/__tests__/signature.test.d.ts.map +0 -1
  624. package/dist/environment/descriptors.d.ts +0 -2
  625. package/dist/environment/descriptors.d.ts.map +0 -1
  626. package/dist/environment/extracted-environment.d.ts +0 -53
  627. package/dist/environment/extracted-environment.d.ts.map +0 -1
  628. package/dist/environment/generation.d.ts +0 -62
  629. package/dist/environment/generation.d.ts.map +0 -1
  630. package/dist/environment/gpu-bundle.d.ts +0 -23
  631. package/dist/environment/gpu-bundle.d.ts.map +0 -1
  632. package/dist/environment/graph.d.ts +0 -108
  633. package/dist/environment/graph.d.ts.map +0 -1
  634. package/dist/environment/inspection.d.ts +0 -48
  635. package/dist/environment/inspection.d.ts.map +0 -1
  636. package/dist/environment/lifecycle.d.ts +0 -22
  637. package/dist/environment/lifecycle.d.ts.map +0 -1
  638. package/dist/environment/readiness.d.ts +0 -29
  639. package/dist/environment/readiness.d.ts.map +0 -1
  640. package/dist/environment/signature.d.ts +0 -70
  641. package/dist/environment/signature.d.ts.map +0 -1
  642. package/dist/extract/__tests__/directional-csm-domain.unit.test.d.ts +0 -2
  643. package/dist/extract/__tests__/directional-csm-domain.unit.test.d.ts.map +0 -1
  644. package/dist/extract/__tests__/environment-source.test.d.ts +0 -2
  645. package/dist/extract/__tests__/environment-source.test.d.ts.map +0 -1
  646. package/dist/extract/__tests__/schema-readers.unit.test.d.ts +0 -2
  647. package/dist/extract/__tests__/schema-readers.unit.test.d.ts.map +0 -1
  648. package/dist/extract/directional-csm.d.ts +0 -129
  649. package/dist/extract/directional-csm.d.ts.map +0 -1
  650. package/dist/extract/index.d.ts +0 -5
  651. package/dist/extract/index.d.ts.map +0 -1
  652. package/dist/extract/material-interface.d.ts +0 -56
  653. package/dist/extract/material-interface.d.ts.map +0 -1
  654. package/dist/extract/schema-readers.d.ts +0 -20
  655. package/dist/extract/schema-readers.d.ts.map +0 -1
  656. package/dist/features/graph-contribution.d.ts +0 -64
  657. package/dist/features/graph-contribution.d.ts.map +0 -1
  658. package/dist/features/index.d.ts +0 -21
  659. package/dist/features/index.d.ts.map +0 -1
  660. package/dist/features/morph/index.d.ts +0 -3
  661. package/dist/features/morph/index.d.ts.map +0 -1
  662. package/dist/features/morph/morph-bounds.d.ts +0 -42
  663. package/dist/features/morph/morph-bounds.d.ts.map +0 -1
  664. package/dist/features/scene-temporal.d.ts +0 -45
  665. package/dist/features/scene-temporal.d.ts.map +0 -1
  666. package/dist/features/taa-resolve.d.ts +0 -21
  667. package/dist/features/taa-resolve.d.ts.map +0 -1
  668. package/dist/frame-chain.d.ts +0 -14
  669. package/dist/frame-chain.d.ts.map +0 -1
  670. package/dist/gpu-driven/view-reference.d.ts.map +0 -1
  671. package/dist/gpu-resource-store.d.ts.map +0 -1
  672. package/dist/hdrp-cluster-membership.d.ts +0 -2
  673. package/dist/hdrp-cluster-membership.d.ts.map +0 -1
  674. package/dist/hdrp-pipeline.d.ts +0 -36
  675. package/dist/hdrp-pipeline.d.ts.map +0 -1
  676. package/dist/ibl/cubemap-projection.d.ts +0 -23
  677. package/dist/ibl/cubemap-projection.d.ts.map +0 -1
  678. package/dist/ibl/face-uniforms.d.ts +0 -65
  679. package/dist/ibl/face-uniforms.d.ts.map +0 -1
  680. package/dist/mesh-update-errors.d.ts +0 -71
  681. package/dist/mesh-update-errors.d.ts.map +0 -1
  682. package/dist/mipmap-generator.d.ts +0 -39
  683. package/dist/mipmap-generator.d.ts.map +0 -1
  684. package/dist/param-schema-projection-census.d.ts +0 -18
  685. package/dist/param-schema-projection-census.d.ts.map +0 -1
  686. package/dist/persistent-render-scene.d.ts +0 -158
  687. package/dist/persistent-render-scene.d.ts.map +0 -1
  688. package/dist/pipeline/index.d.ts +0 -11
  689. package/dist/pipeline/index.d.ts.map +0 -1
  690. package/dist/pipeline-errors.d.ts +0 -110
  691. package/dist/pipeline-errors.d.ts.map +0 -1
  692. package/dist/prepare/__tests__/schema-readers.unit.test.d.ts +0 -2
  693. package/dist/prepare/__tests__/schema-readers.unit.test.d.ts.map +0 -1
  694. package/dist/prepare/index.d.ts +0 -4
  695. package/dist/prepare/index.d.ts.map +0 -1
  696. package/dist/prepare/schema-readers.d.ts +0 -11
  697. package/dist/prepare/schema-readers.d.ts.map +0 -1
  698. package/dist/record/__tests__/environment-record.test.d.ts +0 -2
  699. package/dist/record/__tests__/environment-record.test.d.ts.map +0 -1
  700. package/dist/record/__tests__/frame-targets.unit.test.d.ts +0 -2
  701. package/dist/record/__tests__/frame-targets.unit.test.d.ts.map +0 -1
  702. package/dist/record/__tests__/membership-timing.unit.test.d.ts +0 -2
  703. package/dist/record/__tests__/membership-timing.unit.test.d.ts.map +0 -1
  704. package/dist/record/__tests__/render-submission.integration.test.d.ts +0 -2
  705. package/dist/record/__tests__/render-submission.integration.test.d.ts.map +0 -1
  706. package/dist/record/__tests__/render-submission.perf.test.d.ts +0 -2
  707. package/dist/record/__tests__/render-submission.perf.test.d.ts.map +0 -1
  708. package/dist/record/__tests__/shadow-submit-mode.unit.test.d.ts +0 -2
  709. package/dist/record/__tests__/shadow-submit-mode.unit.test.d.ts.map +0 -1
  710. package/dist/record/__tests__/view-ubo-layout.unit.test.d.ts +0 -2
  711. package/dist/record/__tests__/view-ubo-layout.unit.test.d.ts.map +0 -1
  712. package/dist/record/frame-observation.d.ts +0 -38
  713. package/dist/record/frame-observation.d.ts.map +0 -1
  714. package/dist/record/index.d.ts +0 -15
  715. package/dist/record/index.d.ts.map +0 -1
  716. package/dist/record/main-pass-skin.d.ts +0 -46
  717. package/dist/record/main-pass-skin.d.ts.map +0 -1
  718. package/dist/record/main-pass-sprite.d.ts +0 -69
  719. package/dist/record/main-pass-sprite.d.ts.map +0 -1
  720. package/dist/record/material-payload.d.ts +0 -43
  721. package/dist/record/material-payload.d.ts.map +0 -1
  722. package/dist/record/material-slot-plan.d.ts +0 -26
  723. package/dist/record/material-slot-plan.d.ts.map +0 -1
  724. package/dist/record/membership-timing.d.ts +0 -232
  725. package/dist/record/membership-timing.d.ts.map +0 -1
  726. package/dist/record/shadow-caster-uniform.d.ts +0 -8
  727. package/dist/record/shadow-caster-uniform.d.ts.map +0 -1
  728. package/dist/record/shadow-submit-mode.d.ts +0 -66
  729. package/dist/record/shadow-submit-mode.d.ts.map +0 -1
  730. package/dist/render-dispatch-membership.d.ts +0 -47
  731. package/dist/render-dispatch-membership.d.ts.map +0 -1
  732. package/dist/render-pipeline-context.d.ts +0 -289
  733. package/dist/render-pipeline-context.d.ts.map +0 -1
  734. package/dist/render-pipeline-target.d.ts +0 -16
  735. package/dist/render-pipeline-target.d.ts.map +0 -1
  736. package/dist/render-scene-projection.d.ts +0 -174
  737. package/dist/render-scene-projection.d.ts.map +0 -1
  738. package/dist/render-system-fold.d.ts +0 -266
  739. package/dist/render-system-fold.d.ts.map +0 -1
  740. package/dist/renderer/asset-service.d.ts +0 -10
  741. package/dist/renderer/asset-service.d.ts.map +0 -1
  742. package/dist/renderer/backend-selection.d.ts.map +0 -1
  743. package/dist/renderer/environment-classify.d.ts +0 -6
  744. package/dist/renderer/environment-classify.d.ts.map +0 -1
  745. package/dist/renderer/environment-error.d.ts +0 -13
  746. package/dist/renderer/environment-error.d.ts.map +0 -1
  747. package/dist/renderer/material/pipeline-projection.d.ts +0 -91
  748. package/dist/renderer/material/pipeline-projection.d.ts.map +0 -1
  749. package/dist/renderer/renderer-factory.d.ts +0 -283
  750. package/dist/renderer/renderer-factory.d.ts.map +0 -1
  751. package/dist/renderer.d.ts +0 -771
  752. package/dist/renderer.d.ts.map +0 -1
  753. package/dist/scene-utils/collect-subtree.d.ts +0 -11
  754. package/dist/scene-utils/collect-subtree.d.ts.map +0 -1
  755. package/dist/ssao-data.d.ts +0 -34
  756. package/dist/ssao-data.d.ts.map +0 -1
  757. package/dist/surface-format.d.ts +0 -10
  758. package/dist/surface-format.d.ts.map +0 -1
  759. package/dist/taa-history-store.d.ts +0 -88
  760. package/dist/taa-history-store.d.ts.map +0 -1
  761. package/dist/temporal-coverage.d.ts +0 -35
  762. package/dist/temporal-coverage.d.ts.map +0 -1
  763. package/dist/temporal-frame-transaction.d.ts +0 -92
  764. package/dist/temporal-frame-transaction.d.ts.map +0 -1
  765. package/dist/temporal-inspection.d.ts +0 -57
  766. package/dist/temporal-inspection.d.ts.map +0 -1
  767. package/dist/temporal-view.d.ts +0 -43
  768. package/dist/temporal-view.d.ts.map +0 -1
  769. package/dist/tilemap/resolve-tileset-runtime.d.ts +0 -23
  770. package/dist/tilemap/resolve-tileset-runtime.d.ts.map +0 -1
  771. package/dist/urp-pipeline.d.ts +0 -4
  772. package/dist/urp-pipeline.d.ts.map +0 -1
  773. package/src/__tests__/analytic-sky-contract.test.ts +0 -27
  774. package/src/__tests__/analytic-sky-falsify-carriers.mjs +0 -43
  775. package/src/__tests__/analytic-sky-falsify.test.ts +0 -94
  776. package/src/__tests__/assets-runtime-handoff.integration.test.ts +0 -36
  777. package/src/__tests__/backend-selection.integration.test.ts +0 -11
  778. package/src/__tests__/camera-temporal.test-d.ts +0 -8
  779. package/src/__tests__/camera-temporal.test.ts +0 -188
  780. package/src/__tests__/directional-shadow-probe-atlas-layout.unit.test.ts +0 -18
  781. package/src/__tests__/environment-inspection.test.ts +0 -45
  782. package/src/__tests__/fog-ai-user.fixture.ts +0 -350
  783. package/src/__tests__/fog-custom-render-feature.fixture.ts +0 -33
  784. package/src/__tests__/fog-custom-render-feature.integration.test.ts +0 -76
  785. package/src/__tests__/fog-inspection.integration.test.ts +0 -127
  786. package/src/__tests__/fog-owner-state.integration.test.ts +0 -112
  787. package/src/__tests__/fog-pipeline-topology.integration.test.ts +0 -93
  788. package/src/__tests__/fog-public-surface.integration.test.ts +0 -60
  789. package/src/__tests__/fog-ray-contract.integration.test.ts +0 -73
  790. package/src/__tests__/fog-source-absence.integration.test.ts +0 -51
  791. package/src/__tests__/fog-temporal.integration.test.ts +0 -115
  792. package/src/__tests__/frame-chain.unit.test.ts +0 -26
  793. package/src/__tests__/gpu-scene-field-type-owner.test-d.ts +0 -27
  794. package/src/__tests__/hdrp-pipeline.unit.test.ts +0 -100
  795. package/src/__tests__/ibl/ibl-fallback.unit.test.ts +0 -23
  796. package/src/__tests__/material-derived-error-stop-draw.integration.test.ts +0 -69
  797. package/src/__tests__/material-derived-payload.integration.test.ts +0 -164
  798. package/src/__tests__/materials.unit.test.ts +0 -25
  799. package/src/__tests__/param-schema-projection-census.unit.test.ts +0 -40
  800. package/src/__tests__/persistent-render-scene.unit.test.ts +0 -1311
  801. package/src/__tests__/pipeline-error-policy-owner.unit.test.ts +0 -167
  802. package/src/__tests__/pipeline-pass-trace.test.ts +0 -92
  803. package/src/__tests__/pipeline-stage-owner.test-d.ts +0 -13
  804. package/src/__tests__/plugin.test.ts +0 -25
  805. package/src/__tests__/prepared-graphics-backend-matrix.unit.test.ts +0 -129
  806. package/src/__tests__/prepared-graphics-resolver-recording.unit.test.ts +0 -180
  807. package/src/__tests__/public-pipeline-id.test-d.ts +0 -6
  808. package/src/__tests__/render-dispatch-membership.unit.test.ts +0 -117
  809. package/src/__tests__/render-feature-construction.unit.test.ts +0 -124
  810. package/src/__tests__/render-feature-error-code-owner.test-d.ts +0 -27
  811. package/src/__tests__/render-feature-gpu-buffer-usage-owner.test-d.ts +0 -46
  812. package/src/__tests__/render-feature-graph.integration.test.ts +0 -205
  813. package/src/__tests__/render-feature-graphics-staging.unit.test.ts +0 -200
  814. package/src/__tests__/render-feature-order.unit.test.ts +0 -66
  815. package/src/__tests__/render-feature-prepared-graphics-recording.unit.test.ts +0 -107
  816. package/src/__tests__/render-feature-staging.unit.test.ts +0 -94
  817. package/src/__tests__/renderer-render-scene-public.test-d.ts +0 -27
  818. package/src/__tests__/scene-temporal-coverage.unit.test.ts +0 -259
  819. package/src/__tests__/sun-snapshot-consumers.test.ts +0 -35
  820. package/src/__tests__/surface-backend-kind-owner.test-d.ts +0 -42
  821. package/src/__tests__/taa-history-store.unit.test.ts +0 -196
  822. package/src/__tests__/temporal-frame-transaction.integration.test.ts +0 -537
  823. package/src/__tests__/temporal-inspection.unit.test.ts +0 -138
  824. package/src/assets/__tests__/asset-decoders.unit.test.ts +0 -92
  825. package/src/assets/__tests__/mipmap-generator.unit.test.ts +0 -52
  826. package/src/assets/__tests__/render-asset-port.unit.test.ts +0 -54
  827. package/src/assets/__tests__/resolve-render-asset.unit.test.ts +0 -47
  828. package/src/components/__tests__/atmosphere-red.test.ts +0 -51
  829. package/src/components/__tests__/atmosphere.test.ts +0 -79
  830. package/src/components/__tests__/fog.test-d.ts +0 -49
  831. package/src/components/__tests__/fog.test.ts +0 -60
  832. package/src/components/atmosphere.ts +0 -64
  833. package/src/deferred-lighting.ts +0 -92
  834. package/src/dynamic-texture-store.ts +0 -111
  835. package/src/environment/README.md +0 -76
  836. package/src/environment/__tests__/failure-injection.test.ts +0 -50
  837. package/src/environment/__tests__/generation-red.test.ts +0 -64
  838. package/src/environment/__tests__/generation.test.ts +0 -37
  839. package/src/environment/__tests__/graph-transaction.test.ts +0 -85
  840. package/src/environment/__tests__/inspection-red.test.ts +0 -53
  841. package/src/environment/__tests__/lifecycle-evidence.test.ts +0 -40
  842. package/src/environment/__tests__/pipeline-topology.test.ts +0 -33
  843. package/src/environment/__tests__/readiness.test.ts +0 -42
  844. package/src/environment/__tests__/recovery.test.ts +0 -62
  845. package/src/environment/__tests__/resize-dispose.test.ts +0 -30
  846. package/src/environment/__tests__/signature-red.test.ts +0 -45
  847. package/src/environment/__tests__/signature.test.ts +0 -60
  848. package/src/environment/descriptors.ts +0 -7
  849. package/src/environment/extracted-environment.ts +0 -239
  850. package/src/environment/generation.ts +0 -158
  851. package/src/environment/gpu-bundle.ts +0 -144
  852. package/src/environment/graph.ts +0 -588
  853. package/src/environment/inspection.ts +0 -107
  854. package/src/environment/lifecycle.ts +0 -124
  855. package/src/environment/readiness.ts +0 -76
  856. package/src/environment/signature.ts +0 -185
  857. package/src/extract/__tests__/directional-csm-domain.unit.test.ts +0 -391
  858. package/src/extract/__tests__/environment-source.test.ts +0 -105
  859. package/src/extract/__tests__/schema-readers.unit.test.ts +0 -16
  860. package/src/extract/directional-csm.ts +0 -959
  861. package/src/extract/index.ts +0 -10
  862. package/src/extract/material-interface.ts +0 -604
  863. package/src/extract/schema-readers.ts +0 -27
  864. package/src/features/graph-contribution.ts +0 -577
  865. package/src/features/index.ts +0 -100
  866. package/src/features/morph/index.ts +0 -24
  867. package/src/features/morph/morph-bounds.ts +0 -123
  868. package/src/features/scene-temporal.ts +0 -274
  869. package/src/features/taa-resolve.ts +0 -244
  870. package/src/frame-chain.ts +0 -21
  871. package/src/hdrp-cluster-membership.ts +0 -70
  872. package/src/ibl/cubemap-projection.ts +0 -60
  873. package/src/ibl/face-uniforms.ts +0 -150
  874. package/src/mesh-update-errors.ts +0 -113
  875. package/src/mipmap-generator.ts +0 -244
  876. package/src/param-schema-projection-census.ts +0 -73
  877. package/src/persistent-render-scene.ts +0 -1752
  878. package/src/pipeline/index.ts +0 -40
  879. package/src/pipeline-errors.ts +0 -172
  880. package/src/prepare/__tests__/schema-readers.unit.test.ts +0 -16
  881. package/src/prepare/index.ts +0 -8
  882. package/src/prepare/schema-readers.ts +0 -20
  883. package/src/record/__tests__/environment-record.test.ts +0 -35
  884. package/src/record/__tests__/frame-targets.unit.test.ts +0 -54
  885. package/src/record/__tests__/membership-timing.unit.test.ts +0 -524
  886. package/src/record/__tests__/render-submission.integration.test.ts +0 -76
  887. package/src/record/__tests__/render-submission.perf.test.ts +0 -141
  888. package/src/record/__tests__/shadow-submit-mode.unit.test.ts +0 -88
  889. package/src/record/__tests__/view-ubo-layout.unit.test.ts +0 -101
  890. package/src/record/frame-observation.ts +0 -122
  891. package/src/record/index.ts +0 -15
  892. package/src/record/main-pass-skin.ts +0 -51
  893. package/src/record/main-pass-sprite.ts +0 -166
  894. package/src/record/material-payload.ts +0 -292
  895. package/src/record/material-slot-plan.ts +0 -68
  896. package/src/record/membership-timing.ts +0 -1012
  897. package/src/record/shadow-caster-uniform.ts +0 -37
  898. package/src/record/shadow-submit-mode.ts +0 -277
  899. package/src/render-dispatch-membership.ts +0 -155
  900. package/src/render-pipeline-context.ts +0 -332
  901. package/src/render-pipeline-target.ts +0 -96
  902. package/src/render-scene-projection.ts +0 -1738
  903. package/src/render-system-fold.ts +0 -531
  904. package/src/renderer/asset-service.ts +0 -32
  905. package/src/renderer/backend-selection.ts +0 -121
  906. package/src/renderer/environment-classify.ts +0 -30
  907. package/src/renderer/environment-error.ts +0 -19
  908. package/src/renderer/material/pipeline-projection.ts +0 -140
  909. package/src/renderer.ts +0 -940
  910. package/src/scene-utils/collect-subtree.ts +0 -40
  911. package/src/ssao-data.ts +0 -106
  912. package/src/surface-format.ts +0 -37
  913. package/src/taa-history-store.ts +0 -429
  914. package/src/temporal-coverage.ts +0 -106
  915. package/src/temporal-frame-transaction.ts +0 -301
  916. package/src/temporal-inspection.ts +0 -194
  917. package/src/temporal-view.ts +0 -174
  918. 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
- }