@forgeax/engine-render 0.1.33 → 0.1.35

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 (624) hide show
  1. package/README.md +1062 -127
  2. package/dist/assembly/backend-contract.d.ts +2 -0
  3. package/dist/assembly/backend-contract.d.ts.map +1 -1
  4. package/dist/assembly/barrel-distortion-inspection.d.ts +3 -0
  5. package/dist/assembly/barrel-distortion-inspection.d.ts.map +1 -0
  6. package/dist/assembly/canvas-draw-guard.d.ts +3 -0
  7. package/dist/assembly/canvas-draw-guard.d.ts.map +1 -0
  8. package/dist/assembly/cloud-shadow-entry.d.ts +4 -0
  9. package/dist/assembly/cloud-shadow-entry.d.ts.map +1 -0
  10. package/dist/assembly/device-feature-admission.d.ts +2 -2
  11. package/dist/assembly/dynamic-geometry-host.d.ts +4 -1
  12. package/dist/assembly/dynamic-geometry-host.d.ts.map +1 -1
  13. package/dist/assembly/dynamic-geometry-runtime.d.ts +1 -1
  14. package/dist/assembly/dynamic-geometry-runtime.d.ts.map +1 -1
  15. package/dist/assembly/factory.d.ts +1 -1
  16. package/dist/assembly/factory.d.ts.map +1 -1
  17. package/dist/assembly/host-contract.d.ts +6 -5
  18. package/dist/assembly/host-contract.d.ts.map +1 -1
  19. package/dist/assembly/material/assembly.d.ts.map +1 -1
  20. package/dist/assembly/material/pipeline-helpers.d.ts +5 -0
  21. package/dist/assembly/material/pipeline-helpers.d.ts.map +1 -1
  22. package/dist/assembly/material-shader-policy.d.ts +16 -2
  23. package/dist/assembly/material-shader-policy.d.ts.map +1 -1
  24. package/dist/assembly/material-shader-prewarm.d.ts.map +1 -1
  25. package/dist/assembly/recovery/device-loss-fanout.d.ts.map +1 -1
  26. package/dist/assembly/recovery/renderer-recover.d.ts +2 -0
  27. package/dist/assembly/recovery/renderer-recover.d.ts.map +1 -1
  28. package/dist/assembly/render-feature-post-processes.d.ts +6 -0
  29. package/dist/assembly/render-feature-post-processes.d.ts.map +1 -0
  30. package/dist/assembly/render-target-host.d.ts +5 -0
  31. package/dist/assembly/render-target-host.d.ts.map +1 -1
  32. package/dist/assembly/renderer-facade.d.ts.map +1 -1
  33. package/dist/assembly/renderer-feature-inspection.d.ts +1 -1
  34. package/dist/assembly/renderer-feature-inspection.d.ts.map +1 -1
  35. package/dist/assembly/renderer-frame-transaction.d.ts +12 -0
  36. package/dist/assembly/renderer-frame-transaction.d.ts.map +1 -1
  37. package/dist/assembly/renderer-inspection.d.ts +11 -0
  38. package/dist/assembly/renderer-inspection.d.ts.map +1 -1
  39. package/dist/assembly/webgpu-pbr-ready.d.ts +1 -0
  40. package/dist/assembly/webgpu-pbr-ready.d.ts.map +1 -1
  41. package/dist/assembly/webgpu-ready-per-pass.d.ts +39 -0
  42. package/dist/assembly/webgpu-ready-per-pass.d.ts.map +1 -0
  43. package/dist/assembly/webgpu-ready.d.ts +1 -1
  44. package/dist/assembly/webgpu-ready.d.ts.map +1 -1
  45. package/dist/assembly/webgpu-renderer-bootstrap.d.ts.map +1 -1
  46. package/dist/assembly/webgpu-renderer-observation-owner.d.ts +35 -0
  47. package/dist/assembly/webgpu-renderer-observation-owner.d.ts.map +1 -0
  48. package/dist/assembly/webgpu-renderer.d.ts +2 -1
  49. package/dist/assembly/webgpu-renderer.d.ts.map +1 -1
  50. package/dist/authoring.mjs +2 -4
  51. package/dist/authoring.mjs.map +1 -1
  52. package/dist/barrel-distortion.d.ts +47 -0
  53. package/dist/barrel-distortion.d.ts.map +1 -0
  54. package/dist/chunk-3XUBWRY2.mjs +1842 -0
  55. package/dist/chunk-3XUBWRY2.mjs.map +1 -0
  56. package/dist/{chunk-OO3DRYK7.mjs → chunk-G6HDNGY7.mjs} +2400 -1767
  57. package/dist/chunk-G6HDNGY7.mjs.map +1 -0
  58. package/dist/{chunk-ZDQWGQW7.mjs → chunk-LM5IE7GF.mjs} +4 -4
  59. package/dist/{chunk-ZDQWGQW7.mjs.map → chunk-LM5IE7GF.mjs.map} +1 -1
  60. package/dist/{chunk-VOZWDM3L.mjs → chunk-LNIUIKQ7.mjs} +1514 -498
  61. package/dist/chunk-LNIUIKQ7.mjs.map +1 -0
  62. package/dist/chunk-MXTWKZO4.mjs +3268 -0
  63. package/dist/chunk-MXTWKZO4.mjs.map +1 -0
  64. package/dist/chunk-MZ4C7EHF.mjs +6942 -0
  65. package/dist/chunk-MZ4C7EHF.mjs.map +1 -0
  66. package/dist/chunk-RIPAEGI6.mjs +48 -0
  67. package/dist/chunk-RIPAEGI6.mjs.map +1 -0
  68. package/dist/{chunk-LEAXOMYJ.mjs → chunk-SGPUJW3F.mjs} +117 -5
  69. package/dist/chunk-SGPUJW3F.mjs.map +1 -0
  70. package/dist/{chunk-PA5DRJNI.mjs → chunk-X2KA6WHM.mjs} +29 -4
  71. package/dist/chunk-X2KA6WHM.mjs.map +1 -0
  72. package/dist/{chunk-BLXGONR2.mjs → chunk-XSFB7XXQ.mjs} +51 -4
  73. package/dist/chunk-XSFB7XXQ.mjs.map +1 -0
  74. package/dist/cloud/density.d.ts +55 -0
  75. package/dist/cloud/density.d.ts.map +1 -0
  76. package/dist/cloud/extract.d.ts +25 -0
  77. package/dist/cloud/extract.d.ts.map +1 -0
  78. package/dist/cloud/feature.d.ts +57 -0
  79. package/dist/cloud/feature.d.ts.map +1 -0
  80. package/dist/cloud/frame-context.d.ts +8 -0
  81. package/dist/cloud/frame-context.d.ts.map +1 -0
  82. package/dist/cloud/inspection.d.ts +59 -0
  83. package/dist/cloud/inspection.d.ts.map +1 -0
  84. package/dist/cloud/optics.d.ts +56 -0
  85. package/dist/cloud/optics.d.ts.map +1 -0
  86. package/dist/cloud/parameters.d.ts +73 -0
  87. package/dist/cloud/parameters.d.ts.map +1 -0
  88. package/dist/cloud/resources.d.ts +60 -0
  89. package/dist/cloud/resources.d.ts.map +1 -0
  90. package/dist/cloud/shadow.d.ts +42 -0
  91. package/dist/cloud/shadow.d.ts.map +1 -0
  92. package/dist/cloud/temporal.d.ts +74 -0
  93. package/dist/cloud/temporal.d.ts.map +1 -0
  94. package/dist/components/barrel-distortion.d.ts +13 -0
  95. package/dist/components/barrel-distortion.d.ts.map +1 -0
  96. package/dist/components/cloud-layer.d.ts +29 -0
  97. package/dist/components/cloud-layer.d.ts.map +1 -0
  98. package/dist/components/index.d.ts +2 -0
  99. package/dist/components/index.d.ts.map +1 -1
  100. package/dist/components/instances.d.ts +20 -6
  101. package/dist/components/instances.d.ts.map +1 -1
  102. package/dist/construct-renderer.d.ts +1 -1
  103. package/dist/construct-renderer.d.ts.map +1 -1
  104. package/dist/construct-renderer.mjs +8406 -5785
  105. package/dist/construct-renderer.mjs.map +1 -1
  106. package/dist/device/gpu-residency.d.ts +19 -19
  107. package/dist/device/gpu-residency.d.ts.map +1 -1
  108. package/dist/dynamic-geometry.d.ts +5 -1
  109. package/dist/dynamic-geometry.d.ts.map +1 -1
  110. package/dist/errors/cloud.d.ts +59 -0
  111. package/dist/errors/cloud.d.ts.map +1 -0
  112. package/dist/errors/render.d.ts +20 -5
  113. package/dist/errors/render.d.ts.map +1 -1
  114. package/dist/examples/single-layer-medium-surface.d.ts +47 -0
  115. package/dist/examples/single-layer-medium-surface.d.ts.map +1 -0
  116. package/dist/extract/camera.d.ts.map +1 -1
  117. package/dist/extract/contracts.d.ts +5 -1
  118. package/dist/extract/contracts.d.ts.map +1 -1
  119. package/dist/extract/material-context.d.ts +7 -0
  120. package/dist/extract/material-context.d.ts.map +1 -0
  121. package/dist/features/barrel-distortion.d.ts +29 -0
  122. package/dist/features/barrel-distortion.d.ts.map +1 -0
  123. package/dist/features/error-reporting.d.ts +6 -2
  124. package/dist/features/error-reporting.d.ts.map +1 -1
  125. package/dist/features/host.d.ts +15 -0
  126. package/dist/features/host.d.ts.map +1 -1
  127. package/dist/features/plan.d.ts +10 -0
  128. package/dist/features/plan.d.ts.map +1 -1
  129. package/dist/features/render-graph-contribution.d.ts +5 -0
  130. package/dist/features/render-graph-contribution.d.ts.map +1 -1
  131. package/dist/features/render-graph-raster.d.ts +1 -0
  132. package/dist/features/render-graph-raster.d.ts.map +1 -1
  133. package/dist/features/targets.d.ts +2 -0
  134. package/dist/features/targets.d.ts.map +1 -1
  135. package/dist/features/types.d.ts +48 -0
  136. package/dist/features/types.d.ts.map +1 -1
  137. package/dist/fullscreen-post-process-pass.d.ts +15 -7
  138. package/dist/fullscreen-post-process-pass.d.ts.map +1 -1
  139. package/dist/glyph-text-layout-system.d.ts +1 -1
  140. package/dist/glyph-text-layout-system.d.ts.map +1 -1
  141. package/dist/gpu-dirty-ranges.d.ts +11 -0
  142. package/dist/gpu-dirty-ranges.d.ts.map +1 -0
  143. package/dist/gpu-driven/batch-topology.d.ts +17 -0
  144. package/dist/gpu-driven/batch-topology.d.ts.map +1 -1
  145. package/dist/gpu-driven/material-artifacts.d.ts +6 -0
  146. package/dist/gpu-driven/material-artifacts.d.ts.map +1 -1
  147. package/dist/gpu-driven/prepared-draw.d.ts.map +1 -1
  148. package/dist/gpu-driven/production-raster-material.d.ts +178 -0
  149. package/dist/gpu-driven/production-raster-material.d.ts.map +1 -0
  150. package/dist/gpu-driven/production-raster.d.ts +47 -3
  151. package/dist/gpu-driven/production-raster.d.ts.map +1 -1
  152. package/dist/gpu-driven/resource-allocation.d.ts +31 -0
  153. package/dist/gpu-driven/resource-allocation.d.ts.map +1 -0
  154. package/dist/gpu-driven/shadow-ownership.d.ts +14 -0
  155. package/dist/gpu-driven/shadow-ownership.d.ts.map +1 -0
  156. package/dist/gpu-driven/view-gpu.d.ts +26 -2
  157. package/dist/gpu-driven/view-gpu.d.ts.map +1 -1
  158. package/dist/gpu-scene.d.ts +5 -0
  159. package/dist/gpu-scene.d.ts.map +1 -1
  160. package/dist/hdrp-buffers.d.ts +2 -2
  161. package/dist/hdrp-buffers.d.ts.map +1 -1
  162. package/dist/ibl/frame-resources.d.ts.map +1 -1
  163. package/dist/ibl/skylight-bind-group.d.ts +14 -5
  164. package/dist/ibl/skylight-bind-group.d.ts.map +1 -1
  165. package/dist/index.d.ts +30 -7
  166. package/dist/index.d.ts.map +1 -1
  167. package/dist/index.mjs +780 -9
  168. package/dist/index.mjs.map +1 -1
  169. package/dist/inspection-types.d.ts +135 -1
  170. package/dist/inspection-types.d.ts.map +1 -1
  171. package/dist/instance-buffer-cache.d.ts +4 -4
  172. package/dist/instance-buffer-cache.d.ts.map +1 -1
  173. package/dist/instances.d.ts +47 -100
  174. package/dist/instances.d.ts.map +1 -1
  175. package/dist/internal.mjs +7 -8
  176. package/dist/internal.mjs.map +1 -1
  177. package/dist/pbr-pipeline.d.ts +22 -4
  178. package/dist/pbr-pipeline.d.ts.map +1 -1
  179. package/dist/pipeline/single-layer-medium-passes.d.ts +73 -0
  180. package/dist/pipeline/single-layer-medium-passes.d.ts.map +1 -0
  181. package/dist/pipeline/standard-forward-lane.d.ts.map +1 -1
  182. package/dist/pipeline/standard-output/graph.d.ts.map +1 -1
  183. package/dist/pipeline/standard-output/lut-gpu.d.ts +2 -2
  184. package/dist/pipeline/standard-output/lut-gpu.d.ts.map +1 -1
  185. package/dist/pipeline/standard-output/resources.d.ts +2 -2
  186. package/dist/pipeline/standard-output/resources.d.ts.map +1 -1
  187. package/dist/pipeline/standard-output/types.d.ts +4 -2
  188. package/dist/pipeline/standard-output/types.d.ts.map +1 -1
  189. package/dist/pipeline/standard-pipeline.d.ts.map +1 -1
  190. package/dist/pipeline/standard-post.d.ts.map +1 -1
  191. package/dist/pipeline-builder.d.ts +1 -1
  192. package/dist/pipeline-builder.d.ts.map +1 -1
  193. package/dist/plugin.d.ts.map +1 -1
  194. package/dist/prepare/prepared-graphics-resolver.d.ts +2 -0
  195. package/dist/prepare/prepared-graphics-resolver.d.ts.map +1 -1
  196. package/dist/publication/contract.d.ts +77 -0
  197. package/dist/publication/contract.d.ts.map +1 -0
  198. package/dist/publication/dependencies.d.ts +7 -0
  199. package/dist/publication/dependencies.d.ts.map +1 -0
  200. package/dist/publication/prepare-geometry.d.ts +9 -0
  201. package/dist/publication/prepare-geometry.d.ts.map +1 -0
  202. package/dist/publication/programs.d.ts +5 -0
  203. package/dist/publication/programs.d.ts.map +1 -0
  204. package/dist/publication/publisher.d.ts +33 -0
  205. package/dist/publication/publisher.d.ts.map +1 -0
  206. package/dist/publication/receiver.d.ts +29 -0
  207. package/dist/publication/receiver.d.ts.map +1 -0
  208. package/dist/publication/resource-scope.d.ts +18 -0
  209. package/dist/publication/resource-scope.d.ts.map +1 -0
  210. package/dist/publication/targets.d.ts +33 -0
  211. package/dist/publication/targets.d.ts.map +1 -0
  212. package/dist/publication/video.d.ts +5 -0
  213. package/dist/publication/video.d.ts.map +1 -0
  214. package/dist/record/barrel-distortion-frame.d.ts +15 -0
  215. package/dist/record/barrel-distortion-frame.d.ts.map +1 -0
  216. package/dist/record/dynamic-geometry-consumption.d.ts +10 -2
  217. package/dist/record/dynamic-geometry-consumption.d.ts.map +1 -1
  218. package/dist/record/fold-buckets.d.ts +95 -0
  219. package/dist/record/fold-buckets.d.ts.map +1 -0
  220. package/dist/record/fold-instance-buffer.d.ts +6 -0
  221. package/dist/record/fold-instance-buffer.d.ts.map +1 -0
  222. package/dist/record/frame-lighting.d.ts +1 -0
  223. package/dist/record/frame-lighting.d.ts.map +1 -1
  224. package/dist/record/frame-snapshot.d.ts +43 -9
  225. package/dist/record/frame-snapshot.d.ts.map +1 -1
  226. package/dist/record/frame.d.ts +15 -65
  227. package/dist/record/frame.d.ts.map +1 -1
  228. package/dist/record/gpu-draw-receipts.d.ts +11 -0
  229. package/dist/record/gpu-draw-receipts.d.ts.map +1 -0
  230. package/dist/record/gpu-timing.d.ts +8 -0
  231. package/dist/record/gpu-timing.d.ts.map +1 -1
  232. package/dist/record/helpers.d.ts +2 -2
  233. package/dist/record/helpers.d.ts.map +1 -1
  234. package/dist/record/main-pass-geometry.d.ts +22 -6
  235. package/dist/record/main-pass-geometry.d.ts.map +1 -1
  236. package/dist/record/main-pass-material.d.ts +14 -10
  237. package/dist/record/main-pass-material.d.ts.map +1 -1
  238. package/dist/record/main-pass-sprite-draws.d.ts +3 -16
  239. package/dist/record/main-pass-sprite-draws.d.ts.map +1 -1
  240. package/dist/record/main-pass.d.ts +13 -2
  241. package/dist/record/main-pass.d.ts.map +1 -1
  242. package/dist/record/motion-blur-receipt.d.ts +11 -0
  243. package/dist/record/motion-blur-receipt.d.ts.map +1 -0
  244. package/dist/record/prepared-material-bindings.d.ts +3 -3
  245. package/dist/record/prepared-material-bindings.d.ts.map +1 -1
  246. package/dist/record/probe-blend-buffer.d.ts +16 -0
  247. package/dist/record/probe-blend-buffer.d.ts.map +1 -0
  248. package/dist/record/recovery-pipeline.d.ts.map +1 -1
  249. package/dist/record/render-context.d.ts +24 -5
  250. package/dist/record/render-context.d.ts.map +1 -1
  251. package/dist/record/shadow-pass.d.ts +2 -0
  252. package/dist/record/shadow-pass.d.ts.map +1 -1
  253. package/dist/record/skybox-post-pass.d.ts +1 -1
  254. package/dist/record/skybox-post-pass.d.ts.map +1 -1
  255. package/dist/record/sprite-instance-buffer.d.ts +31 -0
  256. package/dist/record/sprite-instance-buffer.d.ts.map +1 -0
  257. package/dist/record/target-capture-graph.d.ts +19 -0
  258. package/dist/record/target-capture-graph.d.ts.map +1 -0
  259. package/dist/record/typed-frame-graph.d.ts +24 -15
  260. package/dist/record/typed-frame-graph.d.ts.map +1 -1
  261. package/dist/record/view-ubo.d.ts +11 -3
  262. package/dist/record/view-ubo.d.ts.map +1 -1
  263. package/dist/record/volume-params.d.ts +9 -0
  264. package/dist/record/volume-params.d.ts.map +1 -0
  265. package/dist/recovery/render-system-candidate.d.ts +14 -4
  266. package/dist/recovery/render-system-candidate.d.ts.map +1 -1
  267. package/dist/reflection/record-owner.d.ts.map +1 -1
  268. package/dist/render-contract.d.ts +46 -5
  269. package/dist/render-contract.d.ts.map +1 -1
  270. package/dist/render-graph-primitives.d.ts.map +1 -1
  271. package/dist/render-pipeline.d.ts +103 -2
  272. package/dist/render-pipeline.d.ts.map +1 -1
  273. package/dist/render-system-extract-tail.d.ts +3 -2
  274. package/dist/render-system-extract-tail.d.ts.map +1 -1
  275. package/dist/render-system-extract.d.ts +18 -9
  276. package/dist/render-system-extract.d.ts.map +1 -1
  277. package/dist/render-system-presentation.d.ts +23 -0
  278. package/dist/render-system-presentation.d.ts.map +1 -0
  279. package/dist/render-system-producer-roots.d.ts +10 -0
  280. package/dist/render-system-producer-roots.d.ts.map +1 -0
  281. package/dist/render-system-projections.d.ts +3 -2
  282. package/dist/render-system-projections.d.ts.map +1 -1
  283. package/dist/render-system-residency.d.ts +12 -0
  284. package/dist/render-system-residency.d.ts.map +1 -0
  285. package/dist/render-system.d.ts +22 -21
  286. package/dist/render-system.d.ts.map +1 -1
  287. package/dist/scene/probe-blend.d.ts +27 -0
  288. package/dist/scene/probe-blend.d.ts.map +1 -1
  289. package/dist/scene/render-scene.d.ts +18 -7
  290. package/dist/scene/render-scene.d.ts.map +1 -1
  291. package/dist/scene/render-source.d.ts +42 -0
  292. package/dist/scene/render-source.d.ts.map +1 -0
  293. package/dist/scene/source-systems.d.ts +6 -0
  294. package/dist/scene/source-systems.d.ts.map +1 -0
  295. package/dist/ssao-buffers.d.ts +9 -0
  296. package/dist/ssao-buffers.d.ts.map +1 -1
  297. package/dist/surface/dynamic-input.d.ts +133 -0
  298. package/dist/surface/dynamic-input.d.ts.map +1 -0
  299. package/dist/surface/gpu-driven.d.ts +41 -0
  300. package/dist/surface/gpu-driven.d.ts.map +1 -0
  301. package/dist/surface/submission-observation.d.ts +136 -0
  302. package/dist/surface/submission-observation.d.ts.map +1 -0
  303. package/dist/systems/skin-palette-allocator.d.ts.map +1 -1
  304. package/dist/systems/skin-palette-types.d.ts +10 -0
  305. package/dist/systems/skin-palette-types.d.ts.map +1 -1
  306. package/dist/systems/transparent-dispatch.d.ts +2 -2
  307. package/dist/systems/transparent-dispatch.d.ts.map +1 -1
  308. package/dist/systems/transparent-sort-config.d.ts +2 -1
  309. package/dist/systems/transparent-sort-config.d.ts.map +1 -1
  310. package/dist/temporal/gpu.d.ts +13 -1
  311. package/dist/temporal/gpu.d.ts.map +1 -1
  312. package/dist/temporal/index.mjs +6 -7
  313. package/dist/temporal/inspection.d.ts.map +1 -1
  314. package/dist/temporal/standard-scene-data.d.ts.map +1 -1
  315. package/dist/temporal/target-coverage-attachment.d.ts.map +1 -1
  316. package/dist/transmission/single-layer-medium.d.ts +89 -0
  317. package/dist/transmission/single-layer-medium.d.ts.map +1 -0
  318. package/dist/typed-render-graph-primitives.d.ts +14 -2
  319. package/dist/typed-render-graph-primitives.d.ts.map +1 -1
  320. package/dist/volume/component.d.ts +9 -4
  321. package/dist/volume/component.d.ts.map +1 -1
  322. package/dist/volume/extract.d.ts +1 -1
  323. package/dist/volume/extract.d.ts.map +1 -1
  324. package/dist/volume/inspection.d.ts +2 -0
  325. package/dist/volume/inspection.d.ts.map +1 -1
  326. package/dist/volume/passes.d.ts +4 -1
  327. package/dist/volume/passes.d.ts.map +1 -1
  328. package/dist/volume/resources.d.ts.map +1 -1
  329. package/package.json +22 -21
  330. package/src/__tests__/atmosphere-daylight.dawn.test.ts +72 -0
  331. package/src/__tests__/auto-exposure-transaction.integration.test.ts +4 -9
  332. package/src/__tests__/barrel-distortion-lkg.integration.test.ts +353 -0
  333. package/src/__tests__/barrel-distortion.dawn.test.ts +41 -0
  334. package/src/__tests__/barrel-distortion.unit.test.ts +364 -0
  335. package/src/__tests__/construct-renderer-identity.unit.test.ts +49 -0
  336. package/src/__tests__/detached-recovery-graph.unit.test.ts +277 -0
  337. package/src/__tests__/device-feature-admission.unit.test.ts +3 -2
  338. package/src/__tests__/device-loss-fanout.unit.test.ts +36 -1
  339. package/src/__tests__/docs-gate-green.unit.test.ts +112 -1
  340. package/src/__tests__/factory-contract.integration.test.ts +295 -45
  341. package/src/__tests__/feature-depth-input.dawn.test.ts +129 -2
  342. package/src/__tests__/fullscreen-feature-plan.unit.test.ts +14 -3
  343. package/src/__tests__/gpu-dirty-ranges.unit.test.ts +22 -0
  344. package/src/__tests__/gpu-driven-baseline.characterization.test.ts +16 -3
  345. package/src/__tests__/gpu-driven-batch-topology-pbr.unit.test.ts +12 -0
  346. package/src/__tests__/gpu-driven-material-artifacts.unit.test.ts +143 -0
  347. package/src/__tests__/gpu-driven-pbr.dawn.test.ts +5 -6
  348. package/src/__tests__/gpu-driven-production.integration.test.ts +482 -3
  349. package/src/__tests__/gpu-driven-shadow-views.dawn.test.ts +6 -5
  350. package/src/__tests__/gpu-driven-view-gpu-evidence.ts +94 -6
  351. package/src/__tests__/gpu-driven-view-graph.integration.test.ts +18 -2
  352. package/src/__tests__/gpu-driven-view.browser.test.ts +5 -8
  353. package/src/__tests__/gpu-driven-view.dawn.test.ts +6 -2
  354. package/src/__tests__/gpu-driven-view.unit.test.ts +1 -1
  355. package/src/__tests__/gpu-pass-timing-lifecycle.integration.test.ts +1 -0
  356. package/src/__tests__/gpu-pass-timing.browser.test.ts +6 -4
  357. package/src/__tests__/gpu-pass-timing.rhi-null.unit.test.ts +1 -0
  358. package/src/__tests__/gpu-scene.unit.test.ts +119 -9
  359. package/src/__tests__/instance-allocation-failure.unit.test.ts +57 -0
  360. package/src/__tests__/instances-culling.integration.test.ts +10 -36
  361. package/src/__tests__/instances-store.unit.test.ts +97 -305
  362. package/src/__tests__/instances-world-ownership.integration.test.ts +62 -0
  363. package/src/__tests__/ktx2-basis-gpu-consumer.dawn.test.ts +4 -1
  364. package/src/__tests__/main-pass-material-medium-selection.unit.test.ts +145 -0
  365. package/src/__tests__/material-shader-prewarm.unit.test.ts +59 -0
  366. package/src/__tests__/material-snapshot-mutation.integration.test.ts +39 -1
  367. package/src/__tests__/materials-standard-contract.unit.test.ts +0 -1
  368. package/src/__tests__/morph-culling-reentry.dawn.test.ts +5 -5
  369. package/src/__tests__/morph-visual-evidence.integration.test.ts +8 -7
  370. package/src/__tests__/motion-blur-compute.dawn.test.ts +13 -7
  371. package/src/__tests__/motion-blur.pixel.integration.test.ts +2 -2
  372. package/src/__tests__/nineslice-handle-surface.unit.test.ts +4 -4
  373. package/src/__tests__/pbr-view-layout.unit.test.ts +9 -0
  374. package/src/__tests__/physical-clearcoat.integration.test.ts +66 -8
  375. package/src/__tests__/physical-material-budget.unit.test.ts +40 -0
  376. package/src/__tests__/prepared-graphics-capability.unit.test.ts +66 -2
  377. package/src/__tests__/probe-bindings.unit.test.ts +582 -1
  378. package/src/__tests__/probe-scene-dirty.integration.test.ts +28 -1
  379. package/src/__tests__/receipt-observation-retirement.unit.test.ts +65 -0
  380. package/src/__tests__/recovery-candidate-prepare.contract.test.ts +69 -0
  381. package/src/__tests__/render-error-code-owner.test-d.ts +8 -0
  382. package/src/__tests__/render-feature-diagnostics.unit.test.ts +15 -2
  383. package/src/__tests__/render-feature-error-reporting.unit.test.ts +21 -1
  384. package/src/__tests__/render-feature-prepared-diagnostics.unit.test.ts +10 -1
  385. package/src/__tests__/render-feature-retry.unit.test.ts +12 -1
  386. package/src/__tests__/render-scene-mixed-updates.integration.test.ts +145 -19
  387. package/src/__tests__/render-scene-projection.unit.test.ts +36 -11
  388. package/src/__tests__/render-scene-temporal-retry.unit.test.ts +20 -20
  389. package/src/__tests__/render-target-probe-soak.perf.test.ts +2 -2
  390. package/src/__tests__/render-temporal-environment-consumer.browser.test.ts +3 -3
  391. package/src/__tests__/render-temporal-environment-consumer.dawn.test.ts +5 -2
  392. package/src/__tests__/renderer-factory-material-contract.unit.test.ts +42 -8
  393. package/src/__tests__/renderer-frame-generation-fence.integration.test.ts +16 -0
  394. package/src/__tests__/renderer-frame-transaction.integration.test.ts +26 -10
  395. package/src/__tests__/resource-allocation.unit.test.ts +123 -0
  396. package/src/__tests__/single-layer-medium-passes.unit.test.ts +275 -0
  397. package/src/__tests__/skin-motion-regression.unit.test.ts +70 -1
  398. package/src/__tests__/skin-palette-recycling.dawn.test.ts +97 -0
  399. package/src/__tests__/skinned-shadow-caster.test.ts +15 -0
  400. package/src/__tests__/ssr-carrier-public-contract.unit.test.ts +21 -0
  401. package/src/__tests__/ssr-gpu-dispatch.browser.test.ts +4 -4
  402. package/src/__tests__/ssr-gpu-dispatch.dawn.test.ts +2 -2
  403. package/src/__tests__/ssr-gpu-dispatch.ts +1 -1
  404. package/src/__tests__/ssr-receiver-coverage.dawn.test.ts +6 -2
  405. package/src/__tests__/standard-output-chain-contract.unit.test.ts +28 -0
  406. package/src/__tests__/standard-pbr-artifact-assembly.unit.test.ts +46 -1
  407. package/src/__tests__/standard-pipeline.integration.test.ts +182 -1
  408. package/src/__tests__/surface-dynamic-buffer-lifecycle.unit.test.ts +506 -0
  409. package/src/__tests__/surface-submission-observation.unit.test.ts +812 -0
  410. package/src/__tests__/temporal-history-lifecycle.unit.test.ts +32 -0
  411. package/src/__tests__/temporal-performance.integration.test.ts +3 -3
  412. package/src/__tests__/visibility-instances.integration.test.ts +7 -19
  413. package/src/__tests__/visibility-producer-matrix.integration.test.ts +9 -20
  414. package/src/__tests__/volume-optics-oracle.unit.test.ts +4 -2
  415. package/src/__tests__/volumetric-fog-budget-recovery.integration.test.ts +30 -20
  416. package/src/__tests__/volumetric-fog-errors.unit.test.ts +4 -3
  417. package/src/__tests__/volumetric-fog-multiple.unit.test.ts +55 -0
  418. package/src/__tests__/volumetric-fog-spot-frame-optics.integration.test.ts +1 -1
  419. package/src/__tests__/volumetric-fog-stage-readback.dawn.test.ts +113 -9
  420. package/src/__tests__/volumetric-fog-topology.unit.test.ts +5 -3
  421. package/src/assembly/backend-contract.ts +30 -0
  422. package/src/assembly/barrel-distortion-inspection.ts +22 -0
  423. package/src/assembly/canvas-draw-guard.ts +11 -0
  424. package/src/assembly/cloud-shadow-entry.ts +22 -0
  425. package/src/assembly/device-feature-admission.ts +2 -2
  426. package/src/assembly/dynamic-geometry-host.ts +65 -37
  427. package/src/assembly/dynamic-geometry-runtime.ts +7 -1
  428. package/src/assembly/factory.ts +2 -30
  429. package/src/assembly/host-contract.ts +8 -5
  430. package/src/assembly/material/assembly.ts +25 -13
  431. package/src/assembly/material/pipeline-helpers.ts +53 -12
  432. package/src/assembly/material-shader-policy.ts +55 -0
  433. package/src/assembly/material-shader-prewarm.ts +21 -10
  434. package/src/assembly/recovery/device-loss-fanout.ts +13 -0
  435. package/src/assembly/recovery/renderer-recover.ts +50 -18
  436. package/src/assembly/render-feature-post-processes.ts +54 -0
  437. package/src/assembly/render-target-host.ts +57 -47
  438. package/src/assembly/renderer-facade.ts +7 -2
  439. package/src/assembly/renderer-feature-inspection.ts +8 -2
  440. package/src/assembly/renderer-frame-transaction.ts +23 -0
  441. package/src/assembly/renderer-inspection.ts +28 -0
  442. package/src/assembly/skin-palette-owner.ts +1 -1
  443. package/src/assembly/temporal-post-process-prewarm.ts +3 -3
  444. package/src/assembly/webgpu-pbr-ready.ts +9 -1
  445. package/src/assembly/webgpu-ready-per-pass.ts +104 -0
  446. package/src/assembly/webgpu-ready.ts +116 -62
  447. package/src/assembly/webgpu-renderer-bootstrap.ts +0 -12
  448. package/src/assembly/webgpu-renderer-observation-owner.ts +222 -0
  449. package/src/assembly/webgpu-renderer.ts +303 -313
  450. package/src/assembly/webgpu-vertex-layouts.ts +1 -1
  451. package/src/barrel-distortion.ts +247 -0
  452. package/src/cloud/__tests__/cloud-density-parity.dawn.test.ts +173 -0
  453. package/src/cloud/__tests__/cloud-layer-framebuffer-y.dawn.test.ts +265 -0
  454. package/src/cloud/__tests__/cloud-layer.browser.test.ts +432 -0
  455. package/src/cloud/__tests__/cloud-layer.unit.test.ts +634 -0
  456. package/src/cloud/density.ts +600 -0
  457. package/src/cloud/extract.ts +110 -0
  458. package/src/cloud/feature.ts +1810 -0
  459. package/src/cloud/frame-context.ts +42 -0
  460. package/src/cloud/inspection.ts +130 -0
  461. package/src/cloud/optics.ts +285 -0
  462. package/src/cloud/parameters.ts +255 -0
  463. package/src/cloud/resources.ts +122 -0
  464. package/src/cloud/shadow.ts +167 -0
  465. package/src/cloud/temporal.ts +226 -0
  466. package/src/components/barrel-distortion.ts +46 -0
  467. package/src/components/cloud-layer.ts +47 -0
  468. package/src/components/index.ts +2 -0
  469. package/src/components/instances.ts +18 -45
  470. package/src/components/sprite-instances.ts +1 -1
  471. package/src/construct-renderer.ts +1 -1
  472. package/src/device/gpu-residency.ts +26 -25
  473. package/src/dynamic-geometry.ts +12 -1
  474. package/src/errors/cloud.ts +103 -0
  475. package/src/errors/render.ts +47 -8
  476. package/src/examples/single-layer-medium-surface.ts +59 -0
  477. package/src/extract/camera.ts +15 -1
  478. package/src/extract/contracts.ts +5 -0
  479. package/src/extract/material-context.ts +21 -0
  480. package/src/features/barrel-distortion.ts +172 -0
  481. package/src/features/error-reporting.ts +26 -6
  482. package/src/features/host.ts +128 -19
  483. package/src/features/plan.ts +10 -0
  484. package/src/features/render-graph-contribution.ts +9 -0
  485. package/src/features/render-graph-raster.ts +45 -3
  486. package/src/features/targets.ts +66 -0
  487. package/src/features/types.ts +51 -0
  488. package/src/fullscreen-post-process-pass.ts +41 -9
  489. package/src/glyph-text-layout-system.ts +2 -2
  490. package/src/gpu-dirty-ranges.ts +48 -0
  491. package/src/gpu-driven/batch-topology.ts +53 -0
  492. package/src/gpu-driven/material-artifacts.ts +33 -25
  493. package/src/gpu-driven/prepared-draw.ts +12 -4
  494. package/src/gpu-driven/production-raster-material.ts +1894 -0
  495. package/src/gpu-driven/production-raster.ts +825 -784
  496. package/src/gpu-driven/resource-allocation.ts +142 -0
  497. package/src/gpu-driven/shadow-ownership.ts +71 -0
  498. package/src/gpu-driven/view-gpu.ts +164 -10
  499. package/src/gpu-scene.ts +75 -84
  500. package/src/hdrp-buffers.ts +4 -3
  501. package/src/ibl/frame-resources.ts +0 -1
  502. package/src/ibl/skylight-bind-group.ts +62 -32
  503. package/src/index.ts +205 -9
  504. package/src/inspection-types.ts +162 -0
  505. package/src/instance-buffer-cache.ts +4 -4
  506. package/src/instances.ts +152 -569
  507. package/src/pbr-pipeline.ts +230 -30
  508. package/src/pipeline/single-layer-medium-passes.ts +267 -0
  509. package/src/pipeline/standard-forward-lane.ts +313 -57
  510. package/src/pipeline/standard-output/graph.ts +8 -2
  511. package/src/pipeline/standard-output/lut-gpu.ts +3 -3
  512. package/src/pipeline/standard-output/resources.ts +2 -2
  513. package/src/pipeline/standard-output/types.ts +12 -1
  514. package/src/pipeline/standard-pipeline.ts +291 -18
  515. package/src/pipeline/standard-post.ts +90 -24
  516. package/src/pipeline-builder.ts +1 -1
  517. package/src/plugin.ts +4 -0
  518. package/src/points-lines/__tests__/points-lines.bench.ts +17 -8
  519. package/src/prepare/prepared-graphics-resolver.ts +2 -0
  520. package/src/publication/__tests__/derived-geometry.integration.test.ts +177 -0
  521. package/src/publication/__tests__/features.integration.test.ts +122 -0
  522. package/src/publication/__tests__/programs.unit.test.ts +25 -0
  523. package/src/publication/__tests__/publication.integration.test.ts +370 -0
  524. package/src/publication/__tests__/targets.integration.test.ts +120 -0
  525. package/src/publication/__tests__/video.browser.test.ts +50 -0
  526. package/src/publication/contract.ts +104 -0
  527. package/src/publication/dependencies.ts +54 -0
  528. package/src/publication/prepare-geometry.ts +94 -0
  529. package/src/publication/programs.ts +45 -0
  530. package/src/publication/publisher.ts +618 -0
  531. package/src/publication/receiver.ts +297 -0
  532. package/src/publication/resource-scope.ts +31 -0
  533. package/src/publication/targets.ts +182 -0
  534. package/src/publication/video.ts +33 -0
  535. package/src/record/__tests__/main-pass-geometry.unit.test.ts +30 -0
  536. package/src/record/__tests__/material-bg-cache.unit.test.ts +15 -1
  537. package/src/record/__tests__/sprite-material-abi.unit.test.ts +9 -11
  538. package/src/record/__tests__/temporal-payload.unit.test.ts +1 -1
  539. package/src/record/__tests__/transparent-group2-selection.unit.test.ts +11 -0
  540. package/src/record/__tests__/typed-frame-graph-plan.unit.test.ts +1 -0
  541. package/src/record/__tests__/video-texture-view.unit.test.ts +9 -9
  542. package/src/record/__tests__/view-ubo-layout.unit.test.ts +4 -3
  543. package/src/record/barrel-distortion-frame.ts +110 -0
  544. package/src/record/dynamic-geometry-consumption.ts +39 -9
  545. package/src/record/fold-buckets.ts +855 -0
  546. package/src/record/fold-instance-buffer.ts +51 -0
  547. package/src/record/frame-lighting.ts +36 -2
  548. package/src/record/frame-snapshot.ts +45 -9
  549. package/src/record/frame.ts +258 -1105
  550. package/src/record/gpu-draw-receipts.ts +38 -0
  551. package/src/record/gpu-timing.ts +48 -5
  552. package/src/record/helpers.ts +2 -2
  553. package/src/record/main-pass-geometry.ts +272 -84
  554. package/src/record/main-pass-material.ts +102 -36
  555. package/src/record/main-pass-sprite-draws.ts +13 -217
  556. package/src/record/main-pass.ts +164 -27
  557. package/src/record/motion-blur-receipt.ts +91 -0
  558. package/src/record/prepared-material-bindings.ts +11 -6
  559. package/src/record/probe-blend-buffer.ts +180 -0
  560. package/src/record/recovery-pipeline.ts +35 -3
  561. package/src/record/render-context.ts +41 -5
  562. package/src/record/shadow-pass.ts +30 -4
  563. package/src/record/skybox-post-pass.ts +28 -4
  564. package/src/record/sprite-instance-buffer.ts +155 -0
  565. package/src/record/target-capture-graph.ts +258 -0
  566. package/src/record/typed-frame-graph.ts +776 -340
  567. package/src/record/view-ubo.ts +27 -4
  568. package/src/record/volume-params.ts +225 -0
  569. package/src/recovery/render-system-candidate.ts +243 -50
  570. package/src/reflection/record-owner.ts +7 -3
  571. package/src/render-contract.ts +54 -5
  572. package/src/render-graph-primitives.ts +7 -1
  573. package/src/render-pipeline.ts +130 -0
  574. package/src/render-system-extract-tail.ts +90 -78
  575. package/src/render-system-extract.ts +76 -76
  576. package/src/render-system-presentation.ts +56 -0
  577. package/src/render-system-producer-roots.ts +96 -0
  578. package/src/render-system-projections.ts +3 -2
  579. package/src/render-system-residency.ts +159 -0
  580. package/src/render-system.ts +421 -408
  581. package/src/scene/probe-blend.ts +96 -4
  582. package/src/scene/render-scene.ts +416 -337
  583. package/src/scene/render-source.ts +90 -0
  584. package/src/scene/source-systems.ts +33 -0
  585. package/src/ssao-buffers.ts +95 -2
  586. package/src/surface/__tests__/dynamic-input.unit.test.ts +374 -0
  587. package/src/surface/__tests__/gpu-driven.unit.test.ts +87 -0
  588. package/src/surface/dynamic-input.ts +658 -0
  589. package/src/surface/gpu-driven.ts +147 -0
  590. package/src/surface/submission-observation.ts +517 -0
  591. package/src/systems/skin-palette-allocator.ts +5 -1
  592. package/src/systems/skin-palette-types.ts +11 -0
  593. package/src/systems/transparent-dispatch.ts +2 -2
  594. package/src/systems/transparent-sort-config.ts +3 -1
  595. package/src/temporal/gpu.ts +101 -17
  596. package/src/temporal/inspection.ts +7 -1
  597. package/src/temporal/standard-scene-data.ts +5 -0
  598. package/src/temporal/target-coverage-attachment.ts +4 -0
  599. package/src/transmission/__tests__/single-layer-medium.unit.test.ts +149 -0
  600. package/src/transmission/__tests__/standard-transmission.dawn.test.ts +12 -11
  601. package/src/transmission/single-layer-medium.ts +322 -0
  602. package/src/typed-render-graph-primitives.ts +70 -2
  603. package/src/volume/component.ts +10 -9
  604. package/src/volume/extract.ts +11 -5
  605. package/src/volume/inspection.ts +3 -0
  606. package/src/volume/passes.ts +87 -4
  607. package/src/volume/resources.ts +2 -1
  608. package/dist/chunk-3RTCJTH4.mjs +0 -1610
  609. package/dist/chunk-3RTCJTH4.mjs.map +0 -1
  610. package/dist/chunk-BLXGONR2.mjs.map +0 -1
  611. package/dist/chunk-ILQ5MEZF.mjs +0 -32
  612. package/dist/chunk-ILQ5MEZF.mjs.map +0 -1
  613. package/dist/chunk-LEAXOMYJ.mjs.map +0 -1
  614. package/dist/chunk-NB2S7ZRX.mjs +0 -1783
  615. package/dist/chunk-NB2S7ZRX.mjs.map +0 -1
  616. package/dist/chunk-NNQL7CB3.mjs +0 -1713
  617. package/dist/chunk-NNQL7CB3.mjs.map +0 -1
  618. package/dist/chunk-OO3DRYK7.mjs.map +0 -1
  619. package/dist/chunk-PA5DRJNI.mjs.map +0 -1
  620. package/dist/chunk-PLAXOOX5.mjs +0 -1907
  621. package/dist/chunk-PLAXOOX5.mjs.map +0 -1
  622. package/dist/chunk-RXZ3RGOU.mjs +0 -53
  623. package/dist/chunk-RXZ3RGOU.mjs.map +0 -1
  624. package/dist/chunk-VOZWDM3L.mjs.map +0 -1
