@forgeax/engine-render 0.1.27 → 0.1.29

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 (655) hide show
  1. package/README.md +842 -124
  2. package/dist/assembly/atmosphere-shader-prewarm.d.ts +6 -0
  3. package/dist/assembly/atmosphere-shader-prewarm.d.ts.map +1 -0
  4. package/dist/assembly/dynamic-geometry-host.d.ts +52 -0
  5. package/dist/assembly/dynamic-geometry-host.d.ts.map +1 -0
  6. package/dist/assembly/dynamic-geometry-runtime.d.ts +20 -0
  7. package/dist/assembly/dynamic-geometry-runtime.d.ts.map +1 -0
  8. package/dist/assembly/factory.d.ts +3 -1
  9. package/dist/assembly/factory.d.ts.map +1 -1
  10. package/dist/assembly/gpu-driven-owner.d.ts +10 -0
  11. package/dist/assembly/gpu-driven-owner.d.ts.map +1 -0
  12. package/dist/assembly/host-contract.d.ts +19 -0
  13. package/dist/assembly/host-contract.d.ts.map +1 -1
  14. package/dist/assembly/material/assembly.d.ts +7 -0
  15. package/dist/assembly/material/assembly.d.ts.map +1 -1
  16. package/dist/assembly/material-shader-policy.d.ts +3 -1
  17. package/dist/assembly/material-shader-policy.d.ts.map +1 -1
  18. package/dist/assembly/recovery/failure-location.d.ts +12 -0
  19. package/dist/assembly/recovery/failure-location.d.ts.map +1 -0
  20. package/dist/assembly/recovery/renderer-recover.d.ts +6 -4
  21. package/dist/assembly/recovery/renderer-recover.d.ts.map +1 -1
  22. package/dist/assembly/renderer-facade.d.ts.map +1 -1
  23. package/dist/assembly/renderer-feature-inspection.d.ts +5 -0
  24. package/dist/assembly/renderer-feature-inspection.d.ts.map +1 -0
  25. package/dist/assembly/renderer-frame-transaction.d.ts +19 -0
  26. package/dist/assembly/renderer-frame-transaction.d.ts.map +1 -1
  27. package/dist/assembly/renderer-helpers.d.ts +3 -0
  28. package/dist/assembly/renderer-helpers.d.ts.map +1 -1
  29. package/dist/assembly/renderer-inspection.d.ts +4 -0
  30. package/dist/assembly/renderer-inspection.d.ts.map +1 -1
  31. package/dist/assembly/shader-prewarm-policy.d.ts +6 -0
  32. package/dist/assembly/shader-prewarm-policy.d.ts.map +1 -1
  33. package/dist/assembly/skin-palette-owner.d.ts +8 -0
  34. package/dist/assembly/skin-palette-owner.d.ts.map +1 -0
  35. package/dist/assembly/ssr-shader-prewarm.d.ts +6 -0
  36. package/dist/assembly/ssr-shader-prewarm.d.ts.map +1 -0
  37. package/dist/assembly/webgpu-device-loss.d.ts +15 -0
  38. package/dist/assembly/webgpu-device-loss.d.ts.map +1 -0
  39. package/dist/assembly/webgpu-pbr-ready.d.ts +38 -0
  40. package/dist/assembly/webgpu-pbr-ready.d.ts.map +1 -0
  41. package/dist/assembly/webgpu-ready-mipmap.d.ts +11 -0
  42. package/dist/assembly/webgpu-ready-mipmap.d.ts.map +1 -0
  43. package/dist/assembly/webgpu-ready.d.ts +7 -3
  44. package/dist/assembly/webgpu-ready.d.ts.map +1 -1
  45. package/dist/assembly/webgpu-renderer-bootstrap.d.ts +10 -0
  46. package/dist/assembly/webgpu-renderer-bootstrap.d.ts.map +1 -0
  47. package/dist/assembly/webgpu-renderer-contract.d.ts +62 -0
  48. package/dist/assembly/webgpu-renderer-contract.d.ts.map +1 -0
  49. package/dist/assembly/webgpu-renderer-guards.d.ts +9 -0
  50. package/dist/assembly/webgpu-renderer-guards.d.ts.map +1 -0
  51. package/dist/assembly/webgpu-renderer-observation.d.ts +6 -0
  52. package/dist/assembly/webgpu-renderer-observation.d.ts.map +1 -0
  53. package/dist/assembly/webgpu-renderer-recovery-failure.d.ts +12 -0
  54. package/dist/assembly/webgpu-renderer-recovery-failure.d.ts.map +1 -0
  55. package/dist/assembly/webgpu-renderer.d.ts +7 -141
  56. package/dist/assembly/webgpu-renderer.d.ts.map +1 -1
  57. package/dist/assembly/webgpu-vertex-layouts.d.ts +28 -84
  58. package/dist/assembly/webgpu-vertex-layouts.d.ts.map +1 -1
  59. package/dist/authoring.mjs +3 -3
  60. package/dist/{chunk-ADHHVYLW.mjs → chunk-33XZFTQU.mjs} +245 -39
  61. package/dist/chunk-33XZFTQU.mjs.map +1 -0
  62. package/dist/{chunk-GF523LHF.mjs → chunk-BLXGONR2.mjs} +30 -12
  63. package/dist/chunk-BLXGONR2.mjs.map +1 -0
  64. package/dist/{chunk-KM2NOX2I.mjs → chunk-BQVQOQJH.mjs} +958 -254
  65. package/dist/chunk-BQVQOQJH.mjs.map +1 -0
  66. package/dist/{chunk-HKXTW355.mjs → chunk-BTWH7BP4.mjs} +386 -17
  67. package/dist/chunk-BTWH7BP4.mjs.map +1 -0
  68. package/dist/{chunk-TMIASV2N.mjs → chunk-FUODTTIA.mjs} +3934 -676
  69. package/dist/chunk-FUODTTIA.mjs.map +1 -0
  70. package/dist/{chunk-FJ6P52EE.mjs → chunk-ILQ5MEZF.mjs} +3 -17
  71. package/dist/chunk-ILQ5MEZF.mjs.map +1 -0
  72. package/dist/{chunk-E34VL5VI.mjs → chunk-JQTSEI3Z.mjs} +3 -3
  73. package/dist/{chunk-E34VL5VI.mjs.map → chunk-JQTSEI3Z.mjs.map} +1 -1
  74. package/dist/{chunk-GE3SDD72.mjs → chunk-NICXSHAT.mjs} +16 -38
  75. package/dist/chunk-NICXSHAT.mjs.map +1 -0
  76. package/dist/{chunk-ZZ4YQ474.mjs → chunk-NRNXBLIJ.mjs} +577 -7
  77. package/dist/chunk-NRNXBLIJ.mjs.map +1 -0
  78. package/dist/{chunk-JDWARUOI.mjs → chunk-PA5DRJNI.mjs} +17 -3
  79. package/dist/chunk-PA5DRJNI.mjs.map +1 -0
  80. package/dist/{chunk-XDP6XE5V.mjs → chunk-S4DNKQYQ.mjs} +1118 -446
  81. package/dist/chunk-S4DNKQYQ.mjs.map +1 -0
  82. package/dist/components/camera.d.ts +62 -2
  83. package/dist/components/camera.d.ts.map +1 -1
  84. package/dist/components/index.d.ts +1 -0
  85. package/dist/components/index.d.ts.map +1 -1
  86. package/dist/components/instances.d.ts +6 -20
  87. package/dist/components/instances.d.ts.map +1 -1
  88. package/dist/components/scene-instance.d.ts +2 -1
  89. package/dist/components/scene-instance.d.ts.map +1 -1
  90. package/dist/components/screen-space-reflection.d.ts +14 -0
  91. package/dist/components/screen-space-reflection.d.ts.map +1 -0
  92. package/dist/construct-renderer.mjs +13805 -7186
  93. package/dist/construct-renderer.mjs.map +1 -1
  94. package/dist/device/gpu-residency.d.ts +11 -17
  95. package/dist/device/gpu-residency.d.ts.map +1 -1
  96. package/dist/device/mesh-residency-lifetime.d.ts +21 -0
  97. package/dist/device/mesh-residency-lifetime.d.ts.map +1 -0
  98. package/dist/dynamic-geometry.d.ts +125 -0
  99. package/dist/dynamic-geometry.d.ts.map +1 -0
  100. package/dist/environment/background.d.ts +6 -0
  101. package/dist/environment/background.d.ts.map +1 -0
  102. package/dist/errors/gpu-driven.d.ts +6 -3
  103. package/dist/errors/gpu-driven.d.ts.map +1 -1
  104. package/dist/errors/render.d.ts +7 -4
  105. package/dist/errors/render.d.ts.map +1 -1
  106. package/dist/extract/camera.d.ts.map +1 -1
  107. package/dist/extract/gpu-driven.d.ts +33 -3
  108. package/dist/extract/gpu-driven.d.ts.map +1 -1
  109. package/dist/features/host.d.ts +23 -1
  110. package/dist/features/host.d.ts.map +1 -1
  111. package/dist/features/noise-texture.d.ts +17 -0
  112. package/dist/features/noise-texture.d.ts.map +1 -0
  113. package/dist/features/plan.d.ts +83 -2
  114. package/dist/features/plan.d.ts.map +1 -1
  115. package/dist/features/prepared-gpu-work.d.ts +37 -4
  116. package/dist/features/prepared-gpu-work.d.ts.map +1 -1
  117. package/dist/features/prepared-graphics-store.d.ts.map +1 -1
  118. package/dist/features/prepared-graphics.d.ts +5 -0
  119. package/dist/features/prepared-graphics.d.ts.map +1 -1
  120. package/dist/features/render-graph-compute.d.ts +5 -3
  121. package/dist/features/render-graph-compute.d.ts.map +1 -1
  122. package/dist/features/render-graph-contribution.d.ts +11 -3
  123. package/dist/features/render-graph-contribution.d.ts.map +1 -1
  124. package/dist/features/render-graph-raster.d.ts +19 -3
  125. package/dist/features/render-graph-raster.d.ts.map +1 -1
  126. package/dist/features/types.d.ts +11 -0
  127. package/dist/features/types.d.ts.map +1 -1
  128. package/dist/fullscreen-post-process-pass.d.ts +2 -0
  129. package/dist/fullscreen-post-process-pass.d.ts.map +1 -1
  130. package/dist/gpu-driven/batch-topology.d.ts +34 -1
  131. package/dist/gpu-driven/batch-topology.d.ts.map +1 -1
  132. package/dist/gpu-driven/pbr-program.d.ts +10 -0
  133. package/dist/gpu-driven/pbr-program.d.ts.map +1 -0
  134. package/dist/gpu-driven/prepared-draw.d.ts.map +1 -1
  135. package/dist/gpu-driven/production-raster.d.ts +144 -23
  136. package/dist/gpu-driven/production-raster.d.ts.map +1 -1
  137. package/dist/gpu-driven/shadow-views.d.ts +126 -0
  138. package/dist/gpu-driven/shadow-views.d.ts.map +1 -0
  139. package/dist/gpu-driven/view-gpu.d.ts +18 -2
  140. package/dist/gpu-driven/view-gpu.d.ts.map +1 -1
  141. package/dist/gpu-scene-schema.d.ts +2 -8
  142. package/dist/gpu-scene-schema.d.ts.map +1 -1
  143. package/dist/gpu-scene.d.ts +14 -0
  144. package/dist/gpu-scene.d.ts.map +1 -1
  145. package/dist/gpu-texture-usage.d.ts +1 -0
  146. package/dist/gpu-texture-usage.d.ts.map +1 -1
  147. package/dist/hdrp-buffers.d.ts +6 -0
  148. package/dist/hdrp-buffers.d.ts.map +1 -1
  149. package/dist/ibl/frame-resources.d.ts +8 -0
  150. package/dist/ibl/frame-resources.d.ts.map +1 -0
  151. package/dist/ibl/skylight-bind-group.d.ts.map +1 -1
  152. package/dist/index.d.ts +21 -8
  153. package/dist/index.d.ts.map +1 -1
  154. package/dist/index.mjs +8 -7
  155. package/dist/index.mjs.map +1 -1
  156. package/dist/inspection-types.d.ts +164 -0
  157. package/dist/inspection-types.d.ts.map +1 -1
  158. package/dist/instances-derived-bounds.d.ts +11 -0
  159. package/dist/instances-derived-bounds.d.ts.map +1 -1
  160. package/dist/instances.d.ts +89 -44
  161. package/dist/instances.d.ts.map +1 -1
  162. package/dist/internal.d.ts +3 -0
  163. package/dist/internal.d.ts.map +1 -1
  164. package/dist/internal.mjs +118 -10
  165. package/dist/internal.mjs.map +1 -1
  166. package/dist/lifecycle.d.ts +2 -1
  167. package/dist/lifecycle.d.ts.map +1 -1
  168. package/dist/material-row.d.ts +5 -0
  169. package/dist/material-row.d.ts.map +1 -0
  170. package/dist/materials.d.ts +15 -0
  171. package/dist/materials.d.ts.map +1 -1
  172. package/dist/pbr-pipeline.d.ts +21 -5
  173. package/dist/pbr-pipeline.d.ts.map +1 -1
  174. package/dist/pipeline/standard-forward-lane.d.ts.map +1 -1
  175. package/dist/pipeline/standard-output/auto-exposure/capability.d.ts +12 -0
  176. package/dist/pipeline/standard-output/auto-exposure/capability.d.ts.map +1 -0
  177. package/dist/pipeline/standard-output/auto-exposure/gpu.d.ts +70 -0
  178. package/dist/pipeline/standard-output/auto-exposure/gpu.d.ts.map +1 -0
  179. package/dist/pipeline/standard-output/auto-exposure/graph.d.ts +75 -0
  180. package/dist/pipeline/standard-output/auto-exposure/graph.d.ts.map +1 -0
  181. package/dist/pipeline/standard-output/auto-exposure/inspection.d.ts +111 -0
  182. package/dist/pipeline/standard-output/auto-exposure/inspection.d.ts.map +1 -0
  183. package/dist/pipeline/standard-output/auto-exposure/oracle.d.ts +16 -0
  184. package/dist/pipeline/standard-output/auto-exposure/oracle.d.ts.map +1 -0
  185. package/dist/pipeline/standard-output/auto-exposure/preset.d.ts +14 -0
  186. package/dist/pipeline/standard-output/auto-exposure/preset.d.ts.map +1 -0
  187. package/dist/pipeline/standard-output/auto-exposure/state.d.ts +46 -0
  188. package/dist/pipeline/standard-output/auto-exposure/state.d.ts.map +1 -0
  189. package/dist/pipeline/standard-output/color-transform.d.ts +27 -0
  190. package/dist/pipeline/standard-output/color-transform.d.ts.map +1 -0
  191. package/dist/pipeline/standard-output/graph.d.ts +15 -0
  192. package/dist/pipeline/standard-output/graph.d.ts.map +1 -0
  193. package/dist/pipeline/standard-output/lut-admission.d.ts +29 -0
  194. package/dist/pipeline/standard-output/lut-admission.d.ts.map +1 -0
  195. package/dist/pipeline/standard-output/lut-gpu.d.ts +48 -0
  196. package/dist/pipeline/standard-output/lut-gpu.d.ts.map +1 -0
  197. package/dist/pipeline/standard-output/lut-state.d.ts +68 -0
  198. package/dist/pipeline/standard-output/lut-state.d.ts.map +1 -0
  199. package/dist/pipeline/standard-output/resources.d.ts +10 -0
  200. package/dist/pipeline/standard-output/resources.d.ts.map +1 -0
  201. package/dist/pipeline/standard-output/types.d.ts +39 -0
  202. package/dist/pipeline/standard-output/types.d.ts.map +1 -0
  203. package/dist/pipeline/standard-pipeline.d.ts.map +1 -1
  204. package/dist/pipeline/standard-post.d.ts +2 -2
  205. package/dist/pipeline/standard-post.d.ts.map +1 -1
  206. package/dist/pipeline-builder.d.ts +2 -1
  207. package/dist/pipeline-builder.d.ts.map +1 -1
  208. package/dist/pipeline-spec-types.d.ts +4 -0
  209. package/dist/pipeline-spec-types.d.ts.map +1 -1
  210. package/dist/pipeline-spec.d.ts +1 -9
  211. package/dist/pipeline-spec.d.ts.map +1 -1
  212. package/dist/points-lines/standard-owner.d.ts +1 -1
  213. package/dist/points-lines/standard-owner.d.ts.map +1 -1
  214. package/dist/prepare/prepared-graphics-resolver.d.ts +6 -1
  215. package/dist/prepare/prepared-graphics-resolver.d.ts.map +1 -1
  216. package/dist/record/dynamic-geometry-consumption.d.ts +15 -0
  217. package/dist/record/dynamic-geometry-consumption.d.ts.map +1 -0
  218. package/dist/record/frame-lighting.d.ts +3 -3
  219. package/dist/record/frame-lighting.d.ts.map +1 -1
  220. package/dist/record/frame-snapshot.d.ts +106 -5
  221. package/dist/record/frame-snapshot.d.ts.map +1 -1
  222. package/dist/record/frame-targets.d.ts.map +1 -1
  223. package/dist/record/frame.d.ts +39 -4
  224. package/dist/record/frame.d.ts.map +1 -1
  225. package/dist/record/main-pass-geometry.d.ts +7 -8
  226. package/dist/record/main-pass-geometry.d.ts.map +1 -1
  227. package/dist/record/main-pass-material.d.ts +38 -1
  228. package/dist/record/main-pass-material.d.ts.map +1 -1
  229. package/dist/record/main-pass-sprite-draws.d.ts +2 -10
  230. package/dist/record/main-pass-sprite-draws.d.ts.map +1 -1
  231. package/dist/record/main-pass.d.ts +12 -2
  232. package/dist/record/main-pass.d.ts.map +1 -1
  233. package/dist/record/mesh-ssbo.d.ts +15 -6
  234. package/dist/record/mesh-ssbo.d.ts.map +1 -1
  235. package/dist/record/prepared-material-bindings.d.ts +19 -0
  236. package/dist/record/prepared-material-bindings.d.ts.map +1 -0
  237. package/dist/record/recovery-pipeline.d.ts +2 -9
  238. package/dist/record/recovery-pipeline.d.ts.map +1 -1
  239. package/dist/record/render-context.d.ts +76 -26
  240. package/dist/record/render-context.d.ts.map +1 -1
  241. package/dist/record/shadow-pass.d.ts +62 -7
  242. package/dist/record/shadow-pass.d.ts.map +1 -1
  243. package/dist/record/skybox-post-pass.d.ts +1 -1
  244. package/dist/record/skybox-post-pass.d.ts.map +1 -1
  245. package/dist/record/typed-frame-graph.d.ts +35 -7
  246. package/dist/record/typed-frame-graph.d.ts.map +1 -1
  247. package/dist/record/view-ubo.d.ts +1 -0
  248. package/dist/record/view-ubo.d.ts.map +1 -1
  249. package/dist/recovery/render-system-candidate.d.ts +10 -2
  250. package/dist/recovery/render-system-candidate.d.ts.map +1 -1
  251. package/dist/recovery/render-system-roots.d.ts +11 -0
  252. package/dist/recovery/render-system-roots.d.ts.map +1 -0
  253. package/dist/recovery/types.d.ts +76 -0
  254. package/dist/recovery/types.d.ts.map +1 -0
  255. package/dist/reflection/record-owner.d.ts +0 -2
  256. package/dist/reflection/record-owner.d.ts.map +1 -1
  257. package/dist/render-contract.d.ts +185 -30
  258. package/dist/render-contract.d.ts.map +1 -1
  259. package/dist/render-graph-primitives.d.ts +1 -0
  260. package/dist/render-graph-primitives.d.ts.map +1 -1
  261. package/dist/render-pipeline.d.ts +64 -5
  262. package/dist/render-pipeline.d.ts.map +1 -1
  263. package/dist/render-system-extract-tail.d.ts +7 -5
  264. package/dist/render-system-extract-tail.d.ts.map +1 -1
  265. package/dist/render-system-extract.d.ts +101 -41
  266. package/dist/render-system-extract.d.ts.map +1 -1
  267. package/dist/render-system-projections.d.ts +22 -0
  268. package/dist/render-system-projections.d.ts.map +1 -0
  269. package/dist/render-system.d.ts +34 -77
  270. package/dist/render-system.d.ts.map +1 -1
  271. package/dist/scene/render-scene-types.d.ts +14 -7
  272. package/dist/scene/render-scene-types.d.ts.map +1 -1
  273. package/dist/scene/render-scene.d.ts +29 -11
  274. package/dist/scene/render-scene.d.ts.map +1 -1
  275. package/dist/scene/shadow-visibility.d.ts +5 -0
  276. package/dist/scene/shadow-visibility.d.ts.map +1 -0
  277. package/dist/ssr/admission.d.ts +70 -1
  278. package/dist/ssr/admission.d.ts.map +1 -1
  279. package/dist/ssr/compose.d.ts +13 -0
  280. package/dist/ssr/compose.d.ts.map +1 -0
  281. package/dist/ssr/errors.d.ts +35 -0
  282. package/dist/ssr/errors.d.ts.map +1 -1
  283. package/dist/ssr/graph.d.ts +60 -0
  284. package/dist/ssr/graph.d.ts.map +1 -0
  285. package/dist/ssr/history.d.ts +97 -0
  286. package/dist/ssr/history.d.ts.map +1 -0
  287. package/dist/ssr/hiz.d.ts +37 -0
  288. package/dist/ssr/hiz.d.ts.map +1 -0
  289. package/dist/ssr/inspection.d.ts +42 -0
  290. package/dist/ssr/inspection.d.ts.map +1 -0
  291. package/dist/ssr/resources.d.ts +58 -0
  292. package/dist/ssr/resources.d.ts.map +1 -0
  293. package/dist/ssr/temporal.d.ts +38 -0
  294. package/dist/ssr/temporal.d.ts.map +1 -0
  295. package/dist/systems/skin-palette-allocator.d.ts +32 -10
  296. package/dist/systems/skin-palette-allocator.d.ts.map +1 -1
  297. package/dist/systems/skin-palette-types.d.ts +15 -0
  298. package/dist/systems/skin-palette-types.d.ts.map +1 -1
  299. package/dist/systems/transparent-dispatch.d.ts +9 -0
  300. package/dist/systems/transparent-dispatch.d.ts.map +1 -0
  301. package/dist/targets/material-source.d.ts +7 -0
  302. package/dist/targets/material-source.d.ts.map +1 -1
  303. package/dist/temporal/frame-coordinator.d.ts +7 -0
  304. package/dist/temporal/frame-coordinator.d.ts.map +1 -1
  305. package/dist/temporal/gpu.d.ts +8 -0
  306. package/dist/temporal/gpu.d.ts.map +1 -1
  307. package/dist/temporal/history.d.ts.map +1 -1
  308. package/dist/temporal/index.mjs +6 -6
  309. package/dist/temporal/inspection.d.ts.map +1 -1
  310. package/dist/temporal/standard-scene-data.d.ts +2 -1
  311. package/dist/temporal/standard-scene-data.d.ts.map +1 -1
  312. package/dist/temporal/temporal-view.d.ts +2 -0
  313. package/dist/temporal/temporal-view.d.ts.map +1 -1
  314. package/dist/typed-render-graph-primitives.d.ts +35 -1
  315. package/dist/typed-render-graph-primitives.d.ts.map +1 -1
  316. package/dist/typed-shadow-passes.d.ts +3 -1
  317. package/dist/typed-shadow-passes.d.ts.map +1 -1
  318. package/dist/volume/temporal.d.ts +6 -0
  319. package/dist/volume/temporal.d.ts.map +1 -1
  320. package/package.json +21 -20
  321. package/src/__tests__/auto-exposure-gpu-evidence.ts +291 -0
  322. package/src/__tests__/auto-exposure-inspection.unit.test.ts +80 -0
  323. package/src/__tests__/auto-exposure-transaction.integration.test.ts +99 -0
  324. package/src/__tests__/auto-exposure.browser.test.ts +33 -0
  325. package/src/__tests__/auto-exposure.dawn.test.ts +33 -0
  326. package/src/__tests__/detached-inspection.integration.test.ts +5 -0
  327. package/src/__tests__/device-scope-lifecycle.unit.test.ts +18 -0
  328. package/src/__tests__/device-scope-stale-matrix.unit.test.ts +18 -0
  329. package/src/__tests__/docs-gate-green.unit.test.ts +3 -3
  330. package/src/__tests__/dynamic-geometry-host.unit.test.ts +1123 -0
  331. package/src/__tests__/dynamic-geometry.unit.test.ts +233 -0
  332. package/src/__tests__/factory-contract.integration.test.ts +73 -22
  333. package/src/__tests__/fallback-row-stride-surface.unit.test.ts +19 -0
  334. package/src/__tests__/feature-depth-input.dawn.test.ts +121 -0
  335. package/src/__tests__/feature-noise.unit.test.ts +38 -0
  336. package/src/__tests__/fixtures/taa-resolve-pinned-baseline.wgsl +301 -0
  337. package/src/__tests__/frame-camera-selection.unit.test.ts +131 -0
  338. package/src/__tests__/frame-plan-contract.unit.test.ts +24 -0
  339. package/src/__tests__/frame-targets.unit.test.ts +24 -0
  340. package/src/__tests__/fullscreen-feature-plan.unit.test.ts +3 -0
  341. package/src/__tests__/gpu-driven-baseline.characterization.test.ts +79 -0
  342. package/src/__tests__/gpu-driven-batch-topology-pbr.unit.test.ts +287 -6
  343. package/src/__tests__/gpu-driven-indirect-raster-evidence.ts +122 -142
  344. package/src/__tests__/gpu-driven-indirect-raster.browser.test.ts +10 -1
  345. package/src/__tests__/gpu-driven-lod-cache.unit.test.ts +264 -0
  346. package/src/__tests__/gpu-driven-mesh-world-identity.unit.test.ts +349 -0
  347. package/src/__tests__/gpu-driven-pbr.dawn.test.ts +1417 -0
  348. package/src/__tests__/gpu-driven-pbr.integration.test.ts +21 -0
  349. package/src/__tests__/gpu-driven-production-fixture.ts +96 -0
  350. package/src/__tests__/gpu-driven-production.integration.test.ts +1075 -93
  351. package/src/__tests__/gpu-driven-scaling.unit.test.ts +1 -3
  352. package/src/__tests__/gpu-driven-shadow-views.browser.test.ts +63 -0
  353. package/src/__tests__/gpu-driven-shadow-views.dawn.test.ts +294 -0
  354. package/src/__tests__/gpu-driven-shadow-views.integration.test.ts +97 -0
  355. package/src/__tests__/gpu-driven-shadow-views.unit.test.ts +168 -0
  356. package/src/__tests__/gpu-driven-skin-contract.test-d.ts +11 -0
  357. package/src/__tests__/gpu-driven-view-gpu-evidence.ts +72 -20
  358. package/src/__tests__/gpu-driven-view-graph.integration.test.ts +30 -9
  359. package/src/__tests__/gpu-driven-view.unit.test.ts +159 -52
  360. package/src/__tests__/gpu-pass-timing.browser.test.ts +6 -1
  361. package/src/__tests__/gpu-resource-store-stride.unit.test.ts +42 -0
  362. package/src/__tests__/gpu-scene-render-graph-gpu.ts +19 -5
  363. package/src/__tests__/gpu-scene.dawn.test.ts +40 -13
  364. package/src/__tests__/gpu-scene.unit.test.ts +559 -33
  365. package/src/__tests__/instances-culling.integration.test.ts +36 -10
  366. package/src/__tests__/instances-derived-bounds.unit.test.ts +54 -0
  367. package/src/__tests__/instances-store.unit.test.ts +242 -39
  368. package/src/__tests__/ktx2-basis-gpu-consumer.dawn.test.ts +6 -0
  369. package/src/__tests__/lighting-scene-roundtrip.integration.test.ts +13 -16
  370. package/src/__tests__/lut-lkg-transaction.integration.test.ts +122 -0
  371. package/src/__tests__/material-contract-inventory.unit.test.ts +5 -6
  372. package/src/__tests__/material-dispatch-shader-id.unit.test.ts +51 -0
  373. package/src/__tests__/material-lane-selection.unit.test.ts +60 -0
  374. package/src/__tests__/material-numeric-upload.unit.test.ts +53 -0
  375. package/src/__tests__/material-texture-handles.unit.test.ts +18 -0
  376. package/src/__tests__/material-texture-source.unit.test.ts +87 -0
  377. package/src/__tests__/materials-authoring-validation.unit.test.ts +41 -0
  378. package/src/__tests__/materials-standard-contract.unit.test.ts +52 -2
  379. package/src/__tests__/mesh-buffer-usage-surface.unit.test.ts +4 -0
  380. package/src/__tests__/mesh-submission-lifetime.unit.test.ts +53 -0
  381. package/src/__tests__/normal-fallback.dawn.test.ts +122 -0
  382. package/src/__tests__/particle-material-input-layout.unit.test.ts +104 -0
  383. package/src/__tests__/physical-clearcoat.integration.test.ts +37 -3
  384. package/src/__tests__/pipeline-texture-specialization.unit.test.ts +138 -0
  385. package/src/__tests__/point-shadow-inspection.unit.test.ts +2 -0
  386. package/src/__tests__/prepared-gpu-driven-pbr-contract.test-d.ts +31 -0
  387. package/src/__tests__/prepared-gpu-driven-pbr-contract.unit.test.ts +39 -0
  388. package/src/__tests__/prepared-gpu-driven-pbr.integration.test.ts +35 -4
  389. package/src/__tests__/prepared-graphics-capability.unit.test.ts +21 -0
  390. package/src/__tests__/prepared-graphics-pipeline-warmup.unit.test.ts +6 -2
  391. package/src/__tests__/profiler-phase-catalog.test.ts +5 -0
  392. package/src/__tests__/public-surface.test-d.ts +3 -0
  393. package/src/__tests__/recovery-candidate-prepare.contract.test.ts +30 -12
  394. package/src/__tests__/reflection-fallback-async-publication.unit.test.ts +104 -0
  395. package/src/__tests__/reflection-probe-record-owner.characterization.unit.test.ts +2 -1
  396. package/src/__tests__/render-error-code-owner.test-d.ts +4 -0
  397. package/src/__tests__/render-error-detail-ssot.test-d.ts +22 -0
  398. package/src/__tests__/render-error-exhaustive.test-d.ts +15 -0
  399. package/src/__tests__/render-feature-gpu-work.integration.test.ts +285 -2
  400. package/src/__tests__/render-feature-plan.unit.test.ts +245 -0
  401. package/src/__tests__/render-feature-shadow-order.unit.test.ts +228 -0
  402. package/src/__tests__/render-feature-zero-work.unit.test.ts +35 -1
  403. package/src/__tests__/render-graph-fallback.integration.test.ts +2 -2
  404. package/src/__tests__/render-owner-cohesion.unit.test.ts +55 -0
  405. package/src/__tests__/render-scene-mixed-updates.integration.test.ts +426 -0
  406. package/src/__tests__/render-scene-projection.unit.test.ts +914 -23
  407. package/src/__tests__/render-scene-resource-updates.integration.test.ts +214 -0
  408. package/src/__tests__/render-scene-skin-lifecycle.integration.test.ts +173 -0
  409. package/src/__tests__/render-scene-temporal-retry.unit.test.ts +133 -0
  410. package/src/__tests__/render-target-material-source.test-d.ts +27 -3
  411. package/src/__tests__/renderer-factory-material-contract.unit.test.ts +61 -1
  412. package/src/__tests__/renderer-frame-transaction.integration.test.ts +923 -5
  413. package/src/__tests__/shader-manifest-fixture.ts +39 -0
  414. package/src/__tests__/skin-motion-regression.unit.test.ts +0 -33
  415. package/src/__tests__/skin-palette-persistent.integration.test.ts +28 -0
  416. package/src/__tests__/skin-palette-persistent.unit.test.ts +247 -0
  417. package/src/__tests__/skinned-shadow-caster.test.ts +118 -14
  418. package/src/__tests__/specular-environment-scale.dawn.test.ts +156 -0
  419. package/src/__tests__/ssr-admission-matrix.integration.test.ts +7 -1
  420. package/src/__tests__/ssr-confidence-compose.unit.test.ts +84 -0
  421. package/src/__tests__/ssr-coordinate-oracle.unit.test.ts +28 -0
  422. package/src/__tests__/ssr-format-probe-gating.integration.test.ts +82 -0
  423. package/src/__tests__/ssr-gpu-dispatch.browser.test.ts +91 -0
  424. package/src/__tests__/ssr-gpu-dispatch.dawn.test.ts +112 -0
  425. package/src/__tests__/ssr-gpu-dispatch.ts +946 -0
  426. package/src/__tests__/ssr-graph-topology.unit.test.ts +104 -0
  427. package/src/__tests__/ssr-history-filter.dawn.test.ts +198 -0
  428. package/src/__tests__/ssr-hit-color.dawn.test.ts +273 -0
  429. package/src/__tests__/ssr-hiz-odd-reduction.dawn.test.ts +569 -0
  430. package/src/__tests__/ssr-hiz-rescue.dawn.test.ts +279 -0
  431. package/src/__tests__/ssr-hiz.browser.test.ts +150 -0
  432. package/src/__tests__/ssr-hiz.dawn.test.ts +150 -0
  433. package/src/__tests__/ssr-hiz.unit.test.ts +56 -0
  434. package/src/__tests__/ssr-inspection.unit.test.ts +105 -0
  435. package/src/__tests__/ssr-memory-budget.unit.test.ts +45 -0
  436. package/src/__tests__/ssr-performance-sequence-aggregation.unit.test.ts +15 -0
  437. package/src/__tests__/ssr-public-surface.test-d.ts +37 -0
  438. package/src/__tests__/ssr-receiver-coverage.dawn.test.ts +387 -0
  439. package/src/__tests__/ssr-reflection-mip-reducer.dawn.test.ts +309 -0
  440. package/src/__tests__/ssr-reprojection-probe.ts +90 -0
  441. package/src/__tests__/ssr-roughness-mip.dawn.test.ts +163 -0
  442. package/src/__tests__/ssr-shader-prewarm.unit.test.ts +59 -0
  443. package/src/__tests__/ssr-spatial.integration.test.ts +141 -0
  444. package/src/__tests__/ssr-stable-lattice.dawn.test.ts +475 -0
  445. package/src/__tests__/ssr-temporal-history.unit.test.ts +202 -0
  446. package/src/__tests__/ssr-texel-crossing.dawn.test.ts +448 -0
  447. package/src/__tests__/ssr-zero-work.integration.test.ts +87 -0
  448. package/src/__tests__/standard-cluster-variant-resolution.unit.test.ts +44 -12
  449. package/src/__tests__/standard-clustered-pipeline.unit.test.ts +29 -0
  450. package/src/__tests__/standard-output-chain-contract.unit.test.ts +99 -0
  451. package/src/__tests__/standard-output-chain.integration.test.ts +73 -0
  452. package/src/__tests__/standard-output-gpu-evidence.ts +205 -0
  453. package/src/__tests__/standard-output.browser.test.ts +15 -0
  454. package/src/__tests__/standard-output.dawn.test.ts +15 -0
  455. package/src/__tests__/standard-pbr-artifact-assembly.unit.test.ts +38 -0
  456. package/src/__tests__/standard-pipeline.integration.test.ts +320 -3
  457. package/src/__tests__/standard-profile-oracle.unit.test.ts +22 -0
  458. package/src/__tests__/standard-surface-lighting.unit.test.ts +41 -0
  459. package/src/__tests__/standard-texture-specialization.dawn.test.ts +141 -0
  460. package/src/__tests__/surface-adjacent-regressions.integration.test.ts +6 -3
  461. package/src/__tests__/taa-coverage-edge.dawn.test.ts +193 -0
  462. package/src/__tests__/taa-history-clipping.dawn.test.ts +328 -0
  463. package/src/__tests__/taa-neighborhood-equivalence.dawn.test.ts +778 -0
  464. package/src/__tests__/taa-stability-feedback.browser.test.ts +23 -0
  465. package/src/__tests__/taa-stability-feedback.dawn.test.ts +68 -0
  466. package/src/__tests__/taa-stability-feedback.ts +341 -0
  467. package/src/__tests__/temporal-history-lifecycle.unit.test.ts +49 -7
  468. package/src/__tests__/temporal-reset-matrix.unit.test.ts +9 -0
  469. package/src/__tests__/temporal-transaction.integration.test.ts +28 -0
  470. package/src/__tests__/texture-usage-surface.unit.test.ts +4 -2
  471. package/src/__tests__/typed-pipeline-topology.unit.test.ts +109 -4
  472. package/src/__tests__/typed-scene-pass-material-cache.integration.test.ts +126 -0
  473. package/src/__tests__/vertex-layouts-ssot.unit.test.ts +47 -0
  474. package/src/__tests__/visibility-extract.perf.test.ts +20 -8
  475. package/src/__tests__/visibility-instances.integration.test.ts +19 -7
  476. package/src/__tests__/visibility-producer-matrix.integration.test.ts +20 -9
  477. package/src/assembly/atmosphere-shader-prewarm.ts +38 -0
  478. package/src/assembly/dynamic-geometry-host.ts +887 -0
  479. package/src/assembly/dynamic-geometry-runtime.ts +71 -0
  480. package/src/assembly/factory.ts +4 -0
  481. package/src/assembly/gpu-driven-owner.ts +29 -0
  482. package/src/assembly/host-contract.ts +36 -0
  483. package/src/assembly/material/assembly.ts +38 -0
  484. package/src/assembly/material-shader-policy.ts +71 -28
  485. package/src/assembly/recovery/failure-location.ts +62 -0
  486. package/src/assembly/recovery/renderer-recover.ts +19 -17
  487. package/src/assembly/renderer-facade.ts +29 -0
  488. package/src/assembly/renderer-feature-inspection.ts +13 -0
  489. package/src/assembly/renderer-frame-transaction.ts +63 -0
  490. package/src/assembly/renderer-helpers.ts +26 -0
  491. package/src/assembly/renderer-inspection.ts +6 -0
  492. package/src/assembly/shader-prewarm-policy.ts +32 -0
  493. package/src/assembly/skin-palette-owner.ts +21 -0
  494. package/src/assembly/ssr-shader-prewarm.ts +41 -0
  495. package/src/assembly/webgpu-device-loss.ts +75 -0
  496. package/src/assembly/webgpu-pbr-ready.ts +232 -0
  497. package/src/assembly/webgpu-ready-mipmap.ts +26 -0
  498. package/src/assembly/webgpu-ready.ts +142 -121
  499. package/src/assembly/webgpu-renderer-bootstrap.ts +85 -0
  500. package/src/assembly/webgpu-renderer-contract.ts +69 -0
  501. package/src/assembly/webgpu-renderer-guards.ts +32 -0
  502. package/src/assembly/webgpu-renderer-observation.ts +43 -0
  503. package/src/assembly/webgpu-renderer-recovery-failure.ts +62 -0
  504. package/src/assembly/webgpu-renderer.ts +675 -614
  505. package/src/assembly/webgpu-vertex-layouts.ts +233 -87
  506. package/src/components/__tests__/camera-exposure.contract.unit.test.ts +153 -0
  507. package/src/components/camera.ts +287 -7
  508. package/src/components/index.ts +1 -0
  509. package/src/components/instances.ts +45 -18
  510. package/src/components/scene-instance.ts +2 -1
  511. package/src/components/screen-space-reflection.ts +21 -0
  512. package/src/components/sprite-animation.ts +3 -3
  513. package/src/components/sprite-instances.ts +1 -1
  514. package/src/device/gpu-residency.ts +96 -93
  515. package/src/device/mesh-residency-lifetime.ts +73 -0
  516. package/src/dynamic-geometry.ts +736 -0
  517. package/src/environment/background.ts +263 -0
  518. package/src/errors/gpu-driven.ts +39 -5
  519. package/src/errors/render.ts +27 -3
  520. package/src/extract/camera.ts +26 -1
  521. package/src/extract/gpu-driven.ts +185 -10
  522. package/src/features/host.ts +237 -19
  523. package/src/features/noise-texture.ts +91 -0
  524. package/src/features/plan.ts +553 -24
  525. package/src/features/prepared-gpu-work.ts +631 -49
  526. package/src/features/prepared-graphics-store.ts +31 -0
  527. package/src/features/prepared-graphics.ts +5 -0
  528. package/src/features/render-graph-compute.ts +41 -8
  529. package/src/features/render-graph-contribution.ts +141 -3
  530. package/src/features/render-graph-raster.ts +143 -30
  531. package/src/features/types.ts +11 -0
  532. package/src/fullscreen-post-process-pass.ts +3 -0
  533. package/src/gpu-driven/batch-topology.ts +424 -102
  534. package/src/gpu-driven/pbr-program.ts +31 -0
  535. package/src/gpu-driven/prepared-draw.ts +29 -4
  536. package/src/gpu-driven/production-raster.ts +2267 -694
  537. package/src/gpu-driven/shadow-views.ts +539 -0
  538. package/src/gpu-driven/view-gpu.ts +188 -41
  539. package/src/gpu-scene-schema.ts +52 -11
  540. package/src/gpu-scene.ts +186 -99
  541. package/src/gpu-texture-usage.ts +1 -0
  542. package/src/hdrp-buffers.ts +72 -36
  543. package/src/ibl/frame-resources.ts +38 -0
  544. package/src/ibl/skylight-bind-group.ts +5 -4
  545. package/src/index.ts +125 -1
  546. package/src/inspection-types.ts +191 -0
  547. package/src/instances-derived-bounds.ts +258 -34
  548. package/src/instances.ts +459 -150
  549. package/src/internal.ts +22 -0
  550. package/src/lifecycle.ts +2 -0
  551. package/src/material-row.ts +145 -0
  552. package/src/materials.ts +44 -8
  553. package/src/pbr-pipeline.ts +159 -17
  554. package/src/pipeline/standard-forward-lane.ts +52 -24
  555. package/src/pipeline/standard-output/__tests__/lut-admission.unit.test.ts +103 -0
  556. package/src/pipeline/standard-output/auto-exposure/__tests__/capability.unit.test.ts +40 -0
  557. package/src/pipeline/standard-output/auto-exposure/__tests__/gpu.contract.unit.test.ts +125 -0
  558. package/src/pipeline/standard-output/auto-exposure/__tests__/graph.contract.unit.test.ts +94 -0
  559. package/src/pipeline/standard-output/auto-exposure/__tests__/oracle.test.ts +108 -0
  560. package/src/pipeline/standard-output/auto-exposure/__tests__/preset.test.ts +26 -0
  561. package/src/pipeline/standard-output/auto-exposure/capability.ts +38 -0
  562. package/src/pipeline/standard-output/auto-exposure/gpu.ts +567 -0
  563. package/src/pipeline/standard-output/auto-exposure/graph.ts +221 -0
  564. package/src/pipeline/standard-output/auto-exposure/inspection.ts +231 -0
  565. package/src/pipeline/standard-output/auto-exposure/oracle.ts +291 -0
  566. package/src/pipeline/standard-output/auto-exposure/preset.ts +28 -0
  567. package/src/pipeline/standard-output/auto-exposure/state.ts +156 -0
  568. package/src/pipeline/standard-output/color-transform.ts +124 -0
  569. package/src/pipeline/standard-output/graph.ts +139 -0
  570. package/src/pipeline/standard-output/lut-admission.ts +121 -0
  571. package/src/pipeline/standard-output/lut-gpu.ts +399 -0
  572. package/src/pipeline/standard-output/lut-state.ts +176 -0
  573. package/src/pipeline/standard-output/resources.ts +121 -0
  574. package/src/pipeline/standard-output/types.ts +58 -0
  575. package/src/pipeline/standard-pipeline.ts +192 -59
  576. package/src/pipeline/standard-post.ts +186 -27
  577. package/src/pipeline-builder.ts +16 -6
  578. package/src/pipeline-spec-types.ts +4 -0
  579. package/src/pipeline-spec.ts +37 -29
  580. package/src/points-lines/standard-owner.ts +6 -14
  581. package/src/prepare/prepared-graphics-resolver.ts +9 -2
  582. package/src/record/__tests__/material-slot-plan.unit.test.ts +48 -0
  583. package/src/record/__tests__/mesh-ssbo.unit.test.ts +40 -1
  584. package/src/record/__tests__/recovery-pipeline.unit.test.ts +2 -29
  585. package/src/record/__tests__/sprite-material-abi.unit.test.ts +36 -5
  586. package/src/record/__tests__/typed-frame-graph-plan.unit.test.ts +45 -0
  587. package/src/record/__tests__/view-ubo-layout.unit.test.ts +5 -0
  588. package/src/record/dynamic-geometry-consumption.ts +59 -0
  589. package/src/record/frame-lighting.ts +12 -11
  590. package/src/record/frame-snapshot.ts +133 -23
  591. package/src/record/frame-targets.ts +9 -0
  592. package/src/record/frame.ts +727 -133
  593. package/src/record/main-pass-geometry.ts +162 -98
  594. package/src/record/main-pass-material.ts +115 -26
  595. package/src/record/main-pass-sprite-draws.ts +18 -107
  596. package/src/record/main-pass.ts +78 -8
  597. package/src/record/material-uniforms.ts +1 -1
  598. package/src/record/mesh-ssbo.ts +59 -15
  599. package/src/record/prepared-material-bindings.ts +234 -0
  600. package/src/record/recovery-pipeline.ts +59 -136
  601. package/src/record/render-context.ts +92 -22
  602. package/src/record/shadow-pass.ts +1231 -209
  603. package/src/record/skybox-post-pass.ts +14 -3
  604. package/src/record/typed-frame-graph.ts +1006 -53
  605. package/src/record/view-ubo.ts +11 -0
  606. package/src/recovery/render-system-candidate.ts +90 -66
  607. package/src/recovery/render-system-roots.ts +113 -0
  608. package/src/recovery/types.ts +77 -0
  609. package/src/reflection/record-owner.ts +26 -54
  610. package/src/render-contract.ts +219 -25
  611. package/src/render-graph-primitives.ts +6 -2
  612. package/src/render-pipeline.ts +70 -1
  613. package/src/render-system-extract-tail.ts +409 -160
  614. package/src/render-system-extract.ts +376 -102
  615. package/src/render-system-projections.ts +241 -0
  616. package/src/render-system.ts +692 -791
  617. package/src/scene/render-scene-types.ts +13 -4
  618. package/src/scene/render-scene.ts +569 -355
  619. package/src/scene/shadow-visibility.ts +21 -0
  620. package/src/ssr/admission.ts +380 -14
  621. package/src/ssr/compose.ts +144 -0
  622. package/src/ssr/errors.ts +48 -0
  623. package/src/ssr/graph.ts +777 -0
  624. package/src/ssr/history.ts +436 -0
  625. package/src/ssr/hiz.ts +124 -0
  626. package/src/ssr/inspection.ts +124 -0
  627. package/src/ssr/resources.ts +202 -0
  628. package/src/ssr/temporal.ts +164 -0
  629. package/src/systems/skin-palette-allocator.ts +495 -148
  630. package/src/systems/skin-palette-types.ts +17 -0
  631. package/src/systems/transparent-dispatch.ts +90 -0
  632. package/src/targets/material-source.ts +34 -0
  633. package/src/temporal/coverage.ts +1 -1
  634. package/src/temporal/frame-coordinator.ts +23 -2
  635. package/src/temporal/gpu.ts +74 -12
  636. package/src/temporal/history.ts +3 -1
  637. package/src/temporal/inspection.ts +2 -1
  638. package/src/temporal/standard-scene-data.ts +3 -1
  639. package/src/temporal/temporal-view.ts +3 -0
  640. package/src/transmission/__tests__/standard-transmission.dawn.test.ts +204 -139
  641. package/src/typed-render-graph-primitives.ts +266 -74
  642. package/src/typed-shadow-passes.ts +122 -12
  643. package/src/volume/temporal.ts +10 -0
  644. package/dist/chunk-ADHHVYLW.mjs.map +0 -1
  645. package/dist/chunk-FJ6P52EE.mjs.map +0 -1
  646. package/dist/chunk-GE3SDD72.mjs.map +0 -1
  647. package/dist/chunk-GF523LHF.mjs.map +0 -1
  648. package/dist/chunk-HKXTW355.mjs.map +0 -1
  649. package/dist/chunk-JDWARUOI.mjs.map +0 -1
  650. package/dist/chunk-KM2NOX2I.mjs.map +0 -1
  651. package/dist/chunk-TMIASV2N.mjs.map +0 -1
  652. package/dist/chunk-XDP6XE5V.mjs.map +0 -1
  653. package/dist/chunk-ZZ4YQ474.mjs.map +0 -1
  654. package/src/__tests__/instances-world-ownership.integration.test.ts +0 -62
  655. package/src/scene/__tests__/changed-block-summary.candidate.test.ts +0 -36
