@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
@@ -1,4 +1,5 @@
1
1
  import type { PrimitiveTopology } from '@forgeax/engine-types';
2
+ import { gpuDrivenSourceDrawItemIndex } from '../extract/gpu-driven';
2
3
  import type { BatchTopologyInspection } from '../inspection-types';
3
4
  import type { CameraSnapshot } from '../render-contract';
4
5
  import type { RenderSceneApplyResult, RenderSceneSlot } from '../scene/render-scene-types';
@@ -8,6 +9,9 @@ import type { PreparedGpuDrivenDraw } from './prepared-draw';
8
9
 
9
10
  export type { BatchTopologyInspection } from '../inspection-types';
10
11
 
12
+ /** High bit in the compact candidate material lane marks a skin palette row. */
13
+ export const GPU_DRIVEN_SKIN_FLAG = 0x80000000;
14
+
11
15
  export interface GpuDrivenBatchKey {
12
16
  readonly assetHandle: number;
13
17
  readonly drawKind: 'indexed' | 'non-indexed';
@@ -31,6 +35,7 @@ export interface GpuDrivenCandidate {
31
35
  readonly generation: number;
32
36
  readonly drawItemIndex: number;
33
37
  readonly instanceOrdinal: number;
38
+ readonly prepared?: PreparedGpuDrivenDraw;
34
39
  /** Absolute coverage rows uploaded to the GPU selector; root is implicit. */
35
40
  readonly lodCoverages?: readonly number[];
36
41
  readonly lodHysteresis?: number;
@@ -40,7 +45,6 @@ export interface GpuDrivenCandidate {
40
45
  readonly count: number;
41
46
  readonly baseVertex: number;
42
47
  }[];
43
- readonly prepared?: PreparedGpuDrivenDraw;
44
48
  }
45
49
 
46
50
  export interface GpuDrivenBatch {
@@ -55,6 +59,8 @@ export interface GpuDrivenBatch {
55
59
 
56
60
  export interface SubmissionPlan {
57
61
  readonly revision: number;
62
+ /** Payload-only updates keep topology revision stable but still invalidate the plan snapshot. */
63
+ readonly payloadRevision: number;
58
64
  readonly batches: readonly GpuDrivenBatch[];
59
65
  readonly candidateCount: number;
60
66
  readonly visibleCapacity: number;
@@ -86,6 +92,88 @@ export function compactGpuLodCandidates(
86
92
  );
87
93
  }
88
94
 
95
+ export interface SubmissionCandidateMembershipEntry {
96
+ readonly batchId: number;
97
+ readonly candidate: GpuDrivenCandidate;
98
+ }
99
+
100
+ /**
101
+ * Immutable reverse membership for one submission topology.
102
+ *
103
+ * Shadow views query the same candidate domain as the main view. Keeping the
104
+ * primitive-to-batch join beside the immutable plan makes that lookup once per
105
+ * topology instead of rescanning every batch for every view.
106
+ */
107
+ export interface SubmissionCandidateMembership {
108
+ readonly source: SubmissionPlan;
109
+ readonly byPrimitiveIndex: ReadonlyMap<number, readonly SubmissionCandidateMembershipEntry[]>;
110
+ }
111
+
112
+ const submissionCandidateMembershipCache = new WeakMap<
113
+ SubmissionPlan,
114
+ SubmissionCandidateMembership
115
+ >();
116
+
117
+ export function buildSubmissionCandidateMembership(
118
+ source: SubmissionPlan,
119
+ ): SubmissionCandidateMembership {
120
+ const cached = submissionCandidateMembershipCache.get(source);
121
+ if (cached !== undefined) return cached;
122
+
123
+ const mutable = new Map<number, SubmissionCandidateMembershipEntry[]>();
124
+ for (const batch of source.batches) {
125
+ for (const candidate of batch.candidates) {
126
+ const entries = mutable.get(candidate.primitiveIndex) ?? [];
127
+ entries.push({ batchId: batch.batchId, candidate });
128
+ mutable.set(candidate.primitiveIndex, entries);
129
+ }
130
+ }
131
+ const byPrimitiveIndex = new Map<number, readonly SubmissionCandidateMembershipEntry[]>();
132
+ for (const [primitiveIndex, entries] of mutable) {
133
+ byPrimitiveIndex.set(primitiveIndex, Object.freeze(entries));
134
+ }
135
+ const membership: SubmissionCandidateMembership = {
136
+ source,
137
+ byPrimitiveIndex,
138
+ };
139
+ submissionCandidateMembershipCache.set(source, membership);
140
+ return membership;
141
+ }
142
+
143
+ /**
144
+ * Re-project one source topology for a view without changing batch identity.
145
+ * The returned plan only changes candidate windows and keeps batch ids,
146
+ * generations, draw ranges, and indirect offsets from the source plan.
147
+ */
148
+ export function buildBatchAlignedSubmission(
149
+ source: SubmissionPlan,
150
+ candidatesByBatch: ReadonlyMap<number, readonly GpuDrivenCandidate[]>,
151
+ ): SubmissionPlan {
152
+ let visibleBase = 0;
153
+ const batches: GpuDrivenBatch[] = [];
154
+ for (const sourceBatch of source.batches) {
155
+ const candidates = candidatesByBatch.get(sourceBatch.batchId) ?? [];
156
+ if (candidates.length === 0) continue;
157
+ visibleBase = alignInstanceBase(visibleBase);
158
+ batches.push(
159
+ Object.freeze({
160
+ ...sourceBatch,
161
+ candidates: Object.freeze([...candidates]),
162
+ visibleBase,
163
+ visibleCapacity: candidates.length,
164
+ }),
165
+ );
166
+ visibleBase += candidates.length;
167
+ }
168
+ return Object.freeze({
169
+ revision: source.revision,
170
+ payloadRevision: source.payloadRevision,
171
+ batches: Object.freeze(batches),
172
+ candidateCount: batches.reduce((total, batch) => total + batch.candidates.length, 0),
173
+ visibleCapacity: visibleBase,
174
+ });
175
+ }
176
+
89
177
  interface MutableBatch {
90
178
  readonly batchId: number;
91
179
  readonly generation: number;
@@ -93,7 +181,37 @@ interface MutableBatch {
93
181
  readonly candidates: Map<string, GpuDrivenCandidate>;
94
182
  }
95
183
 
96
- function eligibleKeys(slot: RenderSceneSlot): readonly GpuDrivenBatchKey[] {
184
+ interface EligibleGpuDrivenDraw {
185
+ readonly sourceDrawIndex: number;
186
+ readonly key: GpuDrivenBatchKey;
187
+ readonly prepared?: PreparedGpuDrivenDraw;
188
+ readonly projectedHeight?: number;
189
+ readonly lodCoverages?: readonly number[];
190
+ readonly lodHysteresis?: number;
191
+ readonly lodRanges?: readonly {
192
+ readonly first: number;
193
+ readonly count: number;
194
+ readonly baseVertex: number;
195
+ }[];
196
+ /** Candidate data that does not change batch compatibility. */
197
+ readonly payloadRevision: string;
198
+ }
199
+
200
+ interface MembershipDraw {
201
+ readonly sourceDrawIndex: number;
202
+ readonly key: GpuDrivenBatchKey;
203
+ readonly batchText: string;
204
+ readonly candidateKeyPrefix: string;
205
+ readonly payloadRevision: string;
206
+ }
207
+
208
+ interface MembershipProjection {
209
+ readonly instanceCount: number;
210
+ readonly hasLod: boolean;
211
+ readonly draws: readonly MembershipDraw[];
212
+ }
213
+
214
+ function eligibleDraws(slot: RenderSceneSlot): readonly EligibleGpuDrivenDraw[] {
97
215
  const snapshot = slot.snapshot;
98
216
  const draws = snapshot.gpuDrivenDraws;
99
217
  if (
@@ -101,29 +219,51 @@ function eligibleKeys(slot: RenderSceneSlot): readonly GpuDrivenBatchKey[] {
101
219
  draws.length === 0 ||
102
220
  snapshot.instances?.instanceCount === 0 ||
103
221
  snapshot.localAabb === undefined ||
104
- snapshot.skin !== undefined ||
105
222
  snapshot.morph !== undefined ||
106
223
  snapshot.spriteInstances !== undefined
107
224
  ) {
108
225
  return [];
109
226
  }
110
- return draws.flatMap((draw) => {
227
+ const result: EligibleGpuDrivenDraw[] = [];
228
+ for (let compactIndex = 0; compactIndex < draws.length; compactIndex += 1) {
229
+ const draw = draws[compactIndex];
230
+ if (draw === undefined) continue;
231
+ const drawItemIndex = gpuDrivenSourceDrawItemIndex(draw, compactIndex);
111
232
  const prepared = draw.prepared;
112
233
  const material = snapshot.materials[draw.materialSlot] ?? snapshot.material;
113
234
  if (prepared !== undefined) {
114
235
  const isStandardPbr =
115
236
  (material.materialShaderId === 'forgeax::default-standard-pbr' &&
116
237
  prepared.identity.material === 'forgeax::default-standard-pbr') ||
117
- (material.materialShaderId === 'forgeax::default-standard-pbr-skin' &&
118
- prepared.identity.material === 'forgeax::default-standard-pbr-skin');
238
+ ((material.materialShaderId === 'forgeax::pbr-skin' ||
239
+ material.materialShaderId === 'forgeax::default-standard-pbr-skin') &&
240
+ (prepared.identity.material === 'forgeax::pbr-skin' ||
241
+ prepared.identity.material === 'forgeax::default-standard-pbr-skin'));
119
242
  const isAlphaBlend =
120
243
  material.transparent === true || material.renderState?.blend !== undefined;
121
- if (!isStandardPbr || isAlphaBlend || prepared.identity.deformation !== 'rigid') return [];
244
+ const cpuOnlyMaterialResources =
245
+ (material.textureSources?.size ?? 0) > 0 || (material.videoTextureFields?.size ?? 0) > 0;
246
+ const skinReady =
247
+ prepared.identity.deformation !== 'skin' ||
248
+ (snapshot.skin?.storageOrUniform === 'storage' &&
249
+ snapshot.skin.customDataStart >= 0 &&
250
+ Number.isInteger(snapshot.skin.customDataStart) &&
251
+ hasFiniteOrderedBounds(snapshot.skin.bounds) &&
252
+ prepared.skinPaletteAddress !== undefined);
253
+ if (
254
+ !isStandardPbr ||
255
+ isAlphaBlend ||
256
+ cpuOnlyMaterialResources ||
257
+ (prepared.identity.deformation !== 'rigid' && prepared.identity.deformation !== 'skin') ||
258
+ !skinReady
259
+ )
260
+ continue;
122
261
  const preparedIdentity = `${prepared.identity.material}|${prepared.identity.geometry}|${prepared.identity.deformation}`;
123
262
  const admission =
124
263
  typeof material.paramSnapshot?.alphaCutoff === 'number' ? 'alpha-mask' : 'opaque';
125
- return [
126
- {
264
+ result.push({
265
+ sourceDrawIndex: drawItemIndex,
266
+ key: {
127
267
  assetHandle: snapshot.assetHandle,
128
268
  drawKind: draw.kind,
129
269
  first: prepared.first,
@@ -137,10 +277,14 @@ function eligibleKeys(slot: RenderSceneSlot): readonly GpuDrivenBatchKey[] {
137
277
  resourceIdentity: draw.materialResourceClass,
138
278
  admission,
139
279
  },
140
- ];
280
+ prepared,
281
+ ...candidatePayload(draw, snapshot),
282
+ });
283
+ continue;
141
284
  }
142
- return [
143
- {
285
+ result.push({
286
+ sourceDrawIndex: drawItemIndex,
287
+ key: {
144
288
  assetHandle: snapshot.assetHandle,
145
289
  drawKind: draw.kind,
146
290
  first: draw.first,
@@ -151,8 +295,66 @@ function eligibleKeys(slot: RenderSceneSlot): readonly GpuDrivenBatchKey[] {
151
295
  pipelineClass: draw.pipelineClass,
152
296
  materialResourceClass: draw.materialResourceClass,
153
297
  },
154
- ];
298
+ ...candidatePayload(draw, snapshot),
299
+ });
300
+ }
301
+ return result;
302
+ }
303
+
304
+ function candidatePayload(
305
+ draw: NonNullable<RenderSceneSlot['snapshot']['gpuDrivenDraws']>[number],
306
+ snapshot: RenderSceneSlot['snapshot'],
307
+ ): Pick<
308
+ EligibleGpuDrivenDraw,
309
+ 'lodCoverages' | 'lodHysteresis' | 'lodRanges' | 'payloadRevision' | 'projectedHeight'
310
+ > {
311
+ const lodCoverages =
312
+ snapshot.lods === undefined
313
+ ? undefined
314
+ : [1, ...snapshot.lods.map((lod) => lod.screenCoverage)];
315
+ const lodRanges = draw.lodRanges as EligibleGpuDrivenDraw['lodRanges'];
316
+ const lodHysteresis = snapshot.lodHysteresis;
317
+ const payloadRevision = JSON.stringify({
318
+ projectedHeight: draw.projectedHeight,
319
+ lodCoverages,
320
+ lodHysteresis,
321
+ lodRanges,
322
+ prepared: draw.prepared,
155
323
  });
324
+ return {
325
+ ...(draw.projectedHeight === undefined ? {} : { projectedHeight: draw.projectedHeight }),
326
+ ...(lodCoverages === undefined ? {} : { lodCoverages }),
327
+ ...(lodHysteresis === undefined ? {} : { lodHysteresis }),
328
+ ...(lodRanges === undefined ? {} : { lodRanges }),
329
+ payloadRevision,
330
+ };
331
+ }
332
+
333
+ function hasFiniteOrderedBounds(bounds: Float32Array | undefined): boolean {
334
+ if (bounds === undefined || bounds.length < 6) return false;
335
+ const minX = bounds[0];
336
+ const minY = bounds[1];
337
+ const minZ = bounds[2];
338
+ const maxX = bounds[3];
339
+ const maxY = bounds[4];
340
+ const maxZ = bounds[5];
341
+ return (
342
+ minX !== undefined &&
343
+ minY !== undefined &&
344
+ minZ !== undefined &&
345
+ maxX !== undefined &&
346
+ maxY !== undefined &&
347
+ maxZ !== undefined &&
348
+ Number.isFinite(minX) &&
349
+ Number.isFinite(minY) &&
350
+ Number.isFinite(minZ) &&
351
+ Number.isFinite(maxX) &&
352
+ Number.isFinite(maxY) &&
353
+ Number.isFinite(maxZ) &&
354
+ minX <= maxX &&
355
+ minY <= maxY &&
356
+ minZ <= maxZ
357
+ );
156
358
  }
157
359
 
158
360
  function keyText(key: GpuDrivenBatchKey): string {
@@ -160,11 +362,9 @@ function keyText(key: GpuDrivenBatchKey): string {
160
362
  }
161
363
 
162
364
  /**
163
- * A GPU indirect draw has one index/vertex range for the whole batch. LOD
365
+ * A GPU indirect draw has one index/vertex range for the whole batch. LOD
164
366
  * selection is per candidate, so sharing a batch between LOD candidates would
165
- * let `finalizeView` pick the first candidate's range for every visible
166
- * instance. Keep LOD candidates in single-candidate batches; ordinary meshes
167
- * retain the existing compatibility batching path.
367
+ * let the first candidate's range serve every visible instance.
168
368
  */
169
369
  function candidateBatchText(
170
370
  key: GpuDrivenBatchKey,
@@ -178,19 +378,32 @@ function candidateBatchText(
178
378
  : keyText(key);
179
379
  }
180
380
 
181
- function membershipTexts(slot: RenderSceneSlot): readonly string[] {
182
- const keys = eligibleKeys(slot);
381
+ function drawBatchText(
382
+ key: GpuDrivenBatchKey,
383
+ primitiveIndex: number,
384
+ drawItemIndex: number,
385
+ hasLod: boolean,
386
+ ): string {
387
+ return hasLod ? `${keyText(key)}|lod:${primitiveIndex}:${drawItemIndex}` : keyText(key);
388
+ }
389
+
390
+ function membershipProjection(
391
+ slot: RenderSceneSlot,
392
+ draws = eligibleDraws(slot),
393
+ ): MembershipProjection {
183
394
  const instanceCount = slot.snapshot.instances?.instanceCount ?? 1;
184
395
  const hasLod = (slot.snapshot.lods?.length ?? 0) > 0;
185
- const texts: string[] = [];
186
- for (let drawItemIndex = 0; drawItemIndex < keys.length; drawItemIndex += 1) {
187
- const key = keys[drawItemIndex];
188
- if (key === undefined) continue;
189
- for (let instanceOrdinal = 0; instanceOrdinal < instanceCount; instanceOrdinal += 1) {
190
- texts.push(candidateBatchText(key, slot.slot, drawItemIndex, instanceOrdinal, hasLod));
191
- }
192
- }
193
- return texts;
396
+ return {
397
+ instanceCount,
398
+ hasLod,
399
+ draws: draws.map((draw) => ({
400
+ sourceDrawIndex: draw.sourceDrawIndex,
401
+ key: draw.key,
402
+ batchText: drawBatchText(draw.key, slot.slot, draw.sourceDrawIndex, hasLod),
403
+ candidateKeyPrefix: `${slot.slot}:${draw.sourceDrawIndex}:`,
404
+ payloadRevision: draw.payloadRevision,
405
+ })),
406
+ };
194
407
  }
195
408
 
196
409
  function alignInstanceBase(value: number): number {
@@ -209,10 +422,6 @@ export function projectedHeightForCandidate(slot: RenderSceneSlot, camera: Camer
209
422
  const halfY = Math.abs((aabb[4] ?? 0) - (aabb[1] ?? 0)) * 0.5;
210
423
  const halfZ = Math.abs((aabb[5] ?? 0) - (aabb[2] ?? 0)) * 0.5;
211
424
  const world = slot.snapshot.transform.world;
212
- // Transform the local AABB's half extents through the absolute value of the
213
- // world 3x3. This is the conservative world-space sphere bound for every
214
- // rotation and signed/non-uniform scale, and keeps CPU projection aligned
215
- // with the world transform uploaded to the GPU selector.
216
425
  const worldHalfX =
217
426
  Math.abs(world[0] ?? 0) * halfX +
218
427
  Math.abs(world[4] ?? 0) * halfY +
@@ -241,16 +450,19 @@ export function projectedHeightForCandidate(slot: RenderSceneSlot, camera: Camer
241
450
  /** Stable compatibility grouping; per-view visibility never mutates this owner. */
242
451
  export class BatchTopology {
243
452
  private readonly batches = new Map<string, MutableBatch>();
244
- private readonly membershipByPrimitive = new Map<
245
- number,
246
- readonly { readonly batchText: string; readonly candidateKey: string }[]
247
- >();
453
+ private readonly membershipByPrimitive = new Map<number, MembershipProjection>();
248
454
  private readonly ineligiblePrimitives = new Set<number>();
249
455
  private readonly generationByBatchId: number[] = [];
250
456
  private readonly freeBatchIds: number[] = [];
251
457
  private revision = 0;
458
+ private payloadRevision = 0;
252
459
  private rebuilds = 0;
253
460
  private patches = 0;
461
+ private payloadPatches = 0;
462
+ private membershipChecks = 0;
463
+ private membershipAllocations = 0;
464
+ private candidateAdds = 0;
465
+ private candidateRemoves = 0;
254
466
  private cachedPlan: SubmissionPlan | undefined;
255
467
 
256
468
  rebuild(slots: readonly RenderSceneSlot[]): void {
@@ -261,37 +473,125 @@ export class BatchTopology {
261
473
  this.freeBatchIds.length = 0;
262
474
  for (const slot of slots) this.add(slot);
263
475
  this.revision += 1;
476
+ this.payloadRevision += 1;
264
477
  this.rebuilds += 1;
265
478
  this.cachedPlan = undefined;
266
479
  }
267
480
 
268
481
  apply(delta: RenderSceneApplyResult): boolean {
269
482
  let changed = false;
270
- for (const removed of delta.removedSlots) changed = this.remove(removed.slot) || changed;
483
+ let topologyChanged = false;
484
+ for (const removed of delta.removedSlots) {
485
+ const removedChanged = this.remove(removed.slot);
486
+ changed = removedChanged || changed;
487
+ topologyChanged = removedChanged || topologyChanged;
488
+ }
271
489
  for (const slot of delta.recreatedSlots) {
272
- changed = this.remove(slot.slot) || changed;
273
- changed = this.add(slot) || changed;
490
+ const removedChanged = this.remove(slot.slot);
491
+ const addedChanged = this.add(slot);
492
+ changed = removedChanged || addedChanged || changed;
493
+ topologyChanged = removedChanged || addedChanged || topologyChanged;
274
494
  }
275
- // Most updated slots are transform-only. A full renderable update can
276
- // still carry a changed material/geometry/draw topology, so compare the
277
- // stable batch memberships and patch only when that key actually changed.
278
- // This keeps moving entities on the zero-work transform lane while making
279
- // same-entity resource edits visible to the GPU-driven owner.
280
- for (const slot of delta.updatedSlots) {
281
- const previous = this.membershipByPrimitive.get(slot.slot) ?? [];
282
- const next = membershipTexts(slot);
283
- if (
284
- previous.length === next.length &&
285
- previous.every((membership, index) => membership.batchText === next[index])
286
- ) {
495
+ // Membership depends on source descriptors and instance cardinality.
496
+ // Root matrices feed visibility without changing this dependency.
497
+ const contentUpdatedSlots = delta.contentUpdatedSlots;
498
+ const instanceUpdatedSlots = delta.instanceUpdatedSlots;
499
+ const membershipUpdates = new Map<number, { slot: RenderSceneSlot; content: boolean }>();
500
+ for (const slot of contentUpdatedSlots) {
501
+ membershipUpdates.set(slot.slot, { slot, content: true });
502
+ }
503
+ // Instance cardinality is a membership input, including in mixed updates.
504
+ for (const slot of instanceUpdatedSlots) {
505
+ if (!membershipUpdates.has(slot.slot)) {
506
+ membershipUpdates.set(slot.slot, { slot, content: false });
507
+ }
508
+ }
509
+ for (const update of membershipUpdates.values()) {
510
+ const { slot, content } = update;
511
+ const eligible = eligibleDraws(slot);
512
+ const next = membershipProjection(slot, eligible);
513
+ // The projection is one descriptor per eligible source draw; candidate
514
+ // identities are derived from the stable ordinal and are not stored as
515
+ // N per-instance comparison records.
516
+ this.membershipAllocations += next.draws.length;
517
+ const previous = this.membershipByPrimitive.get(slot.slot);
518
+ this.membershipChecks += 1;
519
+ const topologyStable =
520
+ previous !== undefined &&
521
+ previous.instanceCount === next.instanceCount &&
522
+ previous.hasLod === next.hasLod &&
523
+ previous.draws.length === next.draws.length &&
524
+ previous.draws.every((membership, index) => {
525
+ const candidate = next.draws[index];
526
+ return (
527
+ candidate !== undefined &&
528
+ membership.sourceDrawIndex === candidate.sourceDrawIndex &&
529
+ membership.batchText === candidate.batchText
530
+ );
531
+ });
532
+ if (!topologyStable) {
533
+ const removedChanged = this.remove(slot.slot);
534
+ const addedChanged = this.add(slot);
535
+ changed = removedChanged || addedChanged || changed;
536
+ topologyChanged = removedChanged || addedChanged || topologyChanged;
287
537
  continue;
288
538
  }
289
- changed = this.remove(slot.slot) || changed;
290
- changed = this.add(slot) || changed;
539
+ if (!content) {
540
+ this.membershipByPrimitive.set(slot.slot, next);
541
+ continue;
542
+ }
543
+ let payloadChanged = false;
544
+ let topologyFallback = false;
545
+ for (let index = 0; index < next.draws.length; index += 1) {
546
+ const oldMembership = previous.draws[index];
547
+ const newMembership = next.draws[index];
548
+ const draw = eligible[index];
549
+ if (oldMembership === undefined || newMembership === undefined || draw === undefined) {
550
+ continue;
551
+ }
552
+ if (oldMembership.payloadRevision === newMembership.payloadRevision) continue;
553
+ for (let instanceOrdinal = 0; instanceOrdinal < next.instanceCount; instanceOrdinal += 1) {
554
+ const batchText = candidateBatchText(
555
+ draw.key,
556
+ slot.slot,
557
+ draw.sourceDrawIndex,
558
+ instanceOrdinal,
559
+ next.hasLod,
560
+ );
561
+ const batch = this.batches.get(batchText);
562
+ const candidateKey = `${newMembership.candidateKeyPrefix}${instanceOrdinal}`;
563
+ if (batch === undefined || !batch.candidates.has(candidateKey)) {
564
+ const removedChanged = this.remove(slot.slot);
565
+ const addedChanged = this.add(slot);
566
+ changed = removedChanged || addedChanged || changed;
567
+ topologyChanged = removedChanged || addedChanged || topologyChanged;
568
+ topologyFallback = true;
569
+ break;
570
+ }
571
+ batch.candidates.set(
572
+ candidateKey,
573
+ this.candidateFromEligible(slot, instanceOrdinal, draw),
574
+ );
575
+ }
576
+ if (topologyFallback) break;
577
+ payloadChanged = true;
578
+ }
579
+ this.membershipByPrimitive.set(slot.slot, next);
580
+ if (payloadChanged) {
581
+ changed = true;
582
+ this.payloadRevision += 1;
583
+ this.payloadPatches += 1;
584
+ this.cachedPlan = undefined;
585
+ }
291
586
  }
292
- for (const slot of delta.createdSlots) changed = this.add(slot) || changed;
293
- if (changed) {
587
+ for (const slot of delta.createdSlots) {
588
+ const addedChanged = this.add(slot);
589
+ changed = addedChanged || changed;
590
+ topologyChanged = addedChanged || topologyChanged;
591
+ }
592
+ if (topologyChanged) {
294
593
  this.revision += 1;
594
+ this.payloadRevision += 1;
295
595
  this.patches += 1;
296
596
  this.cachedPlan = undefined;
297
597
  }
@@ -324,6 +624,7 @@ export class BatchTopology {
324
624
  });
325
625
  this.cachedPlan = Object.freeze({
326
626
  revision: this.revision,
627
+ payloadRevision: this.payloadRevision,
327
628
  batches: Object.freeze(batches),
328
629
  candidateCount: batches.reduce((total, batch) => total + batch.candidates.length, 0),
329
630
  visibleCapacity: visibleBase,
@@ -341,24 +642,34 @@ export class BatchTopology {
341
642
  rebuilds: this.rebuilds,
342
643
  patches: this.patches,
343
644
  ineligible: this.ineligiblePrimitives.size,
645
+ payloadPatches: this.payloadPatches,
646
+ membershipChecks: this.membershipChecks,
647
+ membershipAllocations: this.membershipAllocations,
648
+ candidateAdds: this.candidateAdds,
649
+ candidateRemoves: this.candidateRemoves,
344
650
  };
345
651
  }
346
652
 
347
653
  private add(slot: RenderSceneSlot): boolean {
348
- const keys = eligibleKeys(slot);
349
- if (keys.length === 0) {
654
+ const draws = eligibleDraws(slot);
655
+ if (draws.length === 0) {
350
656
  this.ineligiblePrimitives.add(slot.slot);
351
657
  return false;
352
658
  }
353
659
  this.ineligiblePrimitives.delete(slot.slot);
354
- const memberships: Array<{ batchText: string; candidateKey: string }> = [];
355
- const instanceCount = slot.snapshot.instances?.instanceCount ?? 1;
356
- const hasLod = (slot.snapshot.lods?.length ?? 0) > 0;
357
- for (let drawItemIndex = 0; drawItemIndex < keys.length; drawItemIndex += 1) {
358
- const key = keys[drawItemIndex];
359
- if (key === undefined) continue;
660
+ const memberships = membershipProjection(slot, draws);
661
+ const instanceCount = memberships.instanceCount;
662
+ const hasLod = memberships.hasLod;
663
+ this.membershipAllocations += memberships.draws.length;
664
+ for (const draw of draws) {
360
665
  for (let instanceOrdinal = 0; instanceOrdinal < instanceCount; instanceOrdinal += 1) {
361
- const text = candidateBatchText(key, slot.slot, drawItemIndex, instanceOrdinal, hasLod);
666
+ const text = candidateBatchText(
667
+ draw.key,
668
+ slot.slot,
669
+ draw.sourceDrawIndex,
670
+ instanceOrdinal,
671
+ hasLod,
672
+ );
362
673
  let batch = this.batches.get(text);
363
674
  if (batch === undefined) {
364
675
  const reused = this.freeBatchIds.pop();
@@ -366,39 +677,12 @@ export class BatchTopology {
366
677
  const generation =
367
678
  reused === undefined ? 0 : (this.generationByBatchId[batchId] ?? -1) + 1;
368
679
  this.generationByBatchId[batchId] = generation;
369
- batch = { batchId, generation, key, candidates: new Map() };
680
+ batch = { batchId, generation, key: draw.key, candidates: new Map() };
370
681
  this.batches.set(text, batch);
371
682
  }
372
- const candidateKey = `${slot.slot}:${drawItemIndex}:${instanceOrdinal}`;
373
- const draw = slot.snapshot.gpuDrivenDraws?.[drawItemIndex];
374
- const prepared = draw?.prepared;
375
- batch.candidates.set(candidateKey, {
376
- primitiveIndex: slot.slot,
377
- generation: slot.generation,
378
- drawItemIndex,
379
- instanceOrdinal,
380
- ...(draw?.projectedHeight === undefined ? {} : { projectedHeight: draw.projectedHeight }),
381
- ...(slot.snapshot.lods === undefined
382
- ? {}
383
- : {
384
- lodCoverages: [1, ...slot.snapshot.lods.map((lod) => lod.screenCoverage)],
385
- ...(slot.snapshot.gpuDrivenDraws?.[drawItemIndex]?.lodRanges === undefined
386
- ? {}
387
- : {
388
- lodRanges: slot.snapshot.gpuDrivenDraws[drawItemIndex]
389
- ?.lodRanges as readonly {
390
- readonly first: number;
391
- readonly count: number;
392
- readonly baseVertex: number;
393
- }[],
394
- }),
395
- ...(slot.snapshot.lodHysteresis === undefined
396
- ? {}
397
- : { lodHysteresis: slot.snapshot.lodHysteresis }),
398
- }),
399
- ...(prepared === undefined ? {} : { prepared }),
400
- });
401
- memberships.push({ batchText: text, candidateKey });
683
+ const candidateKey = `${slot.slot}:${draw.sourceDrawIndex}:${instanceOrdinal}`;
684
+ batch.candidates.set(candidateKey, this.candidateFromEligible(slot, instanceOrdinal, draw));
685
+ this.candidateAdds += 1;
402
686
  }
403
687
  }
404
688
  this.membershipByPrimitive.set(slot.slot, memberships);
@@ -410,15 +694,53 @@ export class BatchTopology {
410
694
  const memberships = this.membershipByPrimitive.get(primitiveIndex);
411
695
  this.membershipByPrimitive.delete(primitiveIndex);
412
696
  if (memberships === undefined) return false;
413
- for (const membership of memberships) {
414
- const batch = this.batches.get(membership.batchText);
415
- if (batch === undefined) continue;
416
- batch.candidates.delete(membership.candidateKey);
417
- if (batch.candidates.size === 0) {
418
- this.batches.delete(membership.batchText);
419
- this.freeBatchIds.push(batch.batchId);
697
+ for (const membership of memberships.draws) {
698
+ const batchTexts = new Set<string>();
699
+ for (
700
+ let instanceOrdinal = 0;
701
+ instanceOrdinal < memberships.instanceCount;
702
+ instanceOrdinal += 1
703
+ ) {
704
+ const batchText = candidateBatchText(
705
+ membership.key,
706
+ primitiveIndex,
707
+ membership.sourceDrawIndex,
708
+ instanceOrdinal,
709
+ memberships.hasLod,
710
+ );
711
+ batchTexts.add(batchText);
712
+ const batch = this.batches.get(batchText);
713
+ if (batch === undefined) continue;
714
+ const candidateKey = `${membership.candidateKeyPrefix}${instanceOrdinal}`;
715
+ if (!batch.candidates.delete(candidateKey)) continue;
716
+ this.candidateRemoves += 1;
717
+ }
718
+ for (const batchText of batchTexts) {
719
+ const batch = this.batches.get(batchText);
720
+ if (batch !== undefined && batch.candidates.size === 0) {
721
+ this.batches.delete(batchText);
722
+ this.freeBatchIds.push(batch.batchId);
723
+ }
420
724
  }
421
725
  }
422
726
  return true;
423
727
  }
728
+
729
+ private candidateFromEligible(
730
+ slot: RenderSceneSlot,
731
+ instanceOrdinal: number,
732
+ draw: EligibleGpuDrivenDraw,
733
+ ): GpuDrivenCandidate {
734
+ return {
735
+ primitiveIndex: slot.slot,
736
+ generation: slot.generation,
737
+ drawItemIndex: draw.sourceDrawIndex,
738
+ instanceOrdinal,
739
+ ...(draw.projectedHeight === undefined ? {} : { projectedHeight: draw.projectedHeight }),
740
+ ...(draw.lodCoverages === undefined ? {} : { lodCoverages: draw.lodCoverages }),
741
+ ...(draw.lodRanges === undefined ? {} : { lodRanges: draw.lodRanges }),
742
+ ...(draw.lodHysteresis === undefined ? {} : { lodHysteresis: draw.lodHysteresis }),
743
+ ...(draw.prepared === undefined ? {} : { prepared: draw.prepared }),
744
+ };
745
+ }
424
746
  }