package/src/instances.ts CHANGED
@@ -1,52 +1,25 @@
1
+ import { InstanceTransformsStrideMismatchError } from '@forgeax/engine-ecs/projection';
1
2
  import type { RhiErrorCode } from '@forgeax/engine-rhi';
2
- import { err, ok, type Result } from '@forgeax/engine-types';
3
3
 
4
4
  const MATRIX_STRIDE = 16;
5
- const INITIAL_CAPACITY = 1;
6
5
 
6
+ /** Renderer projection identity; never stored in a World or SceneAsset. */
7
7
  export type InstanceCollectionId = number & {
8
8
  readonly __forgeaxInstanceCollectionId: unique symbol;
9
9
  };
10
-
11
- export interface InstanceCollectionData {
10
+ export interface InstanceCollectionInfo {
12
11
  readonly collectionId: InstanceCollectionId;
13
- }
14
-
15
- export interface InstanceCollectionInfo extends InstanceCollectionData {
16
12
  readonly count: number;
17
- readonly capacity: number;
18
13
  readonly revision: number;
19
14
  }
20
-
21
15
  export interface InstanceDirtyRange {
22
16
  start: number;
23
17
  end: number;
24
18
  }
25
-
26
- /**
27
- * Choose the ranges that initialize one resident GPU allocation.
28
- *
29
- * A cache miss is not a delta upload: recovery, reassociation, and any other
30
- * new resident has uninitialized device memory. The canonical collection must
31
- * therefore be copied in full even when the current authoring revision only
32
- * records a partial dirty range. Existing residents keep the narrower ranges.
33
- */
34
- export function instanceUploadRangesForResident(
35
- activeIsNew: boolean,
36
- dirtyRanges: readonly InstanceDirtyRange[],
37
- fullRange: InstanceDirtyRange,
38
- ): readonly InstanceDirtyRange[] {
39
- return activeIsNew ? [fullRange] : dirtyRanges;
40
- }
41
-
42
19
  export interface InstanceCollectionSnapshot extends InstanceCollectionInfo {
43
20
  readonly transforms: Float32Array;
44
- /** Unique identity generations that travel with an instance through reorder. */
45
21
  readonly generations: Uint32Array;
46
- readonly dirtyRanges: readonly InstanceDirtyRange[];
47
22
  }
48
-
49
- /** The renderer-owned submission lane selected for one collection. */
50
23
  export type InstanceSubmissionLane =
51
24
  | 'unresident'
52
25
  | 'direct-storage'
@@ -54,14 +27,8 @@ export type InstanceSubmissionLane =
54
27
  | 'direct-uniform'
55
28
  | 'chunked-uniform'
56
29
  | 'unavailable';
57
-
58
- /** Backend identity carried by collection residency and failure facts. */
59
30
  export type InstanceBackendKind = 'webgpu' | 'wgpu-native' | 'wgpu-webgl2' | 'null' | 'unknown';
60
-
61
- /** Closed record-stage failure vocabulary for collection residency. */
62
31
  export type InstanceCollectionFailureCode = RhiErrorCode | 'queue-write-buffer-failed';
63
-
64
- /** Typed producer facts retained when a collection cannot be admitted. */
65
32
  export interface InstanceCollectionFailureFacts {
66
33
  readonly requestedBytes: number;
67
34
  readonly supportedBytes: number | undefined;
@@ -70,29 +37,9 @@ export interface InstanceCollectionFailureFacts {
70
37
  readonly cause: string;
71
38
  readonly recovery: string;
72
39
  }
73
-
74
- function instanceCollectionFailureFacts(
75
- cause: string,
76
- recovery: string,
77
- requestedBytes = 0,
78
- supportedBytes: number | undefined = undefined,
79
- backend: InstanceBackendKind = 'unknown',
80
- ): InstanceCollectionFailureFacts {
81
- return {
82
- requestedBytes,
83
- supportedBytes,
84
- backend,
85
- owner: 'renderer.instances',
86
- cause,
87
- recovery,
88
- };
89
- }
90
-
91
- /** Detached, bounded collection evidence exposed by Renderer.inspect(). */
92
40
  export interface InstanceCollectionInspection extends InstanceCollectionInfo {
93
41
  readonly residentGeneration: number | undefined;
94
42
  readonly lane: InstanceSubmissionLane;
95
- readonly dirtyRanges: readonly InstanceDirtyRange[];
96
43
  readonly uploadRanges: readonly InstanceDirtyRange[];
97
44
  readonly uploadedBytes: number;
98
45
  readonly requestedBytes: number;
@@ -109,82 +56,46 @@ export interface InstanceCollectionInspection extends InstanceCollectionInfo {
109
56
  | undefined;
110
57
  }
111
58
 
112
- export interface InstanceCollectionCreateInput {
113
- readonly transforms: Float32Array;
114
- }
115
-
116
- export interface InstanceCollectionUpdateInput {
117
- /** Matrix ordinal of the first matrix to replace. */
118
- readonly start: number;
119
- readonly transforms: Float32Array;
120
- }
121
-
122
- export interface InstanceCollectionInvalidDetail {
123
- readonly collectionId?: number;
124
- readonly operation: 'create' | 'replace' | 'update' | 'inspect' | 'release';
125
- readonly expected: string;
126
- readonly actual: number | string;
127
- }
128
-
129
- export type InstanceCollectionErrorCode =
130
- | 'instance-collection-invalid'
131
- | 'instance-collection-not-found'
132
- | 'instance-collection-released';
133
-
134
- export class InstanceCollectionError extends Error {
135
- readonly code: InstanceCollectionErrorCode;
136
- readonly expected: string;
137
- readonly hint: string;
138
- readonly detail: InstanceCollectionInvalidDetail | undefined;
139
- readonly owner = 'renderer.instances' as const;
140
- readonly recovery: string;
141
- readonly facts: InstanceCollectionFailureFacts;
142
-
59
+ export class InstanceTransformsError extends Error {
60
+ readonly code = 'instance-transforms-invalid' as const;
61
+ readonly expected = 'finite column-major mat4 values, with transforms.length a multiple of 16';
62
+ readonly hint = 'repair Instances.transforms in the World or source SceneAsset and retry';
143
63
  constructor(
144
- code: InstanceCollectionErrorCode,
145
- expected: string,
146
- hint: string,
147
- detail?: InstanceCollectionInvalidDetail,
148
- facts?: InstanceCollectionFailureFacts,
64
+ readonly detail: { readonly actualLength: number; readonly nonFiniteIndex?: number },
149
65
  ) {
150
- super(`${code}: ${expected}`);
151
- this.name = 'InstanceCollectionError';
152
- this.code = code;
153
- this.expected = expected;
154
- this.hint = hint;
155
- this.detail = detail;
156
- this.facts =
157
- facts ??
158
- instanceCollectionFailureFacts(
159
- code,
160
- hint,
161
- detail?.operation === 'create' || detail?.operation === 'replace'
162
- ? typeof detail.actual === 'number' && Number.isFinite(detail.actual)
163
- ? detail.actual * Float32Array.BYTES_PER_ELEMENT
164
- : 0
165
- : 0,
166
- );
167
- this.recovery = this.facts.recovery;
66
+ super('Instances.transforms must contain complete finite matrices');
67
+ this.name = 'InstanceTransformsError';
168
68
  }
169
69
  }
70
+ export function validateInstanceTransforms(
71
+ transforms: ArrayLike<number>,
72
+ ): InstanceTransformsError | InstanceTransformsStrideMismatchError | undefined {
73
+ if (transforms.length % MATRIX_STRIDE !== 0)
74
+ return new InstanceTransformsStrideMismatchError(transforms.length);
75
+ for (let index = 0; index < transforms.length; index++) {
76
+ if (!Number.isFinite(transforms[index]))
77
+ return new InstanceTransformsError({
78
+ actualLength: transforms.length,
79
+ nonFiniteIndex: index,
80
+ });
81
+ }
82
+ return undefined;
83
+ }
170
84
 
171
- export type InstanceCollectionResult<T> = Result<T, InstanceCollectionError>;
172
-
173
- interface CollectionRecord {
174
- readonly id: InstanceCollectionId;
175
- transforms: Float32Array;
176
- generations: Uint32Array;
177
- count: number;
178
- capacity: number;
179
- revision: number;
180
- dirtyRanges: InstanceDirtyRange[];
181
- /** Last revision detached for extraction; repeated reads of that revision
182
- * retain the same ranges for multiple entities sharing one collection. */
183
- lastSnapshotRevision: number;
184
- released: boolean;
85
+ /** A new allocation must receive the complete payload, including after recovery. */
86
+ export function instanceUploadRangesForResident(
87
+ activeIsNew: boolean,
88
+ dirtyRanges: readonly InstanceDirtyRange[],
89
+ fullRange: InstanceDirtyRange,
90
+ ): readonly InstanceDirtyRange[] {
91
+ return activeIsNew ? [fullRange] : dirtyRanges;
185
92
  }
186
93
 
187
- interface CollectionResidency {
94
+ interface Projection extends InstanceCollectionSnapshot {
95
+ readonly world: object;
96
+ readonly entity: number;
97
+ }
98
+ interface Residency {
188
99
  readonly frameNumber: number;
189
100
  readonly residentGeneration: number | undefined;
190
101
  readonly lane: InstanceSubmissionLane;
@@ -196,300 +107,124 @@ interface CollectionResidency {
196
107
  readonly error: InstanceCollectionInspection['error'];
197
108
  }
198
109
 
199
- function nextCapacity(required: number): number {
200
- let capacity = INITIAL_CAPACITY;
201
- while (capacity < required) capacity *= 2;
202
- return capacity;
203
- }
204
-
205
- function invalid(
206
- operation: InstanceCollectionInvalidDetail['operation'],
207
- expected: string,
208
- actual: number | string,
209
- collectionId?: number,
210
- context?: {
211
- readonly requestedBytes?: number;
212
- readonly supportedBytes?: number;
213
- readonly cause?: string;
214
- readonly recovery?: string;
215
- },
216
- ): InstanceCollectionError {
217
- const hint = 'repair the collection payload and retry the same authoring operation';
218
- return new InstanceCollectionError(
219
- 'instance-collection-invalid',
220
- expected,
221
- hint,
222
- { operation, expected, actual, ...(collectionId === undefined ? {} : { collectionId }) },
223
- instanceCollectionFailureFacts(
224
- context?.cause ?? `invalid-${operation}-authoring`,
225
- context?.recovery ?? hint,
226
- context?.requestedBytes ?? 0,
227
- context?.supportedBytes,
228
- ),
229
- );
230
- }
231
-
232
- function validateTransforms(
233
- operation: InstanceCollectionInvalidDetail['operation'],
234
- transforms: Float32Array,
235
- collectionId?: number,
236
- ): InstanceCollectionError | undefined {
237
- if (!(transforms instanceof Float32Array)) {
238
- return invalid(operation, 'transforms is a Float32Array', typeof transforms, collectionId, {
239
- cause: 'invalid-transform-type',
240
- });
241
- }
242
- if (transforms.length % MATRIX_STRIDE !== 0) {
243
- return invalid(
244
- operation,
245
- `transforms.length is a multiple of ${MATRIX_STRIDE}`,
246
- transforms.length,
247
- collectionId,
248
- {
249
- requestedBytes: transforms.byteLength,
250
- cause: 'invalid-transform-stride',
251
- },
252
- );
253
- }
254
- for (const value of transforms) {
255
- if (!Number.isFinite(value)) {
256
- return invalid(operation, 'every transform value is finite', value, collectionId, {
257
- requestedBytes: transforms.byteLength,
258
- cause: 'invalid-transform-value',
259
- });
260
- }
261
- }
262
- return undefined;
263
- }
264
-
265
- function appendRange(ranges: InstanceDirtyRange[], start: number, end: number): void {
266
- if (start >= end) return;
267
- // Updates are allowed to arrive in any order. Insert at the first range
268
- // whose end reaches the new interval, then consume every range that starts
269
- // before the merged end. This preserves the complete union for both
270
- // adjacent and overlapping writes (for example [10, 12) then [8, 11)).
271
- let index = 0;
272
- while (index < ranges.length) {
273
- const existing = ranges[index];
274
- if (existing === undefined || existing.end >= start) break;
275
- index += 1;
276
- }
277
- while (index < ranges.length) {
278
- const existing = ranges[index];
279
- if (existing === undefined || existing.start > end) break;
280
- start = Math.min(start, existing.start);
281
- end = Math.max(end, existing.end);
282
- ranges.splice(index, 1);
283
- }
284
- ranges.splice(index, 0, { start, end });
285
- }
286
-
287
- function appendDirtyRange(record: CollectionRecord, start: number, end: number): void {
288
- appendRange(record.dirtyRanges, start, end);
289
- }
290
-
291
- function missing(
292
- operation: InstanceCollectionInvalidDetail['operation'],
293
- id: InstanceCollectionId,
294
- ): InstanceCollectionError {
295
- return new InstanceCollectionError(
296
- 'instance-collection-not-found',
297
- `instance collection ${Number(id)} is live and owned by this Renderer`,
298
- 'create a collection with renderer.instances.create or retain the original collection id',
299
- { operation, expected: 'a live instance collection id', actual: Number(id), collectionId: id },
300
- );
301
- }
302
-
303
- /**
304
- * Renderer-owned canonical storage for explicit instance transforms.
305
- *
306
- * ECS carries only `Instances.collectionId`; this owner keeps the copied
307
- * matrices, revision and dirty intervals independent of archetype capacity.
308
- * Snapshots are detached before they cross into extraction, so callers cannot
309
- * mutate the canonical source behind the revision protocol.
310
- */
311
- export class InstanceCollectionStore {
110
+ /** Rebuildable renderer projection. All authoring and entity lifetime belong to World. */
111
+ export class InstanceProjectionStore {
312
112
  private nextId = 1;
313
- private nextInstanceGeneration = 1;
314
- private epochValue = 0;
315
- private disposed = false;
316
- private readonly records = new Map<InstanceCollectionId, CollectionRecord>();
317
- private readonly residency = new Map<InstanceCollectionId, CollectionResidency>();
318
-
319
- get epoch(): number {
320
- return this.epochValue;
321
- }
322
-
323
- create(input: InstanceCollectionCreateInput): InstanceCollectionResult<InstanceCollectionInfo> {
324
- if (this.disposed) {
325
- return err(
326
- new InstanceCollectionError(
327
- 'instance-collection-released',
328
- 'the Renderer-owned instance collection store is live',
329
- 'create a new Renderer before authoring instance collections',
330
- ),
331
- );
332
- }
333
- const invalidPayload = validateTransforms('create', input.transforms);
334
- if (invalidPayload !== undefined) return err(invalidPayload);
335
- const id = this.nextId++ as InstanceCollectionId;
336
- const count = input.transforms.length / MATRIX_STRIDE;
337
- const generations = this.allocateGenerations(count);
338
- const record: CollectionRecord = {
339
- id,
340
- transforms: new Float32Array(input.transforms),
113
+ private nextGeneration = 1;
114
+ private identities = new WeakMap<object, Map<number, InstanceCollectionId>>();
115
+ private readonly records = new Map<InstanceCollectionId, Projection>();
116
+ private readonly residency = new Map<InstanceCollectionId, Residency>();
117
+
118
+ project(
119
+ world: object,
120
+ entity: number,
121
+ transforms: ArrayLike<number>,
122
+ ): InstanceCollectionSnapshot {
123
+ const collectionId =
124
+ this.identities.get(world)?.get(entity) ?? (this.nextId++ as InstanceCollectionId);
125
+ const previous = this.records.get(collectionId);
126
+ if (
127
+ previous !== undefined &&
128
+ previous.transforms.length === transforms.length &&
129
+ previous.transforms.every((value, index) => Object.is(value, transforms[index]))
130
+ )
131
+ return previous;
132
+ const count = transforms.length / MATRIX_STRIDE;
133
+ // Ordinals are identities within the authored array. Pose edits retain them;
134
+ // resizing seeds topology anew so new instances cannot inherit old motion.
135
+ const generations =
136
+ previous?.count === count
137
+ ? previous.generations
138
+ : Uint32Array.from({ length: count }, () => this.nextGeneration++);
139
+ const record: Projection = {
140
+ collectionId,
141
+ world,
142
+ entity,
143
+ transforms: new Float32Array(transforms),
341
144
  generations,
342
145
  count,
343
- capacity: nextCapacity(Math.max(INITIAL_CAPACITY, count)),
344
- revision: 1,
345
- dirtyRanges: count === 0 ? [] : [{ start: 0, end: count }],
346
- lastSnapshotRevision: 0,
347
- released: false,
146
+ revision: (previous?.revision ?? 0) + 1,
348
147
  };
349
- this.records.set(id, record);
350
- this.epochValue += 1;
351
- return ok(this.info(record));
148
+ return record;
352
149
  }
353
150
 
354
- replace(
355
- id: InstanceCollectionId,
356
- transforms: Float32Array,
357
- /** Prior identity generations in the replacement order; omitted rows are new. */
358
- generations?: Uint32Array,
359
- ): InstanceCollectionResult<InstanceCollectionInfo> {
360
- const record = this.live('replace', id);
361
- if (!record.ok) return record;
362
- const invalidPayload = validateTransforms('replace', transforms, id);
363
- if (invalidPayload !== undefined) return err(invalidPayload);
364
- const count = transforms.length / MATRIX_STRIDE;
365
- const generationResult =
366
- generations === undefined
367
- ? ok(this.allocateGenerations(count))
368
- : this.validateReplacementGenerations(generations, count, id);
369
- if (!generationResult.ok) return generationResult;
370
- // Replacement is a topology boundary by default. A producer that keeps
371
- // logical instance identity through compaction/reorder may pass the prior
372
- // generation tokens in their new order; the record stage then maps the
373
- // real previous transform by token instead of by draw ordinal.
374
- const replacementGenerations = generationResult.value;
375
- record.value.transforms = new Float32Array(transforms);
376
- record.value.generations = replacementGenerations;
377
- record.value.count = count;
378
- record.value.capacity = Math.max(record.value.capacity, nextCapacity(Math.max(1, count)));
379
- record.value.revision += 1;
380
- record.value.dirtyRanges = count === 0 ? [] : [{ start: 0, end: count }];
381
- record.value.lastSnapshotRevision = record.value.revision - 1;
382
- this.epochValue += 1;
383
- return ok(this.info(record.value));
151
+ /** Called only after the owning RenderScene accepts its prepared changes. */
152
+ accept(
153
+ world: object,
154
+ entity: number,
155
+ snapshot: {
156
+ readonly collectionId?: InstanceCollectionId;
157
+ readonly revision?: number;
158
+ readonly transforms: Float32Array;
159
+ readonly generations?: Uint32Array;
160
+ },
161
+ ): void {
162
+ const { collectionId, revision, transforms, generations } = snapshot;
163
+ if (collectionId === undefined || revision === undefined || generations === undefined) return;
164
+ let entities = this.identities.get(world);
165
+ if (entities === undefined) {
166
+ entities = new Map();
167
+ this.identities.set(world, entities);
168
+ }
169
+ entities.set(entity, collectionId);
170
+ this.records.set(collectionId, {
171
+ collectionId,
172
+ revision,
173
+ transforms,
174
+ generations,
175
+ count: transforms.length / MATRIX_STRIDE,
176
+ world,
177
+ entity,
178
+ });
384
179
  }
385
180
 
386
- update(
387
- id: InstanceCollectionId,
388
- input: InstanceCollectionUpdateInput,
389
- ): InstanceCollectionResult<InstanceCollectionInfo> {
390
- const record = this.live('update', id);
391
- if (!record.ok) return record;
392
- const invalidPayload = validateTransforms('update', input.transforms, id);
393
- if (invalidPayload !== undefined) return err(invalidPayload);
394
- if (!Number.isInteger(input.start) || input.start < 0) {
395
- return err(
396
- invalid('update', 'start is a non-negative matrix ordinal', input.start, id, {
397
- requestedBytes: input.transforms.byteLength,
398
- supportedBytes: record.value.capacity * MATRIX_STRIDE * Float32Array.BYTES_PER_ELEMENT,
399
- cause: 'invalid-update-range-start',
400
- }),
401
- );
402
- }
403
- const span = input.transforms.length / MATRIX_STRIDE;
404
- const attemptedEnd = input.start + span;
405
- if (attemptedEnd > record.value.count) {
406
- return err(
407
- invalid(
408
- 'update',
409
- `start + matrix count is <= collection count (${record.value.count})`,
410
- attemptedEnd,
411
- id,
412
- {
413
- requestedBytes: attemptedEnd * MATRIX_STRIDE * Float32Array.BYTES_PER_ELEMENT,
414
- supportedBytes: record.value.count * MATRIX_STRIDE * Float32Array.BYTES_PER_ELEMENT,
415
- cause: 'invalid-update-range-end',
416
- },
417
- ),
418
- );
419
- }
420
- if (record.value.lastSnapshotRevision === record.value.revision) {
421
- record.value.dirtyRanges = [];
181
+ release(world: object, entity: number): void {
182
+ const entities = this.identities.get(world);
183
+ const id = entities?.get(entity);
184
+ if (id === undefined) return;
185
+ entities?.delete(entity);
186
+ this.records.delete(id);
187
+ this.residency.delete(id);
188
+ }
189
+ retain(ids: ReadonlySet<InstanceCollectionId>): void {
190
+ for (const record of this.records.values()) {
191
+ if (!ids.has(record.collectionId)) this.release(record.world, record.entity);
422
192
  }
423
- record.value.transforms.set(input.transforms, input.start * MATRIX_STRIDE);
424
- // An update changes a pose while retaining the same ordinal identity.
425
- // Keep its generation stable so the record stage can pair this current
426
- // transform with the last submitted transform and expose real velocity.
427
- // `replace` is the explicit topology boundary that advances generations
428
- // for compaction, reorder, retirement, and newly occupied ordinals.
429
- record.value.revision += 1;
430
- appendDirtyRange(record.value, input.start, input.start + span);
431
- this.epochValue += 1;
432
- return ok(this.info(record.value));
433
193
  }
434
-
435
- inspect(id: InstanceCollectionId): InstanceCollectionResult<InstanceCollectionInfo> {
436
- const record = this.live('inspect', id);
437
- return record.ok ? ok(this.info(record.value)) : record;
194
+ dispose(): void {
195
+ this.records.clear();
196
+ this.residency.clear();
197
+ this.identities = new WeakMap();
438
198
  }
439
-
440
- /**
441
- * Return detached residency facts for every live collection.
442
- *
443
- * @internal Record-stage evidence is reported through the two methods below;
444
- * callers only receive immutable PODs and never GPU handles.
445
- */
446
- _inspections(): readonly InstanceCollectionInspection[] {
447
- return Object.freeze(
448
- [...this.records.values()].map((record) => this.projectInspection(record)),
449
- );
199
+ _resetResidency(): void {
200
+ this.residency.clear();
450
201
  }
451
202
 
452
- /** @internal Renderer record owner reports the accepted collection lane. */
453
- _reportResidency(input: {
454
- readonly collectionId: InstanceCollectionId;
455
- readonly frameNumber: number;
456
- readonly residentGeneration: number;
457
- readonly lane: Exclude<InstanceSubmissionLane, 'unresident' | 'unavailable'>;
458
- readonly uploadRanges: readonly InstanceDirtyRange[];
459
- readonly uploadedBytes: number;
460
- readonly requestedBytes: number;
461
- readonly supportedBytes: number | undefined;
462
- readonly backend: InstanceBackendKind;
463
- }): void {
203
+ _reportResidency(
204
+ input: Omit<Residency, 'error' | 'lane'> & {
205
+ readonly collectionId: InstanceCollectionId;
206
+ readonly lane: Exclude<InstanceSubmissionLane, 'unresident' | 'unavailable'>;
207
+ },
208
+ ): void {
464
209
  if (!this.records.has(input.collectionId)) return;
465
210
  const previous = this.residency.get(input.collectionId);
466
- const sameFrame =
467
- previous !== undefined &&
468
- previous.frameNumber === input.frameNumber &&
469
- previous.error === undefined;
470
- const uploadRanges = sameFrame
471
- ? [...previous.uploadRanges].reduce(
472
- (ranges, range) => {
473
- appendRange(ranges, range.start, range.end);
474
- return ranges;
475
- },
476
- input.uploadRanges.map((range) => ({ ...range })),
477
- )
478
- : input.uploadRanges.map((range) => ({ ...range }));
211
+ const sameFrame = previous?.frameNumber === input.frameNumber && previous.error === undefined;
212
+ const ranges = [...(sameFrame ? previous.uploadRanges : []), ...input.uploadRanges]
213
+ .map((range) => ({ ...range }))
214
+ .sort((a, b) => a.start - b.start);
215
+ const uploadRanges: InstanceDirtyRange[] = [];
216
+ for (const range of ranges) {
217
+ const last = uploadRanges.at(-1);
218
+ if (last !== undefined && range.start <= last.end) last.end = Math.max(last.end, range.end);
219
+ else uploadRanges.push(range);
220
+ }
479
221
  this.residency.set(input.collectionId, {
480
- frameNumber: input.frameNumber,
481
- residentGeneration: input.residentGeneration,
482
- lane: input.lane,
222
+ ...input,
483
223
  uploadRanges,
484
- uploadedBytes: sameFrame ? previous.uploadedBytes + input.uploadedBytes : input.uploadedBytes,
485
- requestedBytes: input.requestedBytes,
486
- supportedBytes: input.supportedBytes,
487
- backend: input.backend,
224
+ uploadedBytes: input.uploadedBytes + (sameFrame ? previous.uploadedBytes : 0),
488
225
  error: undefined,
489
226
  });
490
227
  }
491
-
492
- /** @internal Renderer record owner reports a typed admission failure. */
493
228
  _reportFailure(input: {
494
229
  readonly collectionId: InstanceCollectionId;
495
230
  readonly code: InstanceCollectionFailureCode;
@@ -515,176 +250,24 @@ export class InstanceCollectionStore {
515
250
  },
516
251
  });
517
252
  }
518
-
519
- /** @internal A lost device invalidates every renderer-owned GPU resident. */
520
- _resetResidency(): void {
521
- this.residency.clear();
522
- }
523
-
524
- snapshot(id: InstanceCollectionId): InstanceCollectionResult<InstanceCollectionSnapshot> {
525
- const record = this.live('inspect', id);
526
- if (!record.ok) return record;
527
- const value = record.value;
528
- value.lastSnapshotRevision = value.revision;
529
- const result = {
530
- ...this.info(value),
531
- transforms: new Float32Array(value.transforms),
532
- generations: new Uint32Array(value.generations),
533
- dirtyRanges: value.dirtyRanges.map((range) => ({ ...range })),
534
- };
535
- // Keep the current ranges stable for repeated reads by entities sharing
536
- // this collection. The next authoring mutation starts a fresh interval
537
- // set once this revision has been observed.
538
- return ok(result);
539
- }
540
-
541
- /**
542
- * Read a detached matrix view without advancing the render-consumption
543
- * cursor. Inspection and picking may call this between authoring updates;
544
- * the next renderer snapshot must still receive the complete dirty union.
545
- */
546
- peek(id: InstanceCollectionId): InstanceCollectionResult<InstanceCollectionSnapshot> {
547
- const record = this.live('inspect', id);
548
- return record.ok ? ok(this.detachedSnapshot(record.value)) : record;
549
- }
550
-
551
- release(id: InstanceCollectionId): InstanceCollectionResult<void> {
552
- const record = this.records.get(id);
553
- if (record === undefined) return err(missing('release', id));
554
- if (record.released) {
555
- return err(
556
- new InstanceCollectionError(
557
- 'instance-collection-released',
558
- `instance collection ${Number(id)} has not already been released`,
559
- 'do not reuse a released collection id; create a new collection',
560
- {
561
- operation: 'release',
562
- expected: 'a live instance collection id',
563
- actual: Number(id),
564
- collectionId: id,
565
- },
566
- ),
567
- );
568
- }
569
- record.released = true;
570
- this.records.delete(id);
571
- this.residency.delete(id);
572
- this.epochValue += 1;
573
- return ok(undefined);
574
- }
575
-
576
- /** Drop all canonical matrices during Renderer disposal. */
577
- dispose(): void {
578
- if (this.disposed) return;
579
- this.disposed = true;
580
- for (const record of this.records.values()) record.released = true;
581
- this.records.clear();
582
- this.residency.clear();
583
- this.epochValue += 1;
584
- }
585
-
586
- private live(
587
- operation: InstanceCollectionInvalidDetail['operation'],
588
- id: InstanceCollectionId,
589
- ): InstanceCollectionResult<CollectionRecord> {
590
- if (!Number.isInteger(id) || id <= 0) {
591
- return err(invalid(operation, 'collectionId is a positive integer', id, id));
592
- }
593
- if (this.disposed) {
594
- return err(
595
- new InstanceCollectionError(
596
- 'instance-collection-released',
597
- 'the Renderer-owned instance collection store is live',
598
- 'create a new Renderer before using instance collections',
599
- { operation, expected: 'a live collection store', actual: 'disposed', collectionId: id },
600
- ),
601
- );
602
- }
603
- const record = this.records.get(id);
604
- return record === undefined ? err(missing(operation, id)) : ok(record);
605
- }
606
-
607
- private detachedSnapshot(record: CollectionRecord): InstanceCollectionSnapshot {
608
- return {
609
- ...this.info(record),
610
- transforms: new Float32Array(record.transforms),
611
- generations: new Uint32Array(record.generations),
612
- dirtyRanges: record.dirtyRanges.map((range) => ({ ...range })),
613
- };
614
- }
615
-
616
- private info(record: CollectionRecord): InstanceCollectionInfo {
617
- return Object.freeze({
618
- collectionId: record.id,
619
- count: record.count,
620
- capacity: record.capacity,
621
- revision: record.revision,
622
- });
623
- }
624
-
625
- private allocateGenerations(count: number): Uint32Array {
626
- const generations = new Uint32Array(count);
627
- for (let index = 0; index < count; index += 1) {
628
- generations[index] = this.nextInstanceGeneration;
629
- this.nextInstanceGeneration = (this.nextInstanceGeneration + 1) >>> 0 || 1;
630
- }
631
- return generations;
632
- }
633
-
634
- private validateReplacementGenerations(
635
- generations: Uint32Array,
636
- count: number,
637
- collectionId: InstanceCollectionId,
638
- ): InstanceCollectionResult<Uint32Array> {
639
- if (!(generations instanceof Uint32Array) || generations.length !== count) {
640
- return err(
641
- invalid(
642
- 'replace',
643
- `generations is a Uint32Array with ${count} entries`,
644
- generations instanceof Uint32Array ? generations.length : typeof generations,
645
- collectionId,
646
- { requestedBytes: generations?.byteLength ?? 0, cause: 'invalid-generation-shape' },
647
- ),
648
- );
649
- }
650
- const seen = new Set<number>();
651
- for (const generation of generations) {
652
- if (generation === 0 || seen.has(generation)) {
653
- return err(
654
- invalid(
655
- 'replace',
656
- 'generations contain unique non-zero identity tokens',
657
- generation,
658
- collectionId,
659
- {
660
- requestedBytes: generations.byteLength,
661
- cause: 'invalid-generation-identity',
662
- },
663
- ),
664
- );
665
- }
666
- seen.add(generation);
667
- if (generation >= this.nextInstanceGeneration) {
668
- this.nextInstanceGeneration = (generation + 1) >>> 0 || 1;
669
- }
670
- }
671
- return ok(new Uint32Array(generations));
672
- }
673
-
674
- private projectInspection(record: CollectionRecord): InstanceCollectionInspection {
675
- const residency = this.residency.get(record.id);
676
- return Object.freeze({
677
- ...this.info(record),
678
- residentGeneration: residency?.residentGeneration,
679
- lane: residency?.lane ?? 'unresident',
680
- dirtyRanges: Object.freeze(record.dirtyRanges.map((range) => ({ ...range }))),
681
- uploadRanges: Object.freeze(residency?.uploadRanges.map((range) => ({ ...range })) ?? []),
682
- uploadedBytes: residency?.uploadedBytes ?? 0,
683
- requestedBytes: residency?.requestedBytes ?? record.count * MATRIX_STRIDE * 4,
684
- supportedBytes: residency?.supportedBytes,
685
- backend: residency?.backend ?? 'unknown',
686
- owner: 'renderer.instances',
687
- error: residency?.error,
253
+ _inspections(frameNumber: number): readonly InstanceCollectionInspection[] {
254
+ return [...this.records.values()].map((record) => {
255
+ const resident = this.residency.get(record.collectionId);
256
+ const current = resident?.frameNumber === frameNumber;
257
+ return {
258
+ collectionId: record.collectionId,
259
+ count: record.count,
260
+ revision: record.revision,
261
+ residentGeneration: resident?.residentGeneration,
262
+ lane: resident?.lane ?? 'unresident',
263
+ uploadRanges: current ? resident.uploadRanges.map((range) => ({ ...range })) : [],
264
+ uploadedBytes: current ? resident.uploadedBytes : 0,
265
+ requestedBytes: resident?.requestedBytes ?? record.transforms.byteLength,
266
+ supportedBytes: resident?.supportedBytes,
267
+ backend: resident?.backend ?? 'unknown',
268
+ owner: 'renderer.instances',
269
+ error: resident?.error,
270
+ };
688
271
  });
689
272
  }
690
273
  }