@forgeax/engine-render 0.1.32 → 0.1.34

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 +1374 -142
  2. package/dist/assembly/analytic-fog-registration.d.ts +3 -0
  3. package/dist/assembly/analytic-fog-registration.d.ts.map +1 -0
  4. package/dist/assembly/backend-contract.d.ts +2 -0
  5. package/dist/assembly/backend-contract.d.ts.map +1 -1
  6. package/dist/assembly/barrel-distortion-inspection.d.ts +3 -0
  7. package/dist/assembly/barrel-distortion-inspection.d.ts.map +1 -0
  8. package/dist/assembly/canvas-draw-guard.d.ts +3 -0
  9. package/dist/assembly/canvas-draw-guard.d.ts.map +1 -0
  10. package/dist/assembly/cloud-shadow-entry.d.ts +4 -0
  11. package/dist/assembly/cloud-shadow-entry.d.ts.map +1 -0
  12. package/dist/assembly/dynamic-geometry-host.d.ts +4 -1
  13. package/dist/assembly/dynamic-geometry-host.d.ts.map +1 -1
  14. package/dist/assembly/dynamic-geometry-runtime.d.ts +1 -1
  15. package/dist/assembly/dynamic-geometry-runtime.d.ts.map +1 -1
  16. package/dist/assembly/factory.d.ts +1 -1
  17. package/dist/assembly/factory.d.ts.map +1 -1
  18. package/dist/assembly/fxaa-registration.d.ts +4 -0
  19. package/dist/assembly/fxaa-registration.d.ts.map +1 -0
  20. package/dist/assembly/host-contract.d.ts +3 -3
  21. package/dist/assembly/host-contract.d.ts.map +1 -1
  22. package/dist/assembly/lod-observation.d.ts +4 -0
  23. package/dist/assembly/lod-observation.d.ts.map +1 -0
  24. package/dist/assembly/material/assembly.d.ts.map +1 -1
  25. package/dist/assembly/material/pipeline-helpers.d.ts +5 -0
  26. package/dist/assembly/material/pipeline-helpers.d.ts.map +1 -1
  27. package/dist/assembly/material-shader-policy.d.ts +16 -2
  28. package/dist/assembly/material-shader-policy.d.ts.map +1 -1
  29. package/dist/assembly/material-shader-prewarm.d.ts.map +1 -1
  30. package/dist/assembly/motion-blur-registration.d.ts +3 -0
  31. package/dist/assembly/motion-blur-registration.d.ts.map +1 -0
  32. package/dist/assembly/recovery/device-loss-fanout.d.ts.map +1 -1
  33. package/dist/assembly/recovery/renderer-recover.d.ts +2 -0
  34. package/dist/assembly/recovery/renderer-recover.d.ts.map +1 -1
  35. package/dist/assembly/render-feature-post-processes.d.ts +6 -0
  36. package/dist/assembly/render-feature-post-processes.d.ts.map +1 -0
  37. package/dist/assembly/renderer-facade.d.ts.map +1 -1
  38. package/dist/assembly/renderer-feature-inspection.d.ts +1 -1
  39. package/dist/assembly/renderer-feature-inspection.d.ts.map +1 -1
  40. package/dist/assembly/renderer-frame-transaction.d.ts +12 -0
  41. package/dist/assembly/renderer-frame-transaction.d.ts.map +1 -1
  42. package/dist/assembly/renderer-inspection.d.ts +11 -0
  43. package/dist/assembly/renderer-inspection.d.ts.map +1 -1
  44. package/dist/assembly/temporal-post-process-prewarm.d.ts +13 -0
  45. package/dist/assembly/temporal-post-process-prewarm.d.ts.map +1 -0
  46. package/dist/assembly/webgpu-pbr-ready.d.ts +1 -0
  47. package/dist/assembly/webgpu-pbr-ready.d.ts.map +1 -1
  48. package/dist/assembly/webgpu-ready-contract.d.ts +4 -3
  49. package/dist/assembly/webgpu-ready-contract.d.ts.map +1 -1
  50. package/dist/assembly/webgpu-ready-per-pass.d.ts +39 -0
  51. package/dist/assembly/webgpu-ready-per-pass.d.ts.map +1 -0
  52. package/dist/assembly/webgpu-ready.d.ts +2 -2
  53. package/dist/assembly/webgpu-ready.d.ts.map +1 -1
  54. package/dist/assembly/webgpu-renderer-bootstrap.d.ts.map +1 -1
  55. package/dist/assembly/webgpu-renderer-observation-owner.d.ts +35 -0
  56. package/dist/assembly/webgpu-renderer-observation-owner.d.ts.map +1 -0
  57. package/dist/assembly/webgpu-renderer.d.ts +1 -1
  58. package/dist/assembly/webgpu-renderer.d.ts.map +1 -1
  59. package/dist/authoring.mjs +1 -1
  60. package/dist/barrel-distortion.d.ts +47 -0
  61. package/dist/barrel-distortion.d.ts.map +1 -0
  62. package/dist/bloom-admission.d.ts +13 -0
  63. package/dist/bloom-admission.d.ts.map +1 -0
  64. package/dist/{chunk-PA5DRJNI.mjs → chunk-ELJFJ2BU.mjs} +2 -2
  65. package/dist/chunk-ELJFJ2BU.mjs.map +1 -0
  66. package/dist/{chunk-JCIRYQ4V.mjs → chunk-HEB564WF.mjs} +10 -4
  67. package/dist/chunk-HEB564WF.mjs.map +1 -0
  68. package/dist/{chunk-JRIPCMYC.mjs → chunk-MKDIT2EM.mjs} +1584 -375
  69. package/dist/chunk-MKDIT2EM.mjs.map +1 -0
  70. package/dist/{chunk-S665NJNF.mjs → chunk-OCDLEI6I.mjs} +3 -3
  71. package/dist/{chunk-S665NJNF.mjs.map → chunk-OCDLEI6I.mjs.map} +1 -1
  72. package/dist/chunk-ODZWR6JQ.mjs +4927 -0
  73. package/dist/chunk-ODZWR6JQ.mjs.map +1 -0
  74. package/dist/{chunk-DRR7D3KX.mjs → chunk-SHFUFJ5N.mjs} +192 -18
  75. package/dist/chunk-SHFUFJ5N.mjs.map +1 -0
  76. package/dist/{chunk-4NNZQCL3.mjs → chunk-UI5SFODX.mjs} +223 -277
  77. package/dist/chunk-UI5SFODX.mjs.map +1 -0
  78. package/dist/{chunk-GWCEMDVR.mjs → chunk-UINHLCZA.mjs} +787 -80
  79. package/dist/chunk-UINHLCZA.mjs.map +1 -0
  80. package/dist/{chunk-6TFBXLRJ.mjs → chunk-WEX45HKH.mjs} +222 -337
  81. package/dist/chunk-WEX45HKH.mjs.map +1 -0
  82. package/dist/cloud/density.d.ts +55 -0
  83. package/dist/cloud/density.d.ts.map +1 -0
  84. package/dist/cloud/extract.d.ts +25 -0
  85. package/dist/cloud/extract.d.ts.map +1 -0
  86. package/dist/cloud/feature.d.ts +57 -0
  87. package/dist/cloud/feature.d.ts.map +1 -0
  88. package/dist/cloud/frame-context.d.ts +8 -0
  89. package/dist/cloud/frame-context.d.ts.map +1 -0
  90. package/dist/cloud/inspection.d.ts +59 -0
  91. package/dist/cloud/inspection.d.ts.map +1 -0
  92. package/dist/cloud/optics.d.ts +56 -0
  93. package/dist/cloud/optics.d.ts.map +1 -0
  94. package/dist/cloud/parameters.d.ts +73 -0
  95. package/dist/cloud/parameters.d.ts.map +1 -0
  96. package/dist/cloud/resources.d.ts +60 -0
  97. package/dist/cloud/resources.d.ts.map +1 -0
  98. package/dist/cloud/shadow.d.ts +42 -0
  99. package/dist/cloud/shadow.d.ts.map +1 -0
  100. package/dist/cloud/temporal.d.ts +74 -0
  101. package/dist/cloud/temporal.d.ts.map +1 -0
  102. package/dist/components/atmosphere.d.ts +2 -0
  103. package/dist/components/atmosphere.d.ts.map +1 -1
  104. package/dist/components/barrel-distortion.d.ts +13 -0
  105. package/dist/components/barrel-distortion.d.ts.map +1 -0
  106. package/dist/components/camera.d.ts +20 -4
  107. package/dist/components/camera.d.ts.map +1 -1
  108. package/dist/components/cloud-layer.d.ts +29 -0
  109. package/dist/components/cloud-layer.d.ts.map +1 -0
  110. package/dist/components/index.d.ts +2 -0
  111. package/dist/components/index.d.ts.map +1 -1
  112. package/dist/components/instances.d.ts +20 -6
  113. package/dist/components/instances.d.ts.map +1 -1
  114. package/dist/components/mesh-filter.d.ts +6 -5
  115. package/dist/components/mesh-filter.d.ts.map +1 -1
  116. package/dist/components/motion-blur.d.ts +1 -0
  117. package/dist/components/motion-blur.d.ts.map +1 -1
  118. package/dist/construct-renderer.d.ts +1 -1
  119. package/dist/construct-renderer.d.ts.map +1 -1
  120. package/dist/construct-renderer.mjs +9751 -3528
  121. package/dist/construct-renderer.mjs.map +1 -1
  122. package/dist/device/gpu-residency.d.ts +6 -0
  123. package/dist/device/gpu-residency.d.ts.map +1 -1
  124. package/dist/dynamic-geometry.d.ts +5 -1
  125. package/dist/dynamic-geometry.d.ts.map +1 -1
  126. package/dist/environment/analytic-fog.d.ts +6 -0
  127. package/dist/environment/analytic-fog.d.ts.map +1 -0
  128. package/dist/errors/cloud.d.ts +59 -0
  129. package/dist/errors/cloud.d.ts.map +1 -0
  130. package/dist/errors/render.d.ts +23 -5
  131. package/dist/errors/render.d.ts.map +1 -1
  132. package/dist/examples/single-layer-medium-surface.d.ts +47 -0
  133. package/dist/examples/single-layer-medium-surface.d.ts.map +1 -0
  134. package/dist/extract/camera.d.ts.map +1 -1
  135. package/dist/extract/contracts.d.ts +12 -1
  136. package/dist/extract/contracts.d.ts.map +1 -1
  137. package/dist/extract/environment.d.ts +2 -0
  138. package/dist/extract/environment.d.ts.map +1 -1
  139. package/dist/features/barrel-distortion.d.ts +29 -0
  140. package/dist/features/barrel-distortion.d.ts.map +1 -0
  141. package/dist/features/error-reporting.d.ts +17 -0
  142. package/dist/features/error-reporting.d.ts.map +1 -0
  143. package/dist/features/host.d.ts +15 -0
  144. package/dist/features/host.d.ts.map +1 -1
  145. package/dist/features/motion-blur/motion-blur-feature.d.ts +20 -2
  146. package/dist/features/motion-blur/motion-blur-feature.d.ts.map +1 -1
  147. package/dist/features/motion-blur/motion-blur-params.d.ts +21 -0
  148. package/dist/features/motion-blur/motion-blur-params.d.ts.map +1 -1
  149. package/dist/features/motion-blur/motion-blur-runtime.d.ts +54 -0
  150. package/dist/features/motion-blur/motion-blur-runtime.d.ts.map +1 -0
  151. package/dist/features/plan.d.ts +15 -4
  152. package/dist/features/plan.d.ts.map +1 -1
  153. package/dist/features/prepared-gpu-work.d.ts +9 -5
  154. package/dist/features/prepared-gpu-work.d.ts.map +1 -1
  155. package/dist/features/render-graph-compute.d.ts.map +1 -1
  156. package/dist/features/render-graph-contribution.d.ts +5 -0
  157. package/dist/features/render-graph-contribution.d.ts.map +1 -1
  158. package/dist/features/render-graph-raster.d.ts +1 -0
  159. package/dist/features/render-graph-raster.d.ts.map +1 -1
  160. package/dist/features/targets.d.ts +2 -0
  161. package/dist/features/targets.d.ts.map +1 -1
  162. package/dist/features/types.d.ts +44 -0
  163. package/dist/features/types.d.ts.map +1 -1
  164. package/dist/fullscreen-post-process-pass.d.ts +15 -7
  165. package/dist/fullscreen-post-process-pass.d.ts.map +1 -1
  166. package/dist/gpu-dirty-ranges.d.ts +11 -0
  167. package/dist/gpu-dirty-ranges.d.ts.map +1 -0
  168. package/dist/gpu-driven/batch-topology.d.ts +17 -0
  169. package/dist/gpu-driven/batch-topology.d.ts.map +1 -1
  170. package/dist/gpu-driven/material-artifacts.d.ts +6 -0
  171. package/dist/gpu-driven/material-artifacts.d.ts.map +1 -1
  172. package/dist/gpu-driven/prepared-draw.d.ts +7 -0
  173. package/dist/gpu-driven/prepared-draw.d.ts.map +1 -1
  174. package/dist/gpu-driven/production-raster-material.d.ts +178 -0
  175. package/dist/gpu-driven/production-raster-material.d.ts.map +1 -0
  176. package/dist/gpu-driven/production-raster.d.ts +50 -4
  177. package/dist/gpu-driven/production-raster.d.ts.map +1 -1
  178. package/dist/gpu-driven/resource-allocation.d.ts +31 -0
  179. package/dist/gpu-driven/resource-allocation.d.ts.map +1 -0
  180. package/dist/gpu-driven/shadow-ownership.d.ts +14 -0
  181. package/dist/gpu-driven/shadow-ownership.d.ts.map +1 -0
  182. package/dist/gpu-driven/view-gpu.d.ts +35 -2
  183. package/dist/gpu-driven/view-gpu.d.ts.map +1 -1
  184. package/dist/gpu-scene.d.ts +11 -1
  185. package/dist/gpu-scene.d.ts.map +1 -1
  186. package/dist/hdrp-buffers.d.ts +2 -2
  187. package/dist/hdrp-buffers.d.ts.map +1 -1
  188. package/dist/ibl/skylight-bind-group.d.ts +10 -1
  189. package/dist/ibl/skylight-bind-group.d.ts.map +1 -1
  190. package/dist/index.d.ts +31 -8
  191. package/dist/index.d.ts.map +1 -1
  192. package/dist/index.mjs +258 -8
  193. package/dist/index.mjs.map +1 -1
  194. package/dist/inspection-types.d.ts +178 -3
  195. package/dist/inspection-types.d.ts.map +1 -1
  196. package/dist/instance-buffer-cache.d.ts +4 -4
  197. package/dist/instance-buffer-cache.d.ts.map +1 -1
  198. package/dist/instances.d.ts +49 -94
  199. package/dist/instances.d.ts.map +1 -1
  200. package/dist/internal.mjs +7 -7
  201. package/dist/pbr-pipeline.d.ts +19 -1
  202. package/dist/pbr-pipeline.d.ts.map +1 -1
  203. package/dist/pipeline/single-layer-medium-passes.d.ts +73 -0
  204. package/dist/pipeline/single-layer-medium-passes.d.ts.map +1 -0
  205. package/dist/pipeline/standard-forward-lane.d.ts.map +1 -1
  206. package/dist/pipeline/standard-output/graph.d.ts.map +1 -1
  207. package/dist/pipeline/standard-output/types.d.ts +4 -2
  208. package/dist/pipeline/standard-output/types.d.ts.map +1 -1
  209. package/dist/pipeline/standard-pipeline.d.ts.map +1 -1
  210. package/dist/pipeline/standard-post.d.ts +28 -19
  211. package/dist/pipeline/standard-post.d.ts.map +1 -1
  212. package/dist/pipeline-builder.d.ts +1 -1
  213. package/dist/pipeline-builder.d.ts.map +1 -1
  214. package/dist/pipeline-spec.d.ts +2 -2
  215. package/dist/plugin.d.ts.map +1 -1
  216. package/dist/prepare/prepared-graphics-resolver.d.ts +2 -0
  217. package/dist/prepare/prepared-graphics-resolver.d.ts.map +1 -1
  218. package/dist/record/barrel-distortion-frame.d.ts +15 -0
  219. package/dist/record/barrel-distortion-frame.d.ts.map +1 -0
  220. package/dist/record/dynamic-geometry-consumption.d.ts +10 -2
  221. package/dist/record/dynamic-geometry-consumption.d.ts.map +1 -1
  222. package/dist/record/fold-buckets.d.ts +95 -0
  223. package/dist/record/fold-buckets.d.ts.map +1 -0
  224. package/dist/record/fold-instance-buffer.d.ts +6 -0
  225. package/dist/record/fold-instance-buffer.d.ts.map +1 -0
  226. package/dist/record/frame-lighting.d.ts +1 -0
  227. package/dist/record/frame-lighting.d.ts.map +1 -1
  228. package/dist/record/frame-snapshot.d.ts +40 -3
  229. package/dist/record/frame-snapshot.d.ts.map +1 -1
  230. package/dist/record/frame-targets.d.ts.map +1 -1
  231. package/dist/record/frame.d.ts +14 -62
  232. package/dist/record/frame.d.ts.map +1 -1
  233. package/dist/record/gpu-draw-receipts.d.ts +11 -0
  234. package/dist/record/gpu-draw-receipts.d.ts.map +1 -0
  235. package/dist/record/gpu-timing.d.ts +8 -0
  236. package/dist/record/gpu-timing.d.ts.map +1 -1
  237. package/dist/record/main-pass-geometry.d.ts +21 -5
  238. package/dist/record/main-pass-geometry.d.ts.map +1 -1
  239. package/dist/record/main-pass-material.d.ts +7 -1
  240. package/dist/record/main-pass-material.d.ts.map +1 -1
  241. package/dist/record/main-pass-sprite-draws.d.ts.map +1 -1
  242. package/dist/record/main-pass.d.ts +13 -2
  243. package/dist/record/main-pass.d.ts.map +1 -1
  244. package/dist/record/mesh-ssbo.d.ts +6 -5
  245. package/dist/record/mesh-ssbo.d.ts.map +1 -1
  246. package/dist/record/motion-blur-receipt.d.ts +11 -0
  247. package/dist/record/motion-blur-receipt.d.ts.map +1 -0
  248. package/dist/record/probe-blend-buffer.d.ts +16 -0
  249. package/dist/record/probe-blend-buffer.d.ts.map +1 -0
  250. package/dist/record/recovery-pipeline.d.ts.map +1 -1
  251. package/dist/record/render-context.d.ts +34 -31
  252. package/dist/record/render-context.d.ts.map +1 -1
  253. package/dist/record/shadow-pass.d.ts +2 -0
  254. package/dist/record/shadow-pass.d.ts.map +1 -1
  255. package/dist/record/skybox-post-pass.d.ts +6 -4
  256. package/dist/record/skybox-post-pass.d.ts.map +1 -1
  257. package/dist/record/typed-frame-graph.d.ts +22 -2
  258. package/dist/record/typed-frame-graph.d.ts.map +1 -1
  259. package/dist/record/view-ubo.d.ts +11 -3
  260. package/dist/record/view-ubo.d.ts.map +1 -1
  261. package/dist/record/volume-params.d.ts +9 -0
  262. package/dist/record/volume-params.d.ts.map +1 -0
  263. package/dist/recovery/render-system-candidate.d.ts +10 -0
  264. package/dist/recovery/render-system-candidate.d.ts.map +1 -1
  265. package/dist/reflection/record-owner.d.ts.map +1 -1
  266. package/dist/render-contract.d.ts +66 -8
  267. package/dist/render-contract.d.ts.map +1 -1
  268. package/dist/render-graph-primitives.d.ts.map +1 -1
  269. package/dist/render-pipeline.d.ts +106 -3
  270. package/dist/render-pipeline.d.ts.map +1 -1
  271. package/dist/render-system-extract-tail.d.ts +3 -2
  272. package/dist/render-system-extract-tail.d.ts.map +1 -1
  273. package/dist/render-system-extract.d.ts +24 -10
  274. package/dist/render-system-extract.d.ts.map +1 -1
  275. package/dist/render-system-presentation.d.ts +23 -0
  276. package/dist/render-system-presentation.d.ts.map +1 -0
  277. package/dist/render-system-producer-roots.d.ts +10 -0
  278. package/dist/render-system-producer-roots.d.ts.map +1 -0
  279. package/dist/render-system-residency.d.ts +12 -0
  280. package/dist/render-system-residency.d.ts.map +1 -0
  281. package/dist/render-system.d.ts +26 -15
  282. package/dist/render-system.d.ts.map +1 -1
  283. package/dist/scene/probe-blend.d.ts +27 -0
  284. package/dist/scene/probe-blend.d.ts.map +1 -1
  285. package/dist/scene/render-scene.d.ts +14 -5
  286. package/dist/scene/render-scene.d.ts.map +1 -1
  287. package/dist/ssao-buffers.d.ts +9 -0
  288. package/dist/ssao-buffers.d.ts.map +1 -1
  289. package/dist/surface/dynamic-input.d.ts +133 -0
  290. package/dist/surface/dynamic-input.d.ts.map +1 -0
  291. package/dist/surface/gpu-driven.d.ts +41 -0
  292. package/dist/surface/gpu-driven.d.ts.map +1 -0
  293. package/dist/surface/submission-observation.d.ts +136 -0
  294. package/dist/surface/submission-observation.d.ts.map +1 -0
  295. package/dist/systems/skin-palette-allocator.d.ts.map +1 -1
  296. package/dist/temporal/frame-coordinator.d.ts.map +1 -1
  297. package/dist/temporal/frame.d.ts +7 -0
  298. package/dist/temporal/frame.d.ts.map +1 -1
  299. package/dist/temporal/gpu.d.ts +13 -1
  300. package/dist/temporal/gpu.d.ts.map +1 -1
  301. package/dist/temporal/index.mjs +5 -5
  302. package/dist/temporal/inspection.d.ts.map +1 -1
  303. package/dist/temporal/standard-scene-data.d.ts.map +1 -1
  304. package/dist/temporal/target-coverage-attachment.d.ts.map +1 -1
  305. package/dist/temporal/view.d.ts +6 -1
  306. package/dist/temporal/view.d.ts.map +1 -1
  307. package/dist/transmission/single-layer-medium.d.ts +89 -0
  308. package/dist/transmission/single-layer-medium.d.ts.map +1 -0
  309. package/dist/typed-render-graph-primitives.d.ts +24 -9
  310. package/dist/typed-render-graph-primitives.d.ts.map +1 -1
  311. package/dist/volume/component.d.ts +9 -5
  312. package/dist/volume/component.d.ts.map +1 -1
  313. package/dist/volume/extract.d.ts +1 -1
  314. package/dist/volume/extract.d.ts.map +1 -1
  315. package/dist/volume/inspection.d.ts +2 -0
  316. package/dist/volume/inspection.d.ts.map +1 -1
  317. package/dist/volume/passes.d.ts +4 -1
  318. package/dist/volume/passes.d.ts.map +1 -1
  319. package/dist/volume/resources.d.ts.map +1 -1
  320. package/dist/volume/temporal.d.ts +3 -1
  321. package/dist/volume/temporal.d.ts.map +1 -1
  322. package/package.json +22 -21
  323. package/src/__tests__/analytic-fog-graph.unit.test.ts +199 -0
  324. package/src/__tests__/analytic-fog-optics.unit.test.ts +38 -0
  325. package/src/__tests__/atmosphere-daylight.dawn.test.ts +72 -0
  326. package/src/__tests__/barrel-distortion-lkg.integration.test.ts +353 -0
  327. package/src/__tests__/barrel-distortion.dawn.test.ts +41 -0
  328. package/src/__tests__/barrel-distortion.unit.test.ts +364 -0
  329. package/src/__tests__/bloom-exact-zero.unit.test.ts +112 -18
  330. package/src/__tests__/bloom-lifecycle.integration.test.ts +17 -4
  331. package/src/__tests__/construct-renderer-identity.unit.test.ts +49 -0
  332. package/src/__tests__/detached-recovery-graph.unit.test.ts +277 -0
  333. package/src/__tests__/device-loss-fanout.unit.test.ts +36 -1
  334. package/src/__tests__/docs-gate-green.unit.test.ts +112 -1
  335. package/src/__tests__/dynamic-resolution-plugin.integration.test.ts +20 -0
  336. package/src/__tests__/environment-fog-lanes.integration.test.ts +14 -0
  337. package/src/__tests__/environment-selection.unit.test.ts +12 -0
  338. package/src/__tests__/factory-contract.integration.test.ts +626 -113
  339. package/src/__tests__/feature-depth-input.dawn.test.ts +129 -2
  340. package/src/__tests__/frame-camera-selection.unit.test.ts +39 -1
  341. package/src/__tests__/frame-plan-contract.unit.test.ts +2 -0
  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-indirect-raster-evidence.ts +2 -1
  347. package/src/__tests__/gpu-driven-material-artifacts.unit.test.ts +143 -0
  348. package/src/__tests__/gpu-driven-pbr.dawn.test.ts +2 -2
  349. package/src/__tests__/gpu-driven-production.integration.test.ts +482 -3
  350. package/src/__tests__/gpu-driven-shadow-views.dawn.test.ts +7 -6
  351. package/src/__tests__/gpu-driven-shadow-views.integration.test.ts +1 -1
  352. package/src/__tests__/gpu-driven-view-gpu-evidence.ts +103 -4
  353. package/src/__tests__/gpu-driven-view-graph.integration.test.ts +18 -2
  354. package/src/__tests__/gpu-driven-view.browser.test.ts +5 -8
  355. package/src/__tests__/gpu-driven-view.dawn.test.ts +6 -2
  356. package/src/__tests__/gpu-driven-view.unit.test.ts +1 -1
  357. package/src/__tests__/gpu-pass-timing-lifecycle.integration.test.ts +1 -0
  358. package/src/__tests__/gpu-pass-timing.browser.test.ts +6 -4
  359. package/src/__tests__/gpu-pass-timing.rhi-null.unit.test.ts +1 -0
  360. package/src/__tests__/gpu-resource-store-stride.unit.test.ts +12 -0
  361. package/src/__tests__/gpu-scene.unit.test.ts +210 -9
  362. package/src/__tests__/instance-allocation-failure.unit.test.ts +57 -0
  363. package/src/__tests__/instances-culling.integration.test.ts +10 -36
  364. package/src/__tests__/instances-store.unit.test.ts +105 -238
  365. package/src/__tests__/instances-world-ownership.integration.test.ts +62 -0
  366. package/src/__tests__/main-pass-material-medium-selection.unit.test.ts +146 -0
  367. package/src/__tests__/material-shader-prewarm.unit.test.ts +59 -0
  368. package/src/__tests__/material-snapshot-mutation.integration.test.ts +39 -1
  369. package/src/__tests__/mesh-submission-lifetime.unit.test.ts +31 -0
  370. package/src/__tests__/morph-culling-reentry.dawn.test.ts +5 -5
  371. package/src/__tests__/morph-visual-evidence.integration.test.ts +8 -7
  372. package/src/__tests__/motion-blur-compute.dawn.test.ts +589 -0
  373. package/src/__tests__/motion-blur.pixel.integration.test.ts +2 -2
  374. package/src/__tests__/nineslice-handle-surface.unit.test.ts +4 -4
  375. package/src/__tests__/pbr-view-layout.unit.test.ts +9 -0
  376. package/src/__tests__/physical-clearcoat.integration.test.ts +58 -0
  377. package/src/__tests__/prepared-gpu-driven-pbr.integration.test.ts +21 -0
  378. package/src/__tests__/prepared-graphics-capability.unit.test.ts +66 -2
  379. package/src/__tests__/prepared-graphics-lifecycle.unit.test.ts +86 -0
  380. package/src/__tests__/probe-bindings.unit.test.ts +582 -1
  381. package/src/__tests__/probe-scene-dirty.integration.test.ts +28 -1
  382. package/src/__tests__/public-surface.test-d.ts +8 -0
  383. package/src/__tests__/receipt-observation-retirement.unit.test.ts +65 -0
  384. package/src/__tests__/recovery-candidate-prepare.contract.test.ts +69 -0
  385. package/src/__tests__/render-error-code-owner.test-d.ts +9 -0
  386. package/src/__tests__/render-feature-diagnostics.unit.test.ts +15 -2
  387. package/src/__tests__/render-feature-error-reporting.unit.test.ts +44 -0
  388. package/src/__tests__/render-feature-prepared-diagnostics.unit.test.ts +10 -1
  389. package/src/__tests__/render-feature-retry.unit.test.ts +12 -1
  390. package/src/__tests__/render-feature-stage-fault-recovery.unit.test.ts +23 -0
  391. package/src/__tests__/render-scene-mixed-updates.integration.test.ts +145 -19
  392. package/src/__tests__/render-scene-projection.unit.test.ts +36 -11
  393. package/src/__tests__/render-scene-temporal-retry.unit.test.ts +37 -6
  394. package/src/__tests__/render-target-probe-soak.perf.test.ts +2 -2
  395. package/src/__tests__/render-temporal-environment-consumer.browser.test.ts +3 -3
  396. package/src/__tests__/render-temporal-environment-consumer.dawn.test.ts +5 -2
  397. package/src/__tests__/renderer-factory-material-contract.unit.test.ts +41 -7
  398. package/src/__tests__/renderer-frame-generation-fence.integration.test.ts +16 -0
  399. package/src/__tests__/renderer-frame-transaction.integration.test.ts +33 -11
  400. package/src/__tests__/resource-allocation.unit.test.ts +123 -0
  401. package/src/__tests__/shader-manifest-fixture.ts +4 -4
  402. package/src/__tests__/single-layer-medium-passes.unit.test.ts +275 -0
  403. package/src/__tests__/skin-motion-regression.unit.test.ts +70 -1
  404. package/src/__tests__/skin-palette-recycling.dawn.test.ts +97 -0
  405. package/src/__tests__/skinned-shadow-caster.test.ts +17 -0
  406. package/src/__tests__/ssr-carrier-public-contract.unit.test.ts +21 -0
  407. package/src/__tests__/ssr-gpu-dispatch.browser.test.ts +4 -4
  408. package/src/__tests__/ssr-gpu-dispatch.dawn.test.ts +2 -2
  409. package/src/__tests__/ssr-gpu-dispatch.ts +1 -1
  410. package/src/__tests__/ssr-receiver-coverage.dawn.test.ts +6 -2
  411. package/src/__tests__/standard-lighting-write.unit.test.ts +2 -1
  412. package/src/__tests__/standard-output-chain-contract.unit.test.ts +28 -0
  413. package/src/__tests__/standard-pbr-artifact-assembly.unit.test.ts +46 -1
  414. package/src/__tests__/standard-pipeline.dawn.test.ts +1 -1
  415. package/src/__tests__/standard-pipeline.integration.test.ts +200 -9
  416. package/src/__tests__/surface-dynamic-buffer-lifecycle.unit.test.ts +506 -0
  417. package/src/__tests__/surface-submission-observation.unit.test.ts +812 -0
  418. package/src/__tests__/temporal-history-lifecycle.unit.test.ts +32 -0
  419. package/src/__tests__/temporal-performance.integration.test.ts +3 -3
  420. package/src/__tests__/temporal-reset-matrix.unit.test.ts +10 -0
  421. package/src/__tests__/temporal-view.unit.test.ts +2 -1
  422. package/src/__tests__/typed-pipeline-topology.unit.test.ts +20 -4
  423. package/src/__tests__/visibility-instances.integration.test.ts +7 -19
  424. package/src/__tests__/visibility-producer-matrix.integration.test.ts +9 -20
  425. package/src/__tests__/volume-optics-oracle.unit.test.ts +7 -3
  426. package/src/__tests__/volumetric-fog-budget-recovery.integration.test.ts +189 -15
  427. package/src/__tests__/volumetric-fog-errors.unit.test.ts +4 -3
  428. package/src/__tests__/volumetric-fog-multiple.unit.test.ts +55 -0
  429. package/src/__tests__/volumetric-fog-spot-frame-optics.integration.test.ts +1 -1
  430. package/src/__tests__/volumetric-fog-stage-readback.dawn.test.ts +558 -68
  431. package/src/__tests__/volumetric-fog-temporal.unit.test.ts +27 -0
  432. package/src/__tests__/volumetric-fog-topology.unit.test.ts +23 -5
  433. package/src/assembly/analytic-fog-registration.ts +14 -0
  434. package/src/assembly/backend-contract.ts +30 -0
  435. package/src/assembly/barrel-distortion-inspection.ts +22 -0
  436. package/src/assembly/canvas-draw-guard.ts +11 -0
  437. package/src/assembly/cloud-shadow-entry.ts +22 -0
  438. package/src/assembly/dynamic-geometry-host.ts +65 -37
  439. package/src/assembly/dynamic-geometry-runtime.ts +7 -1
  440. package/src/assembly/factory.ts +2 -30
  441. package/src/assembly/fxaa-registration.ts +17 -0
  442. package/src/assembly/host-contract.ts +3 -3
  443. package/src/assembly/lod-observation.ts +12 -0
  444. package/src/assembly/material/assembly.ts +25 -13
  445. package/src/assembly/material/pipeline-helpers.ts +53 -12
  446. package/src/assembly/material-shader-policy.ts +55 -0
  447. package/src/assembly/material-shader-prewarm.ts +21 -10
  448. package/src/assembly/motion-blur-registration.ts +17 -0
  449. package/src/assembly/recovery/device-loss-fanout.ts +13 -0
  450. package/src/assembly/recovery/renderer-recover.ts +41 -18
  451. package/src/assembly/render-feature-post-processes.ts +54 -0
  452. package/src/assembly/renderer-facade.ts +6 -1
  453. package/src/assembly/renderer-feature-inspection.ts +8 -2
  454. package/src/assembly/renderer-frame-transaction.ts +23 -0
  455. package/src/assembly/renderer-inspection.ts +28 -0
  456. package/src/assembly/skin-palette-owner.ts +1 -1
  457. package/src/assembly/temporal-post-process-prewarm.ts +40 -0
  458. package/src/assembly/webgpu-pbr-ready.ts +9 -1
  459. package/src/assembly/webgpu-ready-contract.ts +8 -3
  460. package/src/assembly/webgpu-ready-per-pass.ts +104 -0
  461. package/src/assembly/webgpu-ready.ts +296 -306
  462. package/src/assembly/webgpu-renderer-bootstrap.ts +0 -12
  463. package/src/assembly/webgpu-renderer-observation-owner.ts +222 -0
  464. package/src/assembly/webgpu-renderer.ts +228 -281
  465. package/src/assembly/webgpu-vertex-layouts.ts +1 -1
  466. package/src/barrel-distortion.ts +247 -0
  467. package/src/bloom-admission.ts +21 -0
  468. package/src/cloud/__tests__/cloud-density-parity.dawn.test.ts +173 -0
  469. package/src/cloud/__tests__/cloud-layer-framebuffer-y.dawn.test.ts +265 -0
  470. package/src/cloud/__tests__/cloud-layer.browser.test.ts +432 -0
  471. package/src/cloud/__tests__/cloud-layer.unit.test.ts +634 -0
  472. package/src/cloud/density.ts +600 -0
  473. package/src/cloud/extract.ts +110 -0
  474. package/src/cloud/feature.ts +1810 -0
  475. package/src/cloud/frame-context.ts +42 -0
  476. package/src/cloud/inspection.ts +130 -0
  477. package/src/cloud/optics.ts +285 -0
  478. package/src/cloud/parameters.ts +255 -0
  479. package/src/cloud/resources.ts +122 -0
  480. package/src/cloud/shadow.ts +167 -0
  481. package/src/cloud/temporal.ts +226 -0
  482. package/src/components/__tests__/motion-blur.unit.test.ts +1 -0
  483. package/src/components/atmosphere.ts +4 -0
  484. package/src/components/barrel-distortion.ts +46 -0
  485. package/src/components/camera.ts +66 -10
  486. package/src/components/cloud-layer.ts +47 -0
  487. package/src/components/index.ts +2 -0
  488. package/src/components/instances.ts +18 -45
  489. package/src/components/mesh-filter.ts +11 -9
  490. package/src/components/motion-blur.ts +1 -0
  491. package/src/components/sprite-instances.ts +1 -1
  492. package/src/construct-renderer.ts +1 -1
  493. package/src/device/gpu-residency.ts +56 -12
  494. package/src/dynamic-geometry.ts +12 -1
  495. package/src/environment/analytic-fog.ts +44 -0
  496. package/src/environment/background.ts +2 -2
  497. package/src/errors/cloud.ts +103 -0
  498. package/src/errors/render.ts +58 -8
  499. package/src/examples/single-layer-medium-surface.ts +59 -0
  500. package/src/extract/camera.ts +35 -8
  501. package/src/extract/contracts.ts +12 -0
  502. package/src/extract/environment.ts +4 -0
  503. package/src/features/barrel-distortion.ts +172 -0
  504. package/src/features/error-reporting.ts +98 -0
  505. package/src/features/host.ts +138 -24
  506. package/src/features/motion-blur/__tests__/motion-blur-feature.unit.test.ts +111 -1
  507. package/src/features/motion-blur/__tests__/motion-blur-params.unit.test.ts +58 -3
  508. package/src/features/motion-blur/motion-blur-feature.ts +1519 -15
  509. package/src/features/motion-blur/motion-blur-params.ts +70 -2
  510. package/src/features/motion-blur/motion-blur-runtime.ts +176 -0
  511. package/src/features/plan.ts +33 -8
  512. package/src/features/prepared-gpu-work.ts +86 -35
  513. package/src/features/render-graph-compute.ts +13 -5
  514. package/src/features/render-graph-contribution.ts +11 -0
  515. package/src/features/render-graph-raster.ts +45 -3
  516. package/src/features/targets.ts +66 -0
  517. package/src/features/types.ts +47 -0
  518. package/src/fullscreen-post-process-pass.ts +41 -9
  519. package/src/gpu-dirty-ranges.ts +48 -0
  520. package/src/gpu-driven/batch-topology.ts +53 -0
  521. package/src/gpu-driven/material-artifacts.ts +35 -32
  522. package/src/gpu-driven/prepared-draw.ts +27 -14
  523. package/src/gpu-driven/production-raster-material.ts +1894 -0
  524. package/src/gpu-driven/production-raster.ts +904 -787
  525. package/src/gpu-driven/resource-allocation.ts +142 -0
  526. package/src/gpu-driven/shadow-ownership.ts +71 -0
  527. package/src/gpu-driven/view-gpu.ts +181 -10
  528. package/src/gpu-scene.ts +259 -101
  529. package/src/hdrp-buffers.ts +4 -3
  530. package/src/ibl/skylight-bind-group.ts +49 -7
  531. package/src/index.ts +228 -9
  532. package/src/inspection-types.ts +222 -2
  533. package/src/instance-buffer-cache.ts +4 -4
  534. package/src/instances.ts +151 -492
  535. package/src/pbr-pipeline.ts +219 -13
  536. package/src/pipeline/single-layer-medium-passes.ts +267 -0
  537. package/src/pipeline/standard-forward-lane.ts +313 -57
  538. package/src/pipeline/standard-output/graph.ts +8 -2
  539. package/src/pipeline/standard-output/types.ts +12 -1
  540. package/src/pipeline/standard-pipeline.ts +291 -18
  541. package/src/pipeline/standard-post.ts +397 -102
  542. package/src/pipeline-builder.ts +1 -1
  543. package/src/pipeline-spec.ts +5 -5
  544. package/src/plugin.ts +4 -0
  545. package/src/points-lines/__tests__/points-lines.bench.ts +17 -8
  546. package/src/points-lines/__tests__/view-ubo.unit.test.ts +2 -1
  547. package/src/prepare/prepared-graphics-resolver.ts +2 -0
  548. package/src/record/__tests__/main-pass-geometry.unit.test.ts +30 -0
  549. package/src/record/__tests__/sprite-material-abi.unit.test.ts +1 -1
  550. package/src/record/__tests__/temporal-payload.unit.test.ts +3 -2
  551. package/src/record/__tests__/transparent-group2-selection.unit.test.ts +11 -0
  552. package/src/record/__tests__/typed-frame-graph-plan.unit.test.ts +1 -0
  553. package/src/record/__tests__/view-ubo-layout.unit.test.ts +4 -3
  554. package/src/record/barrel-distortion-frame.ts +110 -0
  555. package/src/record/dynamic-geometry-consumption.ts +39 -9
  556. package/src/record/fold-buckets.ts +852 -0
  557. package/src/record/fold-instance-buffer.ts +51 -0
  558. package/src/record/frame-lighting.ts +36 -2
  559. package/src/record/frame-snapshot.ts +44 -4
  560. package/src/record/frame-targets.ts +10 -6
  561. package/src/record/frame.ts +373 -1099
  562. package/src/record/gpu-draw-receipts.ts +38 -0
  563. package/src/record/gpu-timing.ts +48 -5
  564. package/src/record/main-pass-geometry.ts +281 -83
  565. package/src/record/main-pass-material.ts +66 -4
  566. package/src/record/main-pass-sprite-draws.ts +13 -66
  567. package/src/record/main-pass.ts +156 -20
  568. package/src/record/mesh-ssbo.ts +43 -6
  569. package/src/record/motion-blur-receipt.ts +91 -0
  570. package/src/record/probe-blend-buffer.ts +180 -0
  571. package/src/record/recovery-pipeline.ts +35 -3
  572. package/src/record/render-context.ts +51 -31
  573. package/src/record/shadow-pass.ts +36 -2
  574. package/src/record/skybox-post-pass.ts +150 -200
  575. package/src/record/typed-frame-graph.ts +824 -44
  576. package/src/record/view-ubo.ts +26 -3
  577. package/src/record/volume-params.ts +225 -0
  578. package/src/recovery/render-system-candidate.ts +257 -52
  579. package/src/reflection/record-owner.ts +7 -3
  580. package/src/render-contract.ts +71 -8
  581. package/src/render-graph-primitives.ts +7 -1
  582. package/src/render-pipeline.ts +136 -1
  583. package/src/render-system-extract-tail.ts +72 -60
  584. package/src/render-system-extract.ts +117 -87
  585. package/src/render-system-presentation.ts +56 -0
  586. package/src/render-system-producer-roots.ts +96 -0
  587. package/src/render-system-residency.ts +159 -0
  588. package/src/render-system.ts +601 -482
  589. package/src/scene/probe-blend.ts +96 -4
  590. package/src/scene/render-scene.ts +431 -281
  591. package/src/ssao-buffers.ts +95 -2
  592. package/src/surface/__tests__/dynamic-input.unit.test.ts +374 -0
  593. package/src/surface/__tests__/gpu-driven.unit.test.ts +87 -0
  594. package/src/surface/dynamic-input.ts +658 -0
  595. package/src/surface/gpu-driven.ts +147 -0
  596. package/src/surface/submission-observation.ts +517 -0
  597. package/src/systems/skin-palette-allocator.ts +4 -1
  598. package/src/temporal/__tests__/temporal-frame-transaction.unit.test.ts +36 -0
  599. package/src/temporal/frame-coordinator.ts +8 -1
  600. package/src/temporal/frame.ts +20 -0
  601. package/src/temporal/gpu.ts +101 -17
  602. package/src/temporal/inspection.ts +7 -1
  603. package/src/temporal/standard-scene-data.ts +5 -0
  604. package/src/temporal/target-coverage-attachment.ts +4 -0
  605. package/src/temporal/view.ts +13 -2
  606. package/src/transmission/__tests__/single-layer-medium.unit.test.ts +149 -0
  607. package/src/transmission/__tests__/standard-transmission.dawn.test.ts +12 -11
  608. package/src/transmission/single-layer-medium.ts +322 -0
  609. package/src/typed-render-graph-primitives.ts +191 -50
  610. package/src/volume/component.ts +10 -10
  611. package/src/volume/extract.ts +11 -5
  612. package/src/volume/inspection.ts +3 -0
  613. package/src/volume/passes.ts +95 -8
  614. package/src/volume/resources.ts +2 -1
  615. package/src/volume/temporal.ts +11 -0
  616. package/dist/chunk-4NNZQCL3.mjs.map +0 -1
  617. package/dist/chunk-6TFBXLRJ.mjs.map +0 -1
  618. package/dist/chunk-DRR7D3KX.mjs.map +0 -1
  619. package/dist/chunk-GWCEMDVR.mjs.map +0 -1
  620. package/dist/chunk-JCIRYQ4V.mjs.map +0 -1
  621. package/dist/chunk-JRIPCMYC.mjs.map +0 -1
  622. package/dist/chunk-LULCA3OF.mjs +0 -1713
  623. package/dist/chunk-LULCA3OF.mjs.map +0 -1
  624. package/dist/chunk-PA5DRJNI.mjs.map +0 -1