@@ -44,6 +44,15 @@ function snapshot(entityKey: number, x: number): RenderableSnapshot {
44
44
  };
45
45
  }
46
46
 
47
+ function updateSnapshot(value: RenderableSnapshot) {
48
+ return {
49
+ kind: 'update' as const,
50
+ worldId: value.worldId,
51
+ entityKey: value.entityKey,
52
+ snapshot: value,
53
+ };
54
+ }
55
+
47
56
  export interface GpuDrivenViewGpuEvidence {
48
57
  readonly visibleInstance: number;
49
58
  readonly indexCount: number;
@@ -90,12 +99,17 @@ export async function runGpuDrivenViewLifecycleEvidence(
90
99
  for (let frame = 0; frame < frames; frame += 1) {
91
100
  const targetCount = frame < 4 ? 2 ** frame : frame % 2 === 0 ? 1 : 8;
92
101
  const operations: Array<
93
- | { readonly kind: 'create'; readonly snapshot: RenderableSnapshot }
102
+ | {
103
+ readonly kind: 'update';
104
+ readonly worldId: number;
105
+ readonly entityKey: number;
106
+ readonly snapshot: RenderableSnapshot;
107
+ }
94
108
  | { readonly kind: 'remove'; readonly worldId: number; readonly entityKey: number }
95
109
  > = [];
96
110
  while (activeCount < targetCount) {
97
111
  activeCount += 1;
98
- operations.push({ kind: 'create', snapshot: snapshot(activeCount, activeCount * 0.05) });
112
+ operations.push(updateSnapshot(snapshot(activeCount, activeCount * 0.05)));
99
113
  }
100
114
  while (activeCount > targetCount) {
101
115
  operations.push({ kind: 'remove', worldId: 0, entityKey: activeCount });
@@ -140,6 +154,9 @@ export async function runGpuDrivenViewLifecycleEvidence(
140
154
  export async function runGpuDrivenViewGpuEvidence(): Promise<GpuDrivenViewGpuEvidence> {
141
155
  const adapter = (await rhi.requestAdapter()).unwrap();
142
156
  const device = (await adapter.requestDevice()).unwrap();
157
+ const rawDevice = _internal_getRawDevice(device);
158
+ if (rawDevice === undefined) throw new Error('GPU-driven evidence raw device unavailable');
159
+ rawDevice.pushErrorScope('validation');
143
160
  const shader = (
144
161
  await rhi.createShaderModule(device, {
145
162
  code: GPU_DRIVEN_VIEW_WGSL,
@@ -168,19 +185,16 @@ export async function runGpuDrivenViewGpuEvidence(): Promise<GpuDrivenViewGpuEvi
168
185
  ],
169
186
  };
170
187
  const delta = projection.apply([
171
- {
172
- kind: 'create',
173
- snapshot: {
174
- ...instancedWithLod,
175
- instances: {
176
- transforms: new Float32Array([...visibleInstance, ...culledInstance]),
177
- instanceCount: 2,
178
- cacheKey: 1,
179
- archVersion: 1,
180
- },
188
+ updateSnapshot({
189
+ ...instancedWithLod,
190
+ instances: {
191
+ transforms: new Float32Array([...visibleInstance, ...culledInstance]),
192
+ instanceCount: 2,
193
+ cacheKey: 1,
194
+ archVersion: 1,
181
195
  },
182
- },
183
- { kind: 'create', snapshot: snapshot(2, 10) },
196
+ }),
197
+ updateSnapshot(snapshot(2, 10)),
184
198
  ]);
185
199
  const sceneAvailability = GpuScene.create(device, 2).unwrap();
186
200
  if (sceneAvailability.status !== 'available') throw new Error('GPU Scene unavailable');
@@ -248,16 +262,54 @@ export async function runGpuDrivenViewGpuEvidence(): Promise<GpuDrivenViewGpuEvi
248
262
  64,
249
263
  );
250
264
  device.queue.submit([encoder.finish().unwrap()]).unwrap();
251
- await device.queue.onSubmittedWorkDone();
252
265
 
253
- // Exercise the real GPU telemetry readback before any mapped range is
254
- // unmapped. This is intentionally on the same submit as the visible and
255
- // indirect readbacks so a detached DataView cannot be hidden by a mock or a
256
- // separate inspection path.
257
- const lodSelection = await view.readLodSelection();
266
+ // Start observing immediately, then submit the cached graph again before
267
+ // the first mapAsync settles. The second copy must be skipped while the
268
+ // readback is pending; compute/raster work remains submit-able.
269
+ const pendingLodSelection = view.readLodSelection();
270
+ if (view.readLodSelection() !== pendingLodSelection) {
271
+ throw new Error('GPU-driven LOD telemetry did not coalesce concurrent observers');
272
+ }
273
+ const overlappingEncoder = device
274
+ .createCommandEncoder({ label: 'gpu-driven-evidence-overlap' })
275
+ .unwrap();
276
+ compiled.execute({ encoder: overlappingEncoder }).unwrap();
277
+ device.queue.submit([overlappingEncoder.finish().unwrap()]).unwrap();
278
+ const lodSelection = await pendingLodSelection;
258
279
  if (lodSelection === undefined || lodSelection.batches.length !== lodSelection.batchCount) {
259
280
  throw new Error('GPU-driven LOD selection readback unavailable or incomplete');
260
281
  }
282
+ await device.queue.onSubmittedWorkDone();
283
+
284
+ // After unmap, a later cached-graph submission must restore telemetry
285
+ // observation rather than leaving the latch permanently consumed.
286
+ const recoveryProjection = mat4.identity(mat4.create());
287
+ recoveryProjection[12] = 10;
288
+ view
289
+ .update(
290
+ topology.plan(),
291
+ sceneAvailability.scene,
292
+ frustum.fromViewProjection(frustum.create(), recoveryProjection),
293
+ )
294
+ .unwrap();
295
+ const recoveryEncoder = device
296
+ .createCommandEncoder({ label: 'gpu-driven-evidence-recovery' })
297
+ .unwrap();
298
+ compiled.execute({ encoder: recoveryEncoder }).unwrap();
299
+ device.queue.submit([recoveryEncoder.finish().unwrap()]).unwrap();
300
+ await device.queue.onSubmittedWorkDone();
301
+ const recoveredLodSelection = await view.readLodSelection();
302
+ if (
303
+ recoveredLodSelection === undefined ||
304
+ recoveredLodSelection === lodSelection ||
305
+ recoveredLodSelection.visible === lodSelection.visible
306
+ ) {
307
+ throw new Error('GPU-driven LOD telemetry did not recover after a skipped copy');
308
+ }
309
+ const validationError = await rawDevice.popErrorScope();
310
+ if (validationError !== null) {
311
+ throw new Error(`GPU-driven telemetry overlap validation failed: ${validationError.message}`);
312
+ }
261
313
 
262
314
  const visibleMap = (await visibleReadback.mapAsync(GPU_MAP_MODE_READ)).unwrap();
263
315
  const visibleValue = new DataView(visibleMap.getMappedRange().unwrap()).getUint32(0, true);
@@ -53,11 +53,26 @@ function snapshot(entityKey: number): RenderableSnapshot {
53
53
  };
54
54
  }
55
55
 
56
+ function updateSnapshot(value: RenderableSnapshot) {
57
+ return {
58
+ kind: 'update' as const,
59
+ worldId: value.worldId,
60
+ entityKey: value.entityKey,
61
+ snapshot: value,
62
+ };
63
+ }
64
+
56
65
  function preparedFrame(view: GpuDrivenView): PreparedGpuDrivenFrame {
57
66
  return {
58
67
  topologySignature: `view-generation:${view.inspect().resourceGeneration}`,
59
- entityKeys: new Set(),
60
- ownsAllRenderables: true,
68
+ ownsAllDrawItems: true,
69
+ standardPbrFrameResources: {
70
+ materialBindGroups: [],
71
+ materialSlotIndicesByEntity: new Map(),
72
+ instancesBindGroup: {} as never,
73
+ materialStride: 0,
74
+ sceneMaterialBuffer: {} as never,
75
+ },
61
76
  _commitResourceReplacement: () => view._commitResourceReplacement(),
62
77
  project: (graph) => {
63
78
  const projected = view.addPasses(graph);
@@ -126,8 +141,14 @@ describe('GpuDrivenView graph projection', () => {
126
141
  if (first === null) return;
127
142
  const prepared: PreparedGpuDrivenFrame = {
128
143
  topologySignature: 'stable-gpu-driven-test',
129
- entityKeys: new Set(),
130
- ownsAllRenderables: true,
144
+ ownsAllDrawItems: true,
145
+ standardPbrFrameResources: {
146
+ materialBindGroups: [],
147
+ materialSlotIndicesByEntity: new Map(),
148
+ instancesBindGroup: {} as never,
149
+ materialStride: 0,
150
+ sceneMaterialBuffer: {} as never,
151
+ },
131
152
  _commitResourceReplacement: () => undefined,
132
153
  project: (graph) => {
133
154
  const pass = graph.addComputePass('gpu-driven-test', {
@@ -153,7 +174,7 @@ describe('GpuDrivenView graph projection', () => {
153
174
  const device = (await adapter.requestDevice()).unwrap();
154
175
  const shader = (await rhi.createShaderModule(device, { code: 'synthetic' })).unwrap();
155
176
  const projection = new RenderScene();
156
- const delta = projection.apply([{ kind: 'create', snapshot: snapshot(1) }]);
177
+ const delta = projection.apply([updateSnapshot(snapshot(1))]);
157
178
  const sceneAvailability = GpuScene.create(device, 1).unwrap();
158
179
  expect(sceneAvailability.status).toBe('available');
159
180
  if (sceneAvailability.status !== 'available') return;
@@ -240,7 +261,7 @@ describe('GpuDrivenView graph projection', () => {
240
261
  const shader = (await rhi.createShaderModule(device, { code: 'synthetic' })).unwrap();
241
262
  const destroyBuffer = vi.spyOn(device, 'destroyBuffer');
242
263
  const projection = new RenderScene();
243
- const firstDelta = projection.apply([{ kind: 'create', snapshot: snapshot(1) }]);
264
+ const firstDelta = projection.apply([updateSnapshot(snapshot(1))]);
244
265
  const sceneAvailability = GpuScene.create(device, 2).unwrap();
245
266
  expect(sceneAvailability.status).toBe('available');
246
267
  if (sceneAvailability.status !== 'available') return;
@@ -351,7 +372,7 @@ describe('GpuDrivenView graph projection', () => {
351
372
  delete (device as unknown as { caps?: unknown }).caps;
352
373
  delete (device as unknown as { surfaceViewFormats?: unknown }).surfaceViewFormats;
353
374
 
354
- const secondDelta = projection.apply([{ kind: 'create', snapshot: snapshot(2) }]);
375
+ const secondDelta = projection.apply([updateSnapshot(snapshot(2))]);
355
376
  sceneAvailability.scene.sync(secondDelta).unwrap();
356
377
  topology.rebuild(projection.slotsSnapshot());
357
378
  view.update(topology.plan(), sceneAvailability.scene, planes).unwrap();
@@ -389,7 +410,7 @@ describe('GpuDrivenView graph projection', () => {
389
410
  const shader = (await rhi.createShaderModule(device, { code: 'synthetic' })).unwrap();
390
411
  const destroyBuffer = vi.spyOn(device, 'destroyBuffer');
391
412
  const projection = new RenderScene();
392
- const firstDelta = projection.apply([{ kind: 'create', snapshot: snapshot(1) }]);
413
+ const firstDelta = projection.apply([updateSnapshot(snapshot(1))]);
393
414
  const sceneAvailability = GpuScene.create(device, 2).unwrap();
394
415
  expect(sceneAvailability.status).toBe('available');
395
416
  if (sceneAvailability.status !== 'available') return;
@@ -406,7 +427,7 @@ describe('GpuDrivenView graph projection', () => {
406
427
  expect(firstVisible).toBeDefined();
407
428
  if (firstVisible === undefined) return;
408
429
 
409
- const secondDelta = projection.apply([{ kind: 'create', snapshot: snapshot(2) }]);
430
+ const secondDelta = projection.apply([updateSnapshot(snapshot(2))]);
410
431
  sceneAvailability.scene.sync(secondDelta).unwrap();
411
432
  topology.rebuild(projection.slotsSnapshot());
412
433
  view.update(topology.plan(), sceneAvailability.scene, planes).unwrap();
@@ -1,6 +1,7 @@
1
1
  import { frustum, mat4 } from '@forgeax/engine-math';
2
2
  import { describe, expect, it } from 'vitest';
3
3
  import { BatchTopology } from '../gpu-driven/batch-topology';
4
+ import { GPU_DRIVEN_VIEW_WGSL } from '../gpu-driven/view-gpu';
4
5
  import type { MaterialSnapshot, RenderableSnapshot } from '../render-system-extract';
5
6
  import { RenderScene } from '../scene/render-scene';
6
7
  import { classifyGpuDrivenView } from './gpu-driven-view-reference';
@@ -38,13 +39,22 @@ function snapshot(entityKey: number, x: number, resourceClass = 'plain'): Render
38
39
  };
39
40
  }
40
41
 
42
+ function updateSnapshot(value: RenderableSnapshot) {
43
+ return {
44
+ kind: 'update' as const,
45
+ worldId: value.worldId,
46
+ entityKey: value.entityKey,
47
+ snapshot: value,
48
+ };
49
+ }
50
+
41
51
  describe('GPU-driven batch topology and CPU oracle', () => {
42
52
  it('isolates LOD candidates so one indirect range cannot serve different meshes', () => {
43
53
  const projection = new RenderScene();
44
54
  const lods = [{ mesh: '00000000-0000-7000-8000-000000000001' as never, screenCoverage: 0.5 }];
45
55
  projection.apply([
46
- { kind: 'create', snapshot: { ...snapshot(1, 0), lods } },
47
- { kind: 'create', snapshot: { ...snapshot(2, 4), lods } },
56
+ updateSnapshot({ ...snapshot(1, 0), lods }),
57
+ updateSnapshot({ ...snapshot(2, 4), lods }),
48
58
  ]);
49
59
  const topology = new BatchTopology();
50
60
  topology.rebuild(projection.slotsSnapshot());
@@ -54,7 +64,7 @@ describe('GPU-driven batch topology and CPU oracle', () => {
54
64
 
55
65
  const transformOnly = projection.apply([
56
66
  {
57
- kind: 'update-transform',
67
+ kind: 'update',
58
68
  worldId: 0,
59
69
  entityKey: 1,
60
70
  world: snapshot(1, 0.25).transform.world,
@@ -64,22 +74,19 @@ describe('GPU-driven batch topology and CPU oracle', () => {
64
74
 
65
75
  const instancedProjection = new RenderScene();
66
76
  instancedProjection.apply([
67
- {
68
- kind: 'create',
69
- snapshot: {
70
- ...snapshot(3, 0),
71
- lods,
72
- instances: {
73
- transforms: new Float32Array([
74
- ...mat4.identity(mat4.create()),
75
- ...mat4.identity(mat4.create()),
76
- ]),
77
- instanceCount: 2,
78
- cacheKey: 3,
79
- archVersion: 1,
80
- },
77
+ updateSnapshot({
78
+ ...snapshot(3, 0),
79
+ lods,
80
+ instances: {
81
+ transforms: new Float32Array([
82
+ ...mat4.identity(mat4.create()),
83
+ ...mat4.identity(mat4.create()),
84
+ ]),
85
+ instanceCount: 2,
86
+ cacheKey: 3,
87
+ archVersion: 1,
81
88
  },
82
- },
89
+ }),
83
90
  ]);
84
91
  const instancedTopology = new BatchTopology();
85
92
  instancedTopology.rebuild(instancedProjection.slotsSnapshot());
@@ -89,12 +96,25 @@ describe('GPU-driven batch topology and CPU oracle', () => {
89
96
  );
90
97
  });
91
98
 
99
+ it('projects compact visible items into batch-local mesh and material indices', () => {
100
+ expect(GPU_DRIVEN_VIEW_WGSL).toMatch(
101
+ /vec2<u32>\(\s*candidate\.submitAdmission >> 1u,\s*materialOrPalette,/,
102
+ );
103
+ expect(GPU_DRIVEN_VIEW_WGSL).toContain('(candidate.submitAdmission & 1u)');
104
+ expect(GPU_DRIVEN_VIEW_WGSL).toContain('instance.customDataStart');
105
+ expect(GPU_DRIVEN_VIEW_WGSL).toContain('(candidate.materialSlot & 0x80000000u)');
106
+ expect(GPU_DRIVEN_VIEW_WGSL).toContain('visibleIndices[candidate.visibleBase + localVisible]');
107
+ expect(GPU_DRIVEN_VIEW_WGSL).toContain('overflowIndex(candidate.batchIndex)');
108
+ expect(GPU_DRIVEN_VIEW_WGSL).toContain('visibleCount = 0u');
109
+ expect(GPU_DRIVEN_VIEW_WGSL).toContain('indirectArgs[args + 4u] = 0u');
110
+ });
111
+
92
112
  it('patches topology only when compatibility membership changes', () => {
93
113
  const projection = new RenderScene();
94
114
  projection.apply([
95
- { kind: 'create', snapshot: snapshot(1, 0) },
96
- { kind: 'create', snapshot: snapshot(2, 0.5) },
97
- { kind: 'create', snapshot: snapshot(3, 0, 'textured') },
115
+ updateSnapshot(snapshot(1, 0)),
116
+ updateSnapshot(snapshot(2, 0.5)),
117
+ updateSnapshot(snapshot(3, 0, 'textured')),
98
118
  ]);
99
119
  const topology = new BatchTopology();
100
120
  topology.rebuild(projection.slotsSnapshot());
@@ -103,7 +123,7 @@ describe('GPU-driven batch topology and CPU oracle', () => {
103
123
 
104
124
  const transformOnly = projection.apply([
105
125
  {
106
- kind: 'update-transform',
126
+ kind: 'update',
107
127
  worldId: 0,
108
128
  entityKey: 1,
109
129
  world: snapshot(1, 0.25).transform.world,
@@ -120,10 +140,7 @@ describe('GPU-driven batch topology and CPU oracle', () => {
120
140
 
121
141
  it('compacts visible primitive indices and writes portable indexed indirect args', () => {
122
142
  const projection = new RenderScene();
123
- projection.apply([
124
- { kind: 'create', snapshot: snapshot(1, 0) },
125
- { kind: 'create', snapshot: snapshot(2, 10) },
126
- ]);
143
+ projection.apply([updateSnapshot(snapshot(1, 0)), updateSnapshot(snapshot(2, 10))]);
127
144
  const topology = new BatchTopology();
128
145
  topology.rebuild(projection.slotsSnapshot());
129
146
  const planes = frustum.fromViewProjection(frustum.create(), mat4.identity(mat4.create()));
@@ -152,16 +169,13 @@ describe('GPU-driven batch topology and CPU oracle', () => {
152
169
  expect(first).toBeDefined();
153
170
  if (first === undefined) return;
154
171
  projection.apply([
155
- {
156
- kind: 'create',
157
- snapshot: {
158
- ...source,
159
- gpuDrivenDraws: [
160
- { ...first, kind: 'non-indexed', first: 0, count: 3 },
161
- { ...first, kind: 'non-indexed', first: 3, count: 6 },
162
- ],
163
- },
164
- },
172
+ updateSnapshot({
173
+ ...source,
174
+ gpuDrivenDraws: [
175
+ { ...first, kind: 'non-indexed', first: 0, count: 3 },
176
+ { ...first, kind: 'non-indexed', first: 3, count: 6 },
177
+ ],
178
+ }),
165
179
  ]);
166
180
  const topology = new BatchTopology();
167
181
  topology.rebuild(projection.slotsSnapshot());
@@ -180,6 +194,105 @@ describe('GPU-driven batch topology and CPU oracle', () => {
180
194
  expect(secondArgs.getUint32(12, true)).toBe(0);
181
195
  });
182
196
 
197
+ it('retains source draw identity when an earlier compact draw is ineligible', () => {
198
+ const source = snapshot(1, 0);
199
+ const first = source.gpuDrivenDraws?.[0];
200
+ expect(first).toBeDefined();
201
+ if (first === undefined) return;
202
+ const projection = new RenderScene();
203
+ projection.apply([
204
+ updateSnapshot({
205
+ ...source,
206
+ gpuDrivenDraws: [
207
+ {
208
+ ...first,
209
+ drawItemIndex: 10,
210
+ prepared: {
211
+ identity: { material: 'custom', geometry: 'triangle', deformation: 'rigid' },
212
+ } as never,
213
+ },
214
+ { ...first, drawItemIndex: 20, first: 9, count: 12 },
215
+ ],
216
+ }),
217
+ ]);
218
+ const topology = new BatchTopology();
219
+ topology.rebuild(projection.slotsSnapshot());
220
+ const candidates = topology.plan().batches.flatMap((batch) => batch.candidates);
221
+ expect(candidates).toHaveLength(1);
222
+ expect(candidates[0]?.drawItemIndex).toBe(20);
223
+ expect(topology.plan().batches[0]?.key).toMatchObject({ first: 9, count: 12 });
224
+ });
225
+
226
+ it('patches a same-key eligibility swap using the retained draw identity', () => {
227
+ const source = snapshot(1, 0);
228
+ const first = source.gpuDrivenDraws?.[0];
229
+ expect(first).toBeDefined();
230
+ if (first === undefined) return;
231
+ const ineligible = {
232
+ ...first,
233
+ drawItemIndex: 10,
234
+ prepared: {
235
+ identity: { material: 'custom', geometry: 'triangle', deformation: 'rigid' },
236
+ } as never,
237
+ };
238
+ const eligible = { ...first, drawItemIndex: 20, first: 9, count: 12 };
239
+ const eligibleAt10 = { ...eligible, drawItemIndex: 10 };
240
+ const ineligibleAt20 = { ...ineligible, drawItemIndex: 20 };
241
+ const projection = new RenderScene();
242
+ projection.apply([updateSnapshot({ ...source, gpuDrivenDraws: [ineligible, eligible] })]);
243
+ const topology = new BatchTopology();
244
+ topology.rebuild(projection.slotsSnapshot());
245
+ const swapped = projection.apply([
246
+ updateSnapshot({ ...source, gpuDrivenDraws: [eligibleAt10, ineligibleAt20] }),
247
+ ]);
248
+ expect(topology.apply(swapped)).toBe(true);
249
+ expect(topology.inspect().patches).toBe(1);
250
+ expect(topology.plan().batches.flatMap((batch) => batch.candidates)[0]?.drawItemIndex).toBe(10);
251
+ });
252
+
253
+ it('keeps prepared material and range identity after reversing submesh order', () => {
254
+ const source = snapshot(1, 0);
255
+ const first = source.gpuDrivenDraws?.[0];
256
+ expect(first).toBeDefined();
257
+ if (first === undefined) return;
258
+ const materialA = { ...material, materialHandle: 11 } as MaterialSnapshot;
259
+ const materialB = { ...material, materialHandle: 12 } as MaterialSnapshot;
260
+ const orderedDraws = [
261
+ { ...first, drawItemIndex: 4, materialSlot: 0, first: 0, count: 3 },
262
+ { ...first, drawItemIndex: 9, materialSlot: 1, first: 3, count: 6 },
263
+ ];
264
+ const [orderedFirst, orderedSecond] = orderedDraws;
265
+ if (orderedFirst === undefined || orderedSecond === undefined) return;
266
+ const ordered = {
267
+ ...source,
268
+ materials: [materialA, materialB],
269
+ material: materialA,
270
+ gpuDrivenDraws: orderedDraws,
271
+ };
272
+ const reversed = {
273
+ ...ordered,
274
+ gpuDrivenDraws: [orderedSecond, orderedFirst],
275
+ };
276
+ const orderedTopology = new BatchTopology();
277
+ const reversedTopology = new BatchTopology();
278
+ const orderedScene = new RenderScene();
279
+ const reversedScene = new RenderScene();
280
+ orderedScene.apply([updateSnapshot(ordered)]);
281
+ reversedScene.apply([updateSnapshot(reversed)]);
282
+ orderedTopology.rebuild(orderedScene.slotsSnapshot());
283
+ reversedTopology.rebuild(reversedScene.slotsSnapshot());
284
+ const describe = (topology: BatchTopology) =>
285
+ topology
286
+ .plan()
287
+ .batches.map((batch) => [
288
+ batch.key.materialSlot,
289
+ batch.key.first,
290
+ batch.key.count,
291
+ batch.candidates[0]?.drawItemIndex,
292
+ ]);
293
+ expect(describe(reversedTopology).sort()).toEqual(describe(orderedTopology).sort());
294
+ });
295
+
183
296
  it('culls ordinary instance-local transforms and emits instance identities', () => {
184
297
  const source = snapshot(1, 0);
185
298
  const identity = mat4.identity(mat4.create());
@@ -187,18 +300,15 @@ describe('GPU-driven batch topology and CPU oracle', () => {
187
300
  outside[12] = 10;
188
301
  const projection = new RenderScene();
189
302
  projection.apply([
190
- {
191
- kind: 'create',
192
- snapshot: {
193
- ...source,
194
- instances: {
195
- transforms: new Float32Array([...identity, ...outside]),
196
- instanceCount: 2,
197
- cacheKey: 1,
198
- archVersion: 1,
199
- },
303
+ updateSnapshot({
304
+ ...source,
305
+ instances: {
306
+ transforms: new Float32Array([...identity, ...outside]),
307
+ instanceCount: 2,
308
+ cacheKey: 1,
309
+ archVersion: 1,
200
310
  },
201
- },
311
+ }),
202
312
  ]);
203
313
  const topology = new BatchTopology();
204
314
  topology.rebuild(projection.slotsSnapshot());
@@ -215,10 +325,7 @@ describe('GPU-driven batch topology and CPU oracle', () => {
215
325
 
216
326
  it('reports overflow instead of silently accepting a truncated batch', () => {
217
327
  const projection = new RenderScene();
218
- projection.apply([
219
- { kind: 'create', snapshot: snapshot(1, 0) },
220
- { kind: 'create', snapshot: snapshot(2, 0.5) },
221
- ]);
328
+ projection.apply([updateSnapshot(snapshot(1, 0)), updateSnapshot(snapshot(2, 0.5))]);
222
329
  const topology = new BatchTopology();
223
330
  topology.rebuild(projection.slotsSnapshot());
224
331
  const plan = topology.plan();
@@ -239,7 +346,7 @@ describe('GPU-driven batch topology and CPU oracle', () => {
239
346
  const projection = new RenderScene();
240
347
  const { localAabb: _localAabb, ...withoutBounds } = snapshot(1, 0);
241
348
  const topology = new BatchTopology();
242
- topology.rebuild(projection.apply([{ kind: 'create', snapshot: withoutBounds }]).createdSlots);
349
+ topology.rebuild(projection.apply([updateSnapshot(withoutBounds)]).createdSlots);
243
350
  expect(topology.inspect().ineligible).toBe(1);
244
351
 
245
352
  const removed = projection.apply([{ kind: 'remove', worldId: 0, entityKey: 1 }]);
@@ -4,7 +4,12 @@ import { runBrowserGpuPassTiming } from './gpu-pass-timing-browser-runner.js';
4
4
  const browserReady = typeof navigator !== 'undefined' && navigator.gpu !== undefined;
5
5
 
6
6
  describe.skipIf(!browserReady)('GPU pass timing Browser dev-server runner', () => {
7
- it('keeps receipt facts and unsupported timing structured without stopping draw', async () => {
7
+ // The first live lavapipe renderer pair can exceed Vitest's 15s default while
8
+ // the shader manifest and timestamp-query path are cold; keep this bound
9
+ // local to the real WebGPU owner instead of weakening the global timeout.
10
+ it('keeps receipt facts and unsupported timing structured without stopping draw', {
11
+ timeout: 30_000,
12
+ }, async () => {
8
13
  const result = await runBrowserGpuPassTiming();
9
14
  expect(result.frames).toBe(3);
10
15
  if (result.supported) {
@@ -121,4 +121,46 @@ describe('GpuResidencyCache mesh stride', () => {
121
121
  if (packedIndices === undefined) return;
122
122
  expect(new Uint16Array(packedIndices.buffer)).toEqual(new Uint16Array([0, 1, 2, 0, 2, 1]));
123
123
  });
124
+
125
+ it('refuses a payload whose bytes do not match the projected stride', async () => {
126
+ const adapter = (await rhi.requestAdapter()).unwrap();
127
+ const device = (await adapter.requestDevice()).unwrap();
128
+ const store = new GpuResidencyCache();
129
+ store.configureGpuDevice(
130
+ device,
131
+ undefined,
132
+ () => {
133
+ throw new Error('cubemap registration is not part of this test');
134
+ },
135
+ device.caps,
136
+ );
137
+ const mesh: MeshAsset = {
138
+ kind: 'mesh',
139
+ vertices: new Float32Array(49),
140
+ attributes: {
141
+ position: new Float32Array(9),
142
+ normal: new Float32Array(9),
143
+ uv: new Float32Array(6),
144
+ tangent: new Float32Array(12),
145
+ },
146
+ submeshes: [
147
+ {
148
+ indexOffset: 0,
149
+ indexCount: 0,
150
+ vertexCount: 3,
151
+ topology: 'triangle-list',
152
+ materialSlot: 0,
153
+ },
154
+ ],
155
+ materialSlots: [{ slotName: 'default' }],
156
+ };
157
+ const world = new World();
158
+ const handle = world.allocSharedRef('MeshAsset', mesh);
159
+
160
+ const resident = store.ensureResident(handle, mesh);
161
+
162
+ expect(resident.ok).toBe(false);
163
+ if (!resident.ok) expect(resident.error.code).toBe('asset-not-registered');
164
+ expect(store.getMeshGpuHandles(handle)).toBeUndefined();
165
+ });
124
166
  });
@@ -76,7 +76,12 @@ fn fs(input: VertexOutput) -> @location(0) vec4<f32> {
76
76
  }
77
77
  `;
78
78
 
79
- const material = { materialHandle: 1 } as MaterialSnapshot;
79
+ const material = {
80
+ baseColor: new Float32Array([1, 1, 1]),
81
+ metallic: 0,
82
+ roughness: 1,
83
+ materialHandle: 1,
84
+ } as MaterialSnapshot;
80
85
 
81
86
  function snapshot(entityKey: number, translationX: number): RenderableSnapshot {
82
87
  const world = new Float32Array(16);
@@ -97,6 +102,15 @@ function snapshot(entityKey: number, translationX: number): RenderableSnapshot {
97
102
  };
98
103
  }
99
104
 
105
+ function updateSnapshot(value: RenderableSnapshot) {
106
+ return {
107
+ kind: 'update' as const,
108
+ worldId: value.worldId,
109
+ entityKey: value.entityKey,
110
+ snapshot: value,
111
+ };
112
+ }
113
+
100
114
  function bufferBinding(buffer: Buffer) {
101
115
  return { kind: 'buffer' as const, value: { buffer } };
102
116
  }
@@ -119,10 +133,10 @@ export async function runGpuSceneGraph(): Promise<GpuSceneGraphEvidence> {
119
133
  scene
120
134
  .sync(
121
135
  projection.apply([
122
- { kind: 'create', snapshot: snapshot(10, -3) },
123
- { kind: 'create', snapshot: snapshot(11, -0.5) },
124
- { kind: 'create', snapshot: snapshot(12, 0.5) },
125
- { kind: 'create', snapshot: snapshot(13, 3) },
136
+ updateSnapshot(snapshot(10, -3)),
137
+ updateSnapshot(snapshot(11, -0.5)),
138
+ updateSnapshot(snapshot(12, 0.5)),
139
+ updateSnapshot(snapshot(13, 3)),
126
140
  ]),
127
141
  )
128
142
  .unwrap();