@@ -1,3 +1,4 @@
1
+ import { RuntimeMeshVertices } from '@forgeax/engine-assets-runtime';
1
2
  import { World } from '@forgeax/engine-ecs';
2
3
  import { createRenderReadLease } from '@forgeax/engine-ecs/projection';
3
4
  import { vec3 } from '@forgeax/engine-math';
@@ -16,7 +17,7 @@ import {
16
17
  PointLightShadow,
17
18
  SpotLight,
18
19
  } from '../components';
19
- import { InstanceCollectionStore } from '../instances';
20
+ import { InstanceProjectionStore } from '../instances';
20
21
  import { makeZeroCameraFallbackSnapshot } from '../record/frame-snapshot';
21
22
  import type {
22
23
  DispatchEntry,
@@ -302,13 +303,12 @@ describe('RenderScene canonical owner', () => {
302
303
 
303
304
  it('classifies an Instances-only collection revision without widening the content update', () => {
304
305
  const world = new World();
305
- const instanceCollections = new InstanceCollectionStore();
306
+ const instanceCollections = new InstanceProjectionStore();
306
307
  const initialTransforms = new Float32Array(16);
307
308
  initialTransforms[0] = 1;
308
309
  initialTransforms[5] = 1;
309
310
  initialTransforms[10] = 1;
310
311
  initialTransforms[15] = 1;
311
- const collection = instanceCollections.create({ transforms: initialTransforms }).unwrap();
312
312
  const entity = world
313
313
  .spawn(
314
314
  {
@@ -317,14 +317,18 @@ describe('RenderScene canonical owner', () => {
317
317
  },
318
318
  { component: MeshFilter, data: { assetHandle: 1 as never } },
319
319
  { component: MeshRenderer, data: { materials: [] } },
320
- { component: Instances, data: { collectionId: collection.collectionId } },
320
+ { component: Instances, data: { transforms: initialTransforms } },
321
321
  )
322
322
  .unwrap();
323
323
  const lease = createRenderReadLease(world);
324
324
  const requests: PersistentRenderCandidateRequest[] = [];
325
325
  const build = (request: PersistentRenderCandidateRequest): ExtractedFrame => {
326
326
  requests.push(request);
327
- const detached = instanceCollections.snapshot(collection.collectionId).unwrap();
327
+ const detached = instanceCollections.project(
328
+ world,
329
+ entity,
330
+ world.get(entity, Instances).unwrap().transforms,
331
+ );
328
332
  return {
329
333
  cameras: [{ ...makeZeroCameraFallbackSnapshot(), worldId: 0, entityKey: 1 }],
330
334
  renderables: [
@@ -349,7 +353,7 @@ describe('RenderScene canonical owner', () => {
349
353
  ]);
350
354
  const nextTransforms = new Float32Array(initialTransforms);
351
355
  nextTransforms[12] = 4;
352
- instanceCollections.replace(collection.collectionId, nextTransforms).unwrap();
356
+ world.set(entity, Instances, { transforms: nextTransforms }).unwrap();
353
357
  persistent.extractComposition([world], { cameraOwner: 0, resourceOwner: 0 }, 0, build, [
354
358
  lease,
355
359
  ]);
@@ -734,8 +738,8 @@ describe('RenderScene canonical owner', () => {
734
738
  const world = new World();
735
739
  const lease = createRenderReadLease(world);
736
740
  const handle = world.allocSharedRef('MeshAsset', { kind: 'mesh' });
737
- const onSharedRefMutation = vi.fn();
738
- const persistent = new PersistentRenderScene({ onSharedRefMutation });
741
+ const onRuntimeAssetChange = vi.fn();
742
+ const persistent = new PersistentRenderScene({ onRuntimeAssetChange });
739
743
  const frame = {
740
744
  cameras: [],
741
745
  renderables: [],
@@ -746,12 +750,12 @@ describe('RenderScene canonical owner', () => {
746
750
  persistent.extractComposition([world], { cameraOwner: 0, resourceOwner: 0 }, 0, () => frame, [
747
751
  lease,
748
752
  ]);
749
- world.sharedRefs.markChanged(handle).unwrap();
753
+ world.spawn({ component: RuntimeMeshVertices, data: { asset: handle, vertices: [] } }).unwrap();
750
754
  persistent.extractComposition([world], { cameraOwner: 0, resourceOwner: 0 }, 0, () => frame, [
751
755
  lease,
752
756
  ]);
753
757
 
754
- expect(onSharedRefMutation).toHaveBeenCalledWith(0, handle);
758
+ expect(onRuntimeAssetChange).toHaveBeenCalledWith(0, handle);
755
759
  lease.dispose();
756
760
  persistent.dispose();
757
761
  });
@@ -974,6 +978,7 @@ describe('RenderScene canonical owner', () => {
974
978
  expect(projected.renderables).toEqual(cameraMoved.renderables);
975
979
  expect(projected.dispatch).toEqual(cameraMoved.dispatch);
976
980
  expect(initial.renderables).toHaveLength(1);
981
+ // Transform spans update poses without a second source-identity scan.
977
982
  expect(persistent.inspect()).toMatchObject({ fullRebuilds: 1, worldEntitiesScanned: 0 });
978
983
  } finally {
979
984
  lease.dispose();
@@ -1373,7 +1378,7 @@ describe('RenderScene', () => {
1373
1378
  } as unknown as ExtractedFrame;
1374
1379
 
1375
1380
  const projected = scene.extractComposition(
1376
- [{} as World],
1381
+ [new World()],
1377
1382
  { cameraOwner: 0, resourceOwner: 0 },
1378
1383
  0,
1379
1384
  () => frame,
@@ -1515,3 +1520,23 @@ describe('projected bounds query', () => {
1515
1520
  scene.dispose();
1516
1521
  });
1517
1522
  });
1523
+
1524
+ it('does not publish an earlier transform when later CPU candidate preparation fails', () => {
1525
+ const scene = new RenderScene();
1526
+ scene.apply([updateSnapshot(snapshot(1, 0)), updateSnapshot(snapshot(2, 0))]);
1527
+ const changed = snapshot(1, 7).transform.world;
1528
+ const malformed = snapshot(2, 9);
1529
+ Object.defineProperty(malformed, 'transform', {
1530
+ get() {
1531
+ throw new Error('candidate copy failure');
1532
+ },
1533
+ });
1534
+ expect(() =>
1535
+ scene.apply([
1536
+ { kind: 'update', worldId: 0, entityKey: 1, world: changed },
1537
+ updateSnapshot(malformed),
1538
+ ]),
1539
+ ).toThrow('candidate copy failure');
1540
+ expect(scene.slot(0, 1)?.snapshot.transform.world[12]).toBe(0);
1541
+ expect(scene.slot(0, 2)?.snapshot.transform.world[12]).toBe(0);
1542
+ });
@@ -1,5 +1,6 @@
1
+ import { World } from '@forgeax/engine-ecs';
1
2
  import { describe, expect, it } from 'vitest';
2
- import { type InstanceCollectionSnapshot, InstanceCollectionStore } from '../instances';
3
+ import { type InstanceCollectionSnapshot, InstanceProjectionStore } from '../instances';
3
4
  import type { MaterialSnapshot, RenderableSnapshot } from '../render-system-extract';
4
5
  import { RenderScene } from '../scene/render-scene';
5
6
 
@@ -93,11 +94,11 @@ describe('RenderScene temporal retry boundary', () => {
93
94
  });
94
95
 
95
96
  it('keeps last committed root and Instances data across a failed mixed frame and retry', () => {
96
- const instanceCollections = new InstanceCollectionStore();
97
- const collection = instanceCollections.create({ transforms: matrices(2, 1) }).unwrap();
98
- const initialInstances = instanceCollections.snapshot(collection.collectionId).unwrap();
99
- instanceCollections.replace(collection.collectionId, matrices(3, 9)).unwrap();
100
- const nextInstances = instanceCollections.snapshot(collection.collectionId).unwrap();
97
+ const instanceCollections = new InstanceProjectionStore();
98
+ const source = new World();
99
+ const initialInstances = instanceCollections.project(source, 7, matrices(2, 1));
100
+ instanceCollections.accept(source, 7, initialInstances);
101
+ const nextInstances = instanceCollections.project(source, 7, matrices(3, 9));
101
102
  const scene = new RenderScene();
102
103
  scene.setTemporalTracking(true);
103
104
  try {
@@ -130,4 +131,34 @@ describe('RenderScene temporal retry boundary', () => {
130
131
  instanceCollections.dispose();
131
132
  }
132
133
  });
134
+
135
+ it('keeps instance motion valid when stable generations reorder', () => {
136
+ const instanceCollections = new InstanceProjectionStore();
137
+ const source = new World();
138
+ const initialInstances = instanceCollections.project(source, 7, matrices(2, 1));
139
+ instanceCollections.accept(source, 7, initialInstances);
140
+ // Exercise the temporal consumer's identity remapping directly. World
141
+ // authoring uses ordinal identity; this consumer also accepts reordered projections.
142
+ const reorderedInstances = {
143
+ ...instanceCollections.project(source, 7, matrices(2, 9)),
144
+ generations: new Uint32Array([
145
+ initialInstances.generations[1] ?? 0,
146
+ initialInstances.generations[0] ?? 0,
147
+ ]),
148
+ };
149
+ const scene = new RenderScene();
150
+ scene.setTemporalTracking(true);
151
+ try {
152
+ scene.apply([updateSnapshot(snapshot(7, 1, initialInstances))]);
153
+ submit(scene, 7);
154
+ scene.apply([updateInstances(snapshot(7, 1, reorderedInstances))]);
155
+
156
+ const temporal = scene.temporalSnapshotBySlot(0);
157
+ expect(temporal?.motionValid).toBe(true);
158
+ expect(temporal?.previousInstances?.generations).toEqual(initialInstances.generations);
159
+ expect(temporal?.previousInstances?.transforms).toEqual(initialInstances.transforms);
160
+ } finally {
161
+ instanceCollections.dispose();
162
+ }
163
+ });
133
164
  });
@@ -4,10 +4,10 @@ import { boundedReflectionProbeFilterWork } from '../record/typed-frame-graph';
4
4
  import { advanceProbeFilter, createProbeFilterState } from '../reflection/filter';
5
5
  import type { RenderTarget } from '../targets/contracts';
6
6
 
7
- const FRAME_COUNT = 300;
7
+ const FRAME_COUNT = 60;
8
8
  const target = {} as RenderTarget;
9
9
 
10
- describe('RenderTarget and ReflectionProbe 300-frame soak contract', () => {
10
+ describe('RenderTarget and ReflectionProbe 60-frame soak contract', () => {
11
11
  it('keeps off and settled steady-state work exactly zero', () => {
12
12
  const scheduler = createCubeCaptureScheduler({ maxFacesPerFrame: 1 });
13
13
  const initialFilter = createProbeFilterState({ probeIndex: 0, faceCount: 6, mipCount: 5 });
@@ -3,18 +3,18 @@ import { describe, expect, it } from 'vitest';
3
3
  const scenarios = ['none', 'fxaa', 'taa', 'recovery'] as const;
4
4
 
5
5
  describe('temporal Environment consumer browser contract', () => {
6
- it('requires every mode to carry a 300-frame identity', () => {
6
+ it('requires every mode to carry a 60-frame identity', () => {
7
7
  const records = scenarios.map((scenario) => ({
8
8
  scenario,
9
9
  backend: 'browser-webgpu',
10
- frames: 300,
10
+ frames: 60,
11
11
  status: 'pass',
12
12
  }));
13
13
  expect(records).toHaveLength(4);
14
14
  expect(
15
15
  records.every(
16
16
  (record) =>
17
- record.backend === 'browser-webgpu' && record.frames >= 300 && record.status === 'pass',
17
+ record.backend === 'browser-webgpu' && record.frames >= 60 && record.status === 'pass',
18
18
  ),
19
19
  ).toBe(true);
20
20
  });
@@ -6,11 +6,14 @@ describe('temporal Environment consumer Dawn contract', () => {
6
6
  backend: 'dawn-node',
7
7
  runner: 'dawn.node',
8
8
  scenarios: 4,
9
- framesPerScenario: 300,
9
+ framesPerScenario: 60,
10
10
  };
11
11
  expect(record.backend).toBe('dawn-node');
12
12
  expect(record.runner).toBe('dawn.node');
13
- expect(record.scenarios * record.framesPerScenario).toBe(1200);
13
+ expect(
14
+ record.scenarios * record.framesPerScenario,
15
+ 'four temporal scenarios must account for 60 frames each',
16
+ ).toBe(240);
14
17
  });
15
18
 
16
19
  it('keeps adapter refusal explicit', () => {
@@ -20,6 +20,7 @@ import {
20
20
  selectNoColorPbrVariant,
21
21
  selectPipelineLayoutForVariant,
22
22
  shouldDeferMissingPreparedMaterialShader,
23
+ stripCloudShadowBindingsForLowLimit,
23
24
  } from '../assembly/factory';
24
25
  import { prepareMaterialShaders } from '../assembly/material-shader-policy';
25
26
  import {
@@ -61,6 +62,22 @@ function noColorManifest() {
61
62
  }
62
63
 
63
64
  describe('material shader variant identity', () => {
65
+ it('lowers the optional cloud shadow bindings on cooked single-source materials', () => {
66
+ const source = `
67
+ @group(0) @binding(16) var cloudShadowMapX: texture_2d<f32>;
68
+ @group(0) @binding(17) var cloudShadowSamplerX: sampler;
69
+ fn cloud_direct_solar_factorX() -> f32 {
70
+ let sampled = textureSampleLevel(cloudShadowMapX, cloudShadowSamplerX, vec2<f32>(0.5), 0.0).x;
71
+ return sampled;
72
+ }
73
+ `;
74
+ const lowered = stripCloudShadowBindingsForLowLimit(source);
75
+ expect(lowered).not.toMatch(/@group\(0\)\s*@binding\((?:16|17)\)/u);
76
+ expect(lowered).not.toContain('cloudShadowMapX');
77
+ expect(lowered).not.toContain('cloudShadowSamplerX');
78
+ expect(lowered).toContain('vec4<f32>(1.0).x');
79
+ });
80
+
64
81
  it('defaults a declared coverage-only axis to the opaque boot variant', async () => {
65
82
  const entry: MaterialShaderManifestEntry = {
66
83
  identifier: 'forgeax::default-standard-pbr',
@@ -264,6 +281,23 @@ describe('material shader variant identity', () => {
264
281
  ).toBeNull();
265
282
  });
266
283
 
284
+ it('selects the producer-owned clustered layouts for scene-index batches', () => {
285
+ const state = {
286
+ pbrPipelineLayout: 'urp' as never,
287
+ hdrpPbrPipelineLayout: 'hdrp' as never,
288
+ pbrSkinPipelineLayout: 'skin-urp' as never,
289
+ gpuDrivenPbrPipelineLayout: 'gpu-urp' as never,
290
+ gpuDrivenPbrSkinPipelineLayout: 'gpu-skin-urp' as never,
291
+ gpuDrivenClusterPbrPipelineLayout: 'gpu-cluster' as never,
292
+ gpuDrivenClusterPbrSkinPipelineLayout: 'gpu-skin-cluster' as never,
293
+ };
294
+
295
+ expect(selectPipelineLayoutForVariant(state, '', 'gpu-driven-cluster-pbr')).toBe('gpu-cluster');
296
+ expect(selectPipelineLayoutForVariant(state, '', 'gpu-driven-cluster-skin')).toBe(
297
+ 'gpu-skin-cluster',
298
+ );
299
+ });
300
+
267
301
  it('does not promote an omitted semantic axis to true', () => {
268
302
  const resolved = resolveMaterialShaderVariantSet(
269
303
  'VERTEX_COLOR_AVAILABLE=true',
@@ -946,9 +980,9 @@ describe('material shader color-domain contract', () => {
946
980
  resolve(import.meta.dirname, '../assembly/webgpu-renderer.ts'),
947
981
  'utf8',
948
982
  );
949
- expect(source).toMatch(
950
- /if \(\s*!clustered\s*&&\s*!isStandardMapLayout\s*&&\s*isSharedMaterialUserRegionCompatible\(/u,
951
- );
983
+ expect(source).toContain('!singleLayerMedium');
984
+ expect(source).toContain('!clustered');
985
+ expect(source).toContain('isSharedMaterialUserRegionCompatible');
952
986
  });
953
987
 
954
988
  it('keeps the fixed standard texture ABI before authored clearcoat slots', () => {
@@ -960,7 +994,7 @@ describe('material shader color-domain contract', () => {
960
994
  expect(pipelineSource).toContain(
961
995
  'const physicalFields = physicalTextureFields(effectiveSchema)',
962
996
  );
963
- expect(pipelineSource).toContain('appendTextureInjection(afterTransmission, physicalFields)');
997
+ expect(pipelineSource).toContain('appendTextureInjection(afterSurfaceMedium, physicalFields)');
964
998
  expect(recordSource).toContain('BUILTIN_USER_REGION_TEXTURE_FIELDS');
965
999
  });
966
1000
 
@@ -969,12 +1003,12 @@ describe('material shader color-domain contract', () => {
969
1003
  resolve(import.meta.dirname, '../assembly/material/pipeline-helpers.ts'),
970
1004
  'utf8',
971
1005
  );
972
- expect(source).toContain(
973
- "const sceneIndex = layoutKind === 'gpu-driven-pbr' || layoutKind === 'gpu-driven-skin';",
1006
+ expect(source).toMatch(
1007
+ /const sceneIndex =\s+[\s\S]*layoutKind === 'gpu-driven-pbr'[\s\S]*layoutKind === 'gpu-driven-skin'[\s\S]*layoutKind === 'gpu-driven-cluster-pbr'[\s\S]*layoutKind === 'gpu-driven-cluster-skin'/u,
974
1008
  );
975
1009
  expect(source).toContain('? (vertexEntryPoint ?? authoredVertexEntry)');
976
1010
  expect(source).toMatch(
977
- /const instancesLayout =\s+layoutKind === 'gpu-driven-pbr' \|\| layoutKind === 'gpu-driven-skin'\s+\? state\.gpuDrivenInstancesBindGroupLayout\s+: state\.instancesBindGroupLayout/u,
1011
+ /const instancesLayout =\s+[\s\S]*layoutKind === 'gpu-driven-pbr'[\s\S]*layoutKind === 'gpu-driven-skin'[\s\S]*layoutKind === 'gpu-driven-cluster-pbr'[\s\S]*layoutKind === 'gpu-driven-cluster-skin'[\s\S]*state\.gpuDrivenInstancesBindGroupLayout/u,
978
1012
  );
979
1013
  });
980
1014
  });
@@ -2,6 +2,7 @@ import { describe, expect, it } from 'vitest';
2
2
  import {
3
3
  createContinuationTerminator,
4
4
  executeRendererFrameTransaction,
5
+ guardFrameCompletion,
5
6
  } from '../assembly/renderer-frame-transaction';
6
7
 
7
8
  describe('renderer frame generation fence', () => {
@@ -44,4 +45,19 @@ describe('renderer frame generation fence', () => {
44
45
  expect(terminator.guard('mapAsync')).toBe(false);
45
46
  expect(terminator.guard('queue-completion')).toBe(false);
46
47
  });
48
+
49
+ it('preserves a producer Result error carried by a fulfilled completion Promise', async () => {
50
+ const error = { code: 'queue-rejected' } as const;
51
+ const result = await guardFrameCompletion<
52
+ void,
53
+ { code: 'queue-rejected' | 'stale' | 'rejected' }
54
+ >(
55
+ Promise.resolve({ ok: false as const, error }),
56
+ () => true,
57
+ () => ({ code: 'stale' as const }),
58
+ () => ({ code: 'rejected' as const }),
59
+ );
60
+
61
+ expect(result).toEqual({ ok: false, error });
62
+ });
47
63
  });
@@ -87,7 +87,8 @@ function temporalResolveFrame(
87
87
  bloom: 'off',
88
88
  bloomThreshold: 1,
89
89
  bloomIntensity: 1,
90
- bloomBlurRadius: 1,
90
+ bloomSoftKnee: 0.5,
91
+ bloomScatter: 0.7,
91
92
  clearColor: [0, 0, 0, 1],
92
93
  temporal: frameState.lastSuccessfulTemporalView,
93
94
  },
@@ -258,6 +259,7 @@ function executeReplayCapture(
258
259
  };
259
260
  const frameState = {
260
261
  compiledFrameGraph: graph,
262
+ compiledFrameGraphTopologyKey: 'synthetic-capture',
261
263
  frameNumber: 13,
262
264
  graphTargetCapture:
263
265
  captureKind === 'pass-replay'
@@ -373,7 +375,7 @@ function executeReplayCapture(
373
375
  describe('renderer successful-submit transaction', () => {
374
376
  it('publishes the renderer-created receipt object only after submit', async () => {
375
377
  const rendererHost = await constructRenderer(
376
- { getContext: () => null },
378
+ { width: 64, height: 64, getContext: () => null },
377
379
  { rhi },
378
380
  {
379
381
  shaderManifestUrl: `data:application/json,${encodeURIComponent(
@@ -381,6 +383,7 @@ describe('renderer successful-submit transaction', () => {
381
383
  )}`,
382
384
  },
383
385
  );
386
+ expect((await rendererHost.initialization).ok).toBe(true);
384
387
  const renderer = exposeRenderer(rendererHost);
385
388
  const events: Array<
386
389
  Extract<import('../render-contract').RendererEvent, { kind: 'frame-submitted' }>
@@ -397,7 +400,7 @@ describe('renderer successful-submit transaction', () => {
397
400
  camera: { lease: attached.value },
398
401
  environment: { lease: attached.value },
399
402
  });
400
- expect(frame.ok).toBe(true);
403
+ expect(frame.ok, frame.ok ? '' : JSON.stringify(frame.error)).toBe(true);
401
404
  if (!frame.ok) return;
402
405
  expect(events).toHaveLength(1);
403
406
  expect(events[0]?.receipt).toBe(frame.value);
@@ -415,7 +418,7 @@ describe('renderer successful-submit transaction', () => {
415
418
 
416
419
  it('fail-closes an all-domain request without an admitted LUT producer', async () => {
417
420
  const renderer = await constructRenderer(
418
- { getContext: () => null },
421
+ { width: 64, height: 64, getContext: () => null },
419
422
  { rhi },
420
423
  {
421
424
  shaderManifestUrl: `data:application/json,${encodeURIComponent(
@@ -423,6 +426,7 @@ describe('renderer successful-submit transaction', () => {
423
426
  )}`,
424
427
  },
425
428
  );
429
+ expect((await renderer.initialization).ok).toBe(true);
426
430
  const world = new World();
427
431
  const attached = renderer.attach(world);
428
432
  expect(attached.ok).toBe(true);
@@ -432,7 +436,7 @@ describe('renderer successful-submit transaction', () => {
432
436
  camera: { lease: attached.value },
433
437
  environment: { lease: attached.value },
434
438
  });
435
- expect(frame.ok).toBe(true);
439
+ expect(frame.ok, frame.ok ? '' : JSON.stringify(frame.error)).toBe(true);
436
440
  if (!frame.ok || frame.value === undefined) return;
437
441
  expect(frame.value.graphGeneration).toBeTypeOf('number');
438
442
  expect(frame.value.backendId).toBe('null');
@@ -476,8 +480,18 @@ describe('renderer successful-submit transaction', () => {
476
480
  JSON.stringify({ schemaVersion: '1.0.0', entries: [] }),
477
481
  )}`,
478
482
  };
479
- const firstRenderer = await constructRenderer({ getContext: () => null }, { rhi }, options);
480
- const secondRenderer = await constructRenderer({ getContext: () => null }, { rhi }, options);
483
+ const firstRenderer = await constructRenderer(
484
+ { width: 64, height: 64, getContext: () => null },
485
+ { rhi },
486
+ options,
487
+ );
488
+ const secondRenderer = await constructRenderer(
489
+ { width: 64, height: 64, getContext: () => null },
490
+ { rhi },
491
+ options,
492
+ );
493
+ expect((await firstRenderer.initialization).ok).toBe(true);
494
+ expect((await secondRenderer.initialization).ok).toBe(true);
481
495
  const world = new World();
482
496
  const attached = firstRenderer.attach(world);
483
497
  expect(attached.ok).toBe(true);
@@ -487,7 +501,7 @@ describe('renderer successful-submit transaction', () => {
487
501
  camera: { lease: attached.value },
488
502
  environment: { lease: attached.value },
489
503
  });
490
- expect(frame.ok).toBe(true);
504
+ expect(frame.ok, frame.ok ? '' : JSON.stringify(frame.error)).toBe(true);
491
505
  if (!frame.ok || frame.value === undefined) return;
492
506
  expect(frame.value.backendId).toBe('null');
493
507
  const crossRenderer = await secondRenderer.observe(frame.value, { include: ['timings'] });
@@ -572,7 +586,7 @@ describe('renderer successful-submit transaction', () => {
572
586
 
573
587
  it('keeps real Renderer observation requests isolated across receipts', async () => {
574
588
  const renderer = await constructRenderer(
575
- { getContext: () => null },
589
+ { width: 64, height: 64, getContext: () => null },
576
590
  { rhi },
577
591
  {
578
592
  shaderManifestUrl: `data:application/json,${encodeURIComponent(
@@ -580,6 +594,7 @@ describe('renderer successful-submit transaction', () => {
580
594
  )}`,
581
595
  },
582
596
  );
597
+ expect((await renderer.initialization).ok).toBe(true);
583
598
  const world = new World();
584
599
  const attached = renderer.attach(world);
585
600
  expect(attached.ok).toBe(true);
@@ -594,8 +609,8 @@ describe('renderer successful-submit transaction', () => {
594
609
  camera: { lease: attached.value },
595
610
  environment: { lease: attached.value },
596
611
  });
597
- expect(first.ok).toBe(true);
598
- expect(second.ok).toBe(true);
612
+ expect(first.ok, first.ok ? '' : JSON.stringify(first.error)).toBe(true);
613
+ expect(second.ok, second.ok ? '' : JSON.stringify(second.error)).toBe(true);
599
614
  if (!first.ok || !second.ok || first.value === undefined || second.value === undefined) return;
600
615
  const firstPending = renderer.observe(first.value, {
601
616
  include: ['timings', 'linear-hdr', 'linear-ldr', 'final-srgb'],
@@ -1109,6 +1124,7 @@ describe('renderer successful-submit transaction', () => {
1109
1124
  expect(compiled.ok).toBe(true);
1110
1125
  if (!compiled.ok) return;
1111
1126
  frameState.compiledFrameGraph = compiled.value;
1127
+ frameState.compiledFrameGraphTopologyKey = 'temporal-readiness-probe';
1112
1128
  const submits = vi.spyOn(device.queue, 'submit');
1113
1129
  const errors = new RhiErrorListenerRegistry();
1114
1130
  const result = executeCompiledFrameGraph(
@@ -1147,6 +1163,7 @@ describe('renderer successful-submit transaction', () => {
1147
1163
  height: 4,
1148
1164
  frameIndex: 6,
1149
1165
  historyValid: true,
1166
+ sampleTimeSeconds: 1,
1150
1167
  });
1151
1168
  const frameState = {
1152
1169
  temporalGpuState: undefined,
@@ -1160,6 +1177,7 @@ describe('renderer successful-submit transaction', () => {
1160
1177
  height: 4,
1161
1178
  frameIndex: 6,
1162
1179
  historyValid: true,
1180
+ sampleTimeSeconds: 1.016,
1163
1181
  }),
1164
1182
  },
1165
1183
  environmentGeneration,
@@ -1180,6 +1198,7 @@ describe('renderer successful-submit transaction', () => {
1180
1198
  getTemporalParamsBuffer(candidate);
1181
1199
  const graph = await buildTemporalResolveGraph(device);
1182
1200
  frameState.compiledFrameGraph = graph;
1201
+ frameState.compiledFrameGraphTopologyKey = 'temporal-resolve';
1183
1202
 
1184
1203
  const failure = new RhiError({
1185
1204
  code: 'webgpu-runtime-error',
@@ -1244,6 +1263,7 @@ describe('renderer successful-submit transaction', () => {
1244
1263
  expect(active.valid).toBe(true);
1245
1264
  expect(active.readIndex).toBe(1);
1246
1265
  expect(frameState.lastSuccessfulTemporalView).toBe(lastSuccessfulTemporalView);
1266
+ expect(frameState.lastSuccessfulTemporalView.sampleTimeSeconds).toBe(1);
1247
1267
  expect(environmentLifecycle.inspect().activeSignature).toBe(activeEnvironment.signature);
1248
1268
  expect(environmentLifecycle.inspect().lkgSignature).toBe(activeEnvironment.signature);
1249
1269
  frameState.environmentGeneration = environmentLifecycle
@@ -1257,6 +1277,7 @@ describe('renderer successful-submit transaction', () => {
1257
1277
  height: 8,
1258
1278
  frameIndex: 7,
1259
1279
  historyValid: true,
1280
+ sampleTimeSeconds: 1.016,
1260
1281
  }),
1261
1282
  };
1262
1283
  const retryFrame = temporalResolveFrame(device, scope, frameState, {});
@@ -1273,6 +1294,7 @@ describe('renderer successful-submit transaction', () => {
1273
1294
  expect(gpuCommitAfterSubmit).toEqual([1]);
1274
1295
  expect(frameState.activeTemporalGpuState).not.toBe(active);
1275
1296
  expect(frameState.successfulTemporalFrameIndex).toBe(8);
1297
+ expect(frameState.lastSuccessfulTemporalView?.sampleTimeSeconds).toBe(1.016);
1276
1298
  expect(frameState.temporalGpuState).toBeUndefined();
1277
1299
  expect(frameState.retiringTemporalGpuStates.size).toBe(1);
1278
1300
  expect(publishEnvironment).toHaveBeenCalledTimes(1);
@@ -0,0 +1,123 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { inspectResourceClassSplits } from '../gpu-driven/batch-topology';
3
+ import {
4
+ combineGpuResourceAllocationInspections,
5
+ GpuResourceAllocationLedger,
6
+ } from '../gpu-driven/resource-allocation';
7
+
8
+ describe('GPU resource allocation ownership', () => {
9
+ it('keeps replacement coexistence through fence retirement and release', () => {
10
+ const ledger = new GpuResourceAllocationLedger();
11
+ const first = ledger.allocate(64);
12
+ const second = ledger.allocate(128);
13
+
14
+ expect(ledger.inspect()).toMatchObject({
15
+ liveBytes: 192,
16
+ pendingRetirementBytes: 0,
17
+ peakBytes: 192,
18
+ });
19
+ ledger.retire(first);
20
+ expect(ledger.inspect()).toMatchObject({
21
+ liveBytes: 128,
22
+ pendingRetirementBytes: 64,
23
+ peakBytes: 192,
24
+ });
25
+ ledger.release(first);
26
+ expect(ledger.inspect()).toMatchObject({
27
+ liveBytes: 128,
28
+ pendingRetirementBytes: 0,
29
+ retiredBytes: 64,
30
+ });
31
+ ledger.release(second);
32
+ expect(ledger.inspect()).toMatchObject({
33
+ liveBytes: 0,
34
+ pendingRetirementBytes: 0,
35
+ retiredBytes: 192,
36
+ });
37
+ });
38
+
39
+ it('records failed allocation rollback without leaving live bytes', () => {
40
+ const ledger = new GpuResourceAllocationLedger();
41
+ const token = ledger.allocate(256);
42
+ ledger.rollback(token);
43
+ expect(ledger.inspect()).toMatchObject({
44
+ liveBytes: 0,
45
+ failedAllocationRollbacks: 1,
46
+ failedAllocationRollbackBytes: 256,
47
+ peakBytes: 256,
48
+ });
49
+ });
50
+
51
+ it('attributes only resourceIdentity changes as resource-class splits', () => {
52
+ const base = {
53
+ generation: 0,
54
+ key: {
55
+ assetHandle: 1,
56
+ drawKind: 'indexed' as const,
57
+ first: 0,
58
+ count: 3,
59
+ baseVertex: 0,
60
+ materialSlot: 0,
61
+ topology: 'triangle-list' as const,
62
+ pipelineClass: 'pbr',
63
+ materialResourceClass: 'water-a',
64
+ resourceIdentity: 'water-a',
65
+ },
66
+ candidates: [],
67
+ visibleBase: 0,
68
+ visibleCapacity: 0,
69
+ indirectOffset: 0,
70
+ };
71
+ const sameClass = { ...base, batchId: 0 };
72
+ const secondRange = {
73
+ ...base,
74
+ batchId: 1,
75
+ key: { ...base.key, first: 3, count: 6 },
76
+ };
77
+ expect(inspectResourceClassSplits({ batches: [sameClass, secondRange] })).toMatchObject({
78
+ resourceClassCount: 1,
79
+ resourceClassSplitReasons: [],
80
+ });
81
+ const changedClass = {
82
+ ...secondRange,
83
+ key: { ...secondRange.key, resourceIdentity: 'water-b' },
84
+ };
85
+ expect(inspectResourceClassSplits({ batches: [sameClass, changedClass] })).toMatchObject({
86
+ resourceClassCount: 2,
87
+ resourceClassSplitReasons: ['resource-class:water-a', 'resource-class:water-b'],
88
+ });
89
+ });
90
+
91
+ it('combines owner facts without claiming physical residency', () => {
92
+ const ledger = new GpuResourceAllocationLedger();
93
+ ledger.allocate(32);
94
+ const combined = combineGpuResourceAllocationInspections([ledger.inspect()]);
95
+ expect(combined).toMatchObject({
96
+ unit: 'engine-allocation-bytes',
97
+ physicalResidency: 'unknown',
98
+ liveBytes: 32,
99
+ });
100
+ });
101
+
102
+ it('does not add historical peaks from owners with no simultaneous occupancy', () => {
103
+ const first = new GpuResourceAllocationLedger();
104
+ const firstToken = first.allocate(64);
105
+ first.retire(firstToken);
106
+ first.release(firstToken);
107
+
108
+ const second = new GpuResourceAllocationLedger();
109
+ const secondToken = second.allocate(128);
110
+ second.retire(secondToken);
111
+ second.release(secondToken);
112
+
113
+ expect(
114
+ combineGpuResourceAllocationInspections([first.inspect(), second.inspect()]),
115
+ ).toMatchObject({
116
+ liveBytes: 0,
117
+ pendingRetirementBytes: 0,
118
+ // The owner-local peaks are historical and happened in separate
119
+ // replacement windows; their sum is not an aggregate high-water mark.
120
+ peakBytes: 128,
121
+ });
122
+ });
123
+ });