@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
@@ -5,15 +5,19 @@ import type {
5
5
  Buffer,
6
6
  ComputePipeline,
7
7
  PipelineLayout,
8
+ RhiBindingResource,
8
9
  RhiComputePassEncoder,
9
10
  RhiComputePipelineOps,
10
11
  RhiDevice,
12
+ Sampler,
11
13
  ShaderModule,
14
+ TextureView,
12
15
  } from '@forgeax/engine-rhi';
13
16
  import { type BindGroupLayoutDescriptor, err, ok, type Result } from '@forgeax/engine-types';
14
17
  import type { DeviceScope, LifecycleResourceSpec } from '../device/device-scope';
15
18
  import { type RenderError, RenderFeaturePreparationFailedError } from '../errors/render';
16
19
  import type { PipelineBuilderShaderModuleFactory } from '../pipeline-builder';
20
+ import type { RenderFeatureTargetHandle } from './targets';
17
21
  import type { RenderFeatureShaderModuleMode } from './types';
18
22
 
19
23
  declare const RenderFeatureGpuProgramBrand: unique symbol;
@@ -29,6 +33,25 @@ export interface RenderFeatureGpuBufferRef {
29
33
  readonly generation: number;
30
34
  }
31
35
 
36
+ declare const RenderFeatureGpuTextureViewBrand: unique symbol;
37
+ export interface RenderFeatureGpuTextureViewRef {
38
+ readonly [RenderFeatureGpuTextureViewBrand]: void;
39
+ readonly name: string;
40
+ readonly generation: number;
41
+ }
42
+
43
+ declare const RenderFeatureGpuSamplerBrand: unique symbol;
44
+ export interface RenderFeatureGpuSamplerRef {
45
+ readonly [RenderFeatureGpuSamplerBrand]: void;
46
+ readonly name: string;
47
+ readonly generation: number;
48
+ }
49
+
50
+ export type RenderFeatureGpuPreparedResourceRef =
51
+ | { readonly kind: 'buffer'; readonly reference: RenderFeatureGpuBufferRef }
52
+ | { readonly kind: 'texture-view'; readonly reference: RenderFeatureGpuTextureViewRef }
53
+ | { readonly kind: 'sampler'; readonly reference: RenderFeatureGpuSamplerRef };
54
+
32
55
  declare const RenderFeatureGpuBindingsBrand: unique symbol;
33
56
  export interface RenderFeatureGpuBindingsRef {
34
57
  readonly [RenderFeatureGpuBindingsBrand]: void;
@@ -57,10 +80,10 @@ export interface RenderFeatureGpuBufferDescriptor {
57
80
 
58
81
  export interface RenderFeatureGpuBindingsDescriptor {
59
82
  readonly program: RenderFeatureGpuProgramRef;
60
- readonly entries: readonly {
61
- readonly binding: number;
62
- readonly buffer: RenderFeatureGpuBufferRef;
63
- }[];
83
+ readonly entries: readonly (
84
+ | { readonly binding: number; readonly buffer: RenderFeatureGpuBufferRef }
85
+ | { readonly binding: number; readonly resource: RenderFeatureGpuPreparedResourceRef }
86
+ )[];
64
87
  }
65
88
 
66
89
  export interface RenderFeatureGpuPrepare {
@@ -73,6 +96,18 @@ export interface RenderFeatureGpuPrepare {
73
96
  name: string,
74
97
  descriptor: RenderFeatureGpuBufferDescriptor,
75
98
  ): Result<RenderFeatureGpuBufferRef, RenderError>;
99
+ /** Adopt a provider-owned resident buffer without taking destruction ownership. */
100
+ prepareBufferResource(
101
+ name: string,
102
+ resource: Buffer,
103
+ descriptor: Pick<RenderFeatureGpuBufferDescriptor, 'size' | 'usage'>,
104
+ ): Result<RenderFeatureGpuBufferRef, RenderError>;
105
+ prepareTextureView(
106
+ name: string,
107
+ resource: TextureView,
108
+ logicalTarget?: RenderFeatureTargetHandle,
109
+ ): Result<RenderFeatureGpuTextureViewRef, RenderError>;
110
+ prepareSampler(name: string, resource: Sampler): Result<RenderFeatureGpuSamplerRef, RenderError>;
76
111
  prepareBindings(
77
112
  name: string,
78
113
  descriptor: RenderFeatureGpuBindingsDescriptor,
@@ -106,6 +141,7 @@ export interface RenderFeatureGpuComputePassDescriptor {
106
141
  }
107
142
 
108
143
  export interface RenderFeatureResolvedGpuComputePass {
144
+ readonly sampledTargets?: readonly RenderFeatureTargetHandle[];
109
145
  readonly buffers: readonly {
110
146
  readonly name: string;
111
147
  readonly buffer: Buffer;
@@ -117,11 +153,17 @@ export interface RenderFeatureResolvedGpuComputePass {
117
153
  | {
118
154
  readonly pipeline: ComputePipeline;
119
155
  readonly bindGroup: BindGroup;
156
+ readonly resolveBindGroup?: (
157
+ resolve: (target: RenderFeatureTargetHandle) => TextureView,
158
+ ) => BindGroup;
120
159
  readonly workgroups: readonly [number, number, number];
121
160
  }
122
161
  | {
123
162
  readonly pipeline: ComputePipeline;
124
163
  readonly bindGroup: BindGroup;
164
+ readonly resolveBindGroup?: (
165
+ resolve: (target: RenderFeatureTargetHandle) => TextureView,
166
+ ) => BindGroup;
125
167
  readonly indirectBuffer: Buffer;
126
168
  readonly indirectOffset: number;
127
169
  }
@@ -137,10 +179,19 @@ export interface RenderFeatureResolvedGpuBuffer {
137
179
  export function encodeRenderFeatureGpuComputePass(
138
180
  pass: RhiComputePassEncoder,
139
181
  work: RenderFeatureResolvedGpuComputePass,
182
+ resolveTarget?: (target: RenderFeatureTargetHandle) => TextureView,
140
183
  ): void {
141
184
  for (const dispatch of work.dispatches) {
142
185
  pass.setPipeline(dispatch.pipeline);
143
- pass.setBindGroup(0, dispatch.bindGroup);
186
+ if (dispatch.resolveBindGroup !== undefined && resolveTarget === undefined) {
187
+ throw new Error('Graph texture resolver required for sampled compute work');
188
+ }
189
+ pass.setBindGroup(
190
+ 0,
191
+ dispatch.resolveBindGroup !== undefined && resolveTarget !== undefined
192
+ ? dispatch.resolveBindGroup(resolveTarget)
193
+ : dispatch.bindGroup,
194
+ );
144
195
  if ('workgroups' in dispatch) pass.dispatchWorkgroups(...dispatch.workgroups);
145
196
  else pass.dispatchWorkgroupsIndirect(dispatch.indirectBuffer, dispatch.indirectOffset);
146
197
  }
@@ -163,7 +214,8 @@ export interface PreparedGraphicsResourceLease {
163
214
 
164
215
  interface ProgramItem {
165
216
  readonly name: string;
166
- readonly signature: string;
217
+ /** Detached descriptor used for exact warm-frame equality checks. */
218
+ readonly descriptor: RenderFeatureGpuProgramDescriptor;
167
219
  readonly reference: RenderFeatureGpuProgramRef;
168
220
  readonly module: ShaderModule;
169
221
  readonly pipelines: ReadonlyMap<string, ComputePipeline>;
@@ -178,6 +230,28 @@ interface BufferItem {
178
230
  readonly buffer: Buffer;
179
231
  readonly size: number;
180
232
  readonly physicalUsage: number;
233
+ readonly owned: boolean;
234
+ }
235
+
236
+ interface TextureViewItem {
237
+ readonly logicalTarget?: RenderFeatureTargetHandle;
238
+ readonly name: string;
239
+ readonly resource: TextureView;
240
+ readonly reference: RenderFeatureGpuTextureViewRef;
241
+ }
242
+
243
+ interface SamplerItem {
244
+ readonly name: string;
245
+ readonly resource: Sampler;
246
+ readonly reference: RenderFeatureGpuSamplerRef;
247
+ }
248
+
249
+ interface BindingResourceItem {
250
+ readonly binding: number;
251
+ readonly resource: RhiBindingResource;
252
+ readonly buffer?: BufferItem;
253
+ readonly textureView?: TextureViewItem;
254
+ readonly sampler?: SamplerItem;
181
255
  }
182
256
 
183
257
  interface BindingsItem {
@@ -185,10 +259,22 @@ interface BindingsItem {
185
259
  readonly signature: string;
186
260
  readonly reference: RenderFeatureGpuBindingsRef;
187
261
  readonly program: ProgramItem;
262
+ readonly entries: readonly BindingResourceItem[];
188
263
  readonly buffers: readonly { readonly binding: number; readonly item: BufferItem }[];
189
264
  readonly bindGroup: BindGroup;
190
265
  }
191
266
 
267
+ /**
268
+ * VFX fixed-tick queues can briefly shrink when the host consumes one tick
269
+ * earlier than the next one is published. Keep those named allocations warm
270
+ * for a bounded window so a q-slot oscillation does not create/destroy a GPU
271
+ * buffer on every frame. The parking policy is deliberately scoped to the
272
+ * native VFX feature; generic feature resources retain the old immediate
273
+ * retirement contract until they publish the same lifetime proof.
274
+ */
275
+ const VFX_PARKED_RESOURCE_FRAME_LIMIT = 8;
276
+ const VFX_PARKED_RESOURCE_LIMIT = 256;
277
+
192
278
  const BUFFER_USAGE = {
193
279
  storage: 0x0080,
194
280
  uniform: 0x0040,
@@ -241,13 +327,85 @@ function stable(value: unknown): string {
241
327
  if (Array.isArray(value)) return `[${value.map(stable).join(',')}]`;
242
328
  if (value !== null && typeof value === 'object') {
243
329
  return `{${Object.entries(value as Record<string, unknown>)
244
- .sort(([left], [right]) => left.localeCompare(right))
330
+ // Descriptor keys are canonicalized by code unit, not locale. These
331
+ // descriptors are generated every frame; avoiding locale collation
332
+ // keeps the stable spelling deterministic and removes a per-call
333
+ // ICU-backed comparator from the prepared-resource hot path.
334
+ .sort(([left], [right]) => (left < right ? -1 : left > right ? 1 : 0))
245
335
  .map(([key, child]) => `${key}:${stable(child)}`)
246
336
  .join(',')}}`;
247
337
  }
248
338
  return JSON.stringify(value);
249
339
  }
250
340
 
341
+ /**
342
+ * Compare prepared-program declarations without reserializing the WGSL and
343
+ * bind-group layout on every warm frame. This is intentionally a structural
344
+ * comparison: callers may reuse and mutate their declaration objects, so an
345
+ * object-identity fast path would make a stale pipeline appear valid.
346
+ */
347
+ function equalDescriptorValue(left: unknown, right: unknown): boolean {
348
+ if (Object.is(left, right)) return true;
349
+ if (typeof left !== typeof right || left === null || right === null) return false;
350
+ if (ArrayBuffer.isView(left) || ArrayBuffer.isView(right)) {
351
+ if (!ArrayBuffer.isView(left) || !ArrayBuffer.isView(right)) return false;
352
+ if (left.byteLength !== right.byteLength) return false;
353
+ const leftBytes = new Uint8Array(left.buffer, left.byteOffset, left.byteLength);
354
+ const rightBytes = new Uint8Array(right.buffer, right.byteOffset, right.byteLength);
355
+ for (let index = 0; index < leftBytes.length; index += 1) {
356
+ if (leftBytes[index] !== rightBytes[index]) return false;
357
+ }
358
+ return true;
359
+ }
360
+ if (Array.isArray(left) || Array.isArray(right)) {
361
+ if (!Array.isArray(left) || !Array.isArray(right) || left.length !== right.length) return false;
362
+ for (let index = 0; index < left.length; index += 1) {
363
+ if (!equalDescriptorValue(left[index], right[index])) return false;
364
+ }
365
+ return true;
366
+ }
367
+ if (typeof left === 'object' && typeof right === 'object') {
368
+ const leftRecord = left as Record<string, unknown>;
369
+ const rightRecord = right as Record<string, unknown>;
370
+ const leftKeys = Object.keys(leftRecord);
371
+ const rightKeys = Object.keys(rightRecord);
372
+ if (leftKeys.length !== rightKeys.length) return false;
373
+ for (const key of leftKeys) {
374
+ if (!Object.hasOwn(rightRecord, key)) return false;
375
+ if (!equalDescriptorValue(leftRecord[key], rightRecord[key])) return false;
376
+ }
377
+ return true;
378
+ }
379
+ return false;
380
+ }
381
+
382
+ function cloneDescriptorValue(value: unknown): unknown {
383
+ if (Array.isArray(value)) {
384
+ return Object.freeze(value.map((child) => cloneDescriptorValue(child)));
385
+ }
386
+ if (value !== null && typeof value === 'object' && !ArrayBuffer.isView(value)) {
387
+ return Object.freeze(
388
+ Object.fromEntries(
389
+ Object.entries(value as Record<string, unknown>).map(([key, child]) => [
390
+ key,
391
+ cloneDescriptorValue(child),
392
+ ]),
393
+ ),
394
+ );
395
+ }
396
+ if (ArrayBuffer.isView(value)) {
397
+ const source = new Uint8Array(value.buffer, value.byteOffset, value.byteLength);
398
+ return new Uint8Array(source);
399
+ }
400
+ return value;
401
+ }
402
+
403
+ function cloneProgramDescriptor(
404
+ descriptor: RenderFeatureGpuProgramDescriptor,
405
+ ): RenderFeatureGpuProgramDescriptor {
406
+ return cloneDescriptorValue(descriptor) as RenderFeatureGpuProgramDescriptor;
407
+ }
408
+
251
409
  function rhiReason(error: {
252
410
  readonly code: string;
253
411
  readonly hint: string;
@@ -264,14 +422,54 @@ function createRenderFeatureGpuWorkSession(input: {
264
422
  readonly featureIdentity: string;
265
423
  }): RenderFeatureGpuPrepareSession {
266
424
  const programs = new Map<string, ProgramItem>();
425
+ const parkedPrograms = new Map<string, { readonly item: ProgramItem; readonly frame: number }>();
267
426
  const programRefs = new Map<object, ProgramItem>();
268
427
  const buffers = new Map<string, BufferItem>();
428
+ const parkedBuffers = new Map<string, { readonly item: BufferItem; readonly frame: number }>();
269
429
  const bufferRefs = new Map<object, BufferItem>();
430
+ const textureViews = new Map<string, TextureViewItem>();
431
+ const textureViewRefs = new Map<object, TextureViewItem>();
432
+ const samplers = new Map<string, SamplerItem>();
433
+ const samplerRefs = new Map<object, SamplerItem>();
270
434
  const bindings = new Map<string, BindingsItem>();
435
+ const parkedBindings = new Map<string, { readonly item: BindingsItem; readonly frame: number }>();
271
436
  const bindingRefs = new Map<object, BindingsItem>();
272
437
  const touchedPrograms = new Set<ProgramItem>();
273
438
  const touchedBuffers = new Set<BufferItem>();
439
+ const touchedTextureViews = new Set<TextureViewItem>();
440
+ const touchedSamplers = new Set<SamplerItem>();
274
441
  const touchedBindings = new Set<BindingsItem>();
442
+ const parksUntouched = input.featureIdentity === 'forgeax.vfx-render.gpu-particles';
443
+ let frameSerial = 0;
444
+
445
+ // A parked bind group must not retain a borrowed view, sampler, or buffer
446
+ // whose producer may replace the underlying handle while this feature is
447
+ // dormant. Owned buffers are generation-local and can safely be revived.
448
+ const canParkBinding = (item: BindingsItem): boolean =>
449
+ item.entries.every(
450
+ (entry) =>
451
+ entry.textureView === undefined &&
452
+ entry.sampler === undefined &&
453
+ (entry.buffer === undefined || entry.buffer.owned),
454
+ );
455
+
456
+ const activateProgram = (item: ProgramItem): void => {
457
+ const parked = parkedPrograms.get(item.name);
458
+ if (parked?.item === item) parkedPrograms.delete(item.name);
459
+ programs.set(item.name, item);
460
+ };
461
+ const activateBuffer = (item: BufferItem): void => {
462
+ const parked = parkedBuffers.get(item.name);
463
+ if (parked?.item === item) parkedBuffers.delete(item.name);
464
+ buffers.set(item.name, item);
465
+ };
466
+ const activateBindings = (item: BindingsItem): void => {
467
+ const parked = parkedBindings.get(item.name);
468
+ if (parked?.item === item) parkedBindings.delete(item.name);
469
+ bindings.set(item.name, item);
470
+ activateProgram(item.program);
471
+ for (const entry of item.buffers) activateBuffer(entry.item);
472
+ };
275
473
 
276
474
  const touchProgram = (item: ProgramItem): void => {
277
475
  touchedPrograms.add(item);
@@ -279,18 +477,28 @@ function createRenderFeatureGpuWorkSession(input: {
279
477
  const touchBuffer = (item: BufferItem): void => {
280
478
  touchedBuffers.add(item);
281
479
  };
480
+ const touchTextureView = (item: TextureViewItem): void => {
481
+ touchedTextureViews.add(item);
482
+ };
483
+ const touchSampler = (item: SamplerItem): void => {
484
+ touchedSamplers.add(item);
485
+ };
282
486
  const touchBindings = (item: BindingsItem): void => {
283
487
  touchedBindings.add(item);
284
488
  touchProgram(item.program);
285
- for (const entry of item.buffers) touchBuffer(entry.item);
489
+ for (const entry of item.entries) {
490
+ if (entry.buffer !== undefined) touchBuffer(entry.buffer);
491
+ if (entry.textureView !== undefined) touchTextureView(entry.textureView);
492
+ if (entry.sampler !== undefined) touchSampler(entry.sampler);
493
+ }
286
494
  };
287
495
 
288
496
  const prepareProgram: RenderFeatureGpuPrepare['prepareProgram'] = (name, descriptor) => {
289
- const signature = stable(descriptor);
290
- const prior = programs.get(name);
497
+ const prior = programs.get(name) ?? parkedPrograms.get(name)?.item;
291
498
  if (prior !== undefined) {
499
+ activateProgram(prior);
292
500
  touchProgram(prior);
293
- return prior.signature === signature
501
+ return equalDescriptorValue(prior.descriptor, descriptor)
294
502
  ? ok(prior.reference)
295
503
  : err(
296
504
  failure(
@@ -417,7 +625,7 @@ function createRenderFeatureGpuWorkSession(input: {
417
625
  const reference = Object.freeze({ generation: input.generation }) as RenderFeatureGpuProgramRef;
418
626
  const item = {
419
627
  name,
420
- signature,
628
+ descriptor: cloneProgramDescriptor(descriptor),
421
629
  reference,
422
630
  module: module.value,
423
631
  pipelines: pipelineMap,
@@ -453,7 +661,7 @@ function createRenderFeatureGpuWorkSession(input: {
453
661
  );
454
662
  }
455
663
  const signature = stable({ size: descriptor.size, usage: [...descriptor.usage].sort() });
456
- let item = buffers.get(name);
664
+ let item = buffers.get(name) ?? parkedBuffers.get(name)?.item;
457
665
  if (item !== undefined && item.signature !== signature) {
458
666
  return err(
459
667
  failure(
@@ -494,10 +702,12 @@ function createRenderFeatureGpuWorkSession(input: {
494
702
  buffer: created.value,
495
703
  size: alignedSize(descriptor.size),
496
704
  physicalUsage: usage,
705
+ owned: true,
497
706
  };
498
707
  buffers.set(name, item);
499
708
  bufferRefs.set(reference, item);
500
709
  }
710
+ activateBuffer(item);
501
711
  touchBuffer(item);
502
712
  if (descriptor.data !== undefined) {
503
713
  if (descriptor.data.byteLength > descriptor.size) {
@@ -527,43 +737,267 @@ function createRenderFeatureGpuWorkSession(input: {
527
737
  return ok(item.reference);
528
738
  };
529
739
 
530
- const prepareBindings: RenderFeatureGpuPrepare['prepareBindings'] = (name, descriptor) => {
531
- const program = programRefs.get(descriptor.program as object);
532
- if (program === undefined || descriptor.program.generation !== input.generation) {
740
+ const prepareBufferResource: RenderFeatureGpuPrepare['prepareBufferResource'] = (
741
+ name,
742
+ resource,
743
+ descriptor,
744
+ ) => {
745
+ if (
746
+ name.length === 0 ||
747
+ !Number.isInteger(descriptor.size) ||
748
+ descriptor.size <= 0 ||
749
+ descriptor.usage.length === 0
750
+ ) {
533
751
  return err(
534
752
  failure(
535
753
  input.featureIdentity,
536
- 'prepare-gpu-bindings',
537
- 'bindings',
754
+ 'prepare-gpu-buffer-resource',
755
+ 'uniform-data',
538
756
  name,
539
- 'program-unavailable',
757
+ 'descriptor-invalid',
540
758
  ),
541
759
  );
542
760
  }
543
- const entryItems = descriptor.entries.map((entry) => ({
544
- binding: entry.binding,
545
- item: bufferRefs.get(entry.buffer as object),
546
- }));
547
- if (entryItems.some((entry) => entry.item === undefined)) {
761
+ const size = alignedSize(descriptor.size);
762
+ const usage = descriptor.usage.reduce((bits, key) => bits | BUFFER_USAGE[key], COPY_DST);
763
+ const prior = buffers.get(name);
764
+ if (prior !== undefined) {
765
+ touchBuffer(prior);
766
+ return prior.buffer === resource &&
767
+ prior.size === size &&
768
+ prior.physicalUsage === usage &&
769
+ !prior.owned
770
+ ? ok(prior.reference)
771
+ : err(
772
+ failure(
773
+ input.featureIdentity,
774
+ 'prepare-gpu-buffer-resource',
775
+ 'uniform-data',
776
+ name,
777
+ 'signature-mismatch',
778
+ ),
779
+ );
780
+ }
781
+ const reference = Object.freeze({
782
+ name,
783
+ generation: input.generation,
784
+ }) as RenderFeatureGpuBufferRef;
785
+ const item: BufferItem = {
786
+ name,
787
+ signature: stable({ external: true, size, usage: [...descriptor.usage].sort() }),
788
+ reference,
789
+ buffer: resource,
790
+ size,
791
+ physicalUsage: usage,
792
+ owned: false,
793
+ };
794
+ buffers.set(name, item);
795
+ bufferRefs.set(reference, item);
796
+ touchBuffer(item);
797
+ return ok(reference);
798
+ };
799
+
800
+ const prepareTextureView: RenderFeatureGpuPrepare['prepareTextureView'] = (
801
+ name,
802
+ resource,
803
+ logicalTarget,
804
+ ) => {
805
+ if (name.length === 0) {
806
+ return err(
807
+ failure(
808
+ input.featureIdentity,
809
+ 'prepare-gpu-texture-view',
810
+ 'texture-view',
811
+ name,
812
+ 'descriptor-invalid',
813
+ ),
814
+ );
815
+ }
816
+ const prior = textureViews.get(name);
817
+ if (prior !== undefined) {
818
+ touchTextureView(prior);
819
+ return prior.resource === resource && stable(prior.logicalTarget) === stable(logicalTarget)
820
+ ? ok(prior.reference)
821
+ : err(
822
+ failure(
823
+ input.featureIdentity,
824
+ 'prepare-gpu-texture-view',
825
+ 'texture-view',
826
+ name,
827
+ 'signature-mismatch',
828
+ ),
829
+ );
830
+ }
831
+ const reference = Object.freeze({
832
+ name,
833
+ generation: input.generation,
834
+ }) as RenderFeatureGpuTextureViewRef;
835
+ const item = {
836
+ name,
837
+ resource,
838
+ reference,
839
+ ...(logicalTarget === undefined ? {} : { logicalTarget }),
840
+ };
841
+ textureViews.set(name, item);
842
+ textureViewRefs.set(reference, item);
843
+ touchTextureView(item);
844
+ return ok(reference);
845
+ };
846
+
847
+ const prepareSampler: RenderFeatureGpuPrepare['prepareSampler'] = (name, resource) => {
848
+ if (name.length === 0) {
849
+ return err(
850
+ failure(
851
+ input.featureIdentity,
852
+ 'prepare-gpu-sampler',
853
+ 'sampler',
854
+ name,
855
+ 'descriptor-invalid',
856
+ ),
857
+ );
858
+ }
859
+ const prior = samplers.get(name);
860
+ if (prior !== undefined) {
861
+ touchSampler(prior);
862
+ return prior.resource === resource
863
+ ? ok(prior.reference)
864
+ : err(
865
+ failure(
866
+ input.featureIdentity,
867
+ 'prepare-gpu-sampler',
868
+ 'sampler',
869
+ name,
870
+ 'signature-mismatch',
871
+ ),
872
+ );
873
+ }
874
+ const reference = Object.freeze({
875
+ name,
876
+ generation: input.generation,
877
+ }) as RenderFeatureGpuSamplerRef;
878
+ const item = { name, resource, reference };
879
+ samplers.set(name, item);
880
+ samplerRefs.set(reference, item);
881
+ touchSampler(item);
882
+ return ok(reference);
883
+ };
884
+
885
+ const prepareBindings: RenderFeatureGpuPrepare['prepareBindings'] = (name, descriptor) => {
886
+ const program = programRefs.get(descriptor.program as object);
887
+ if (program === undefined || descriptor.program.generation !== input.generation) {
548
888
  return err(
549
889
  failure(
550
890
  input.featureIdentity,
551
891
  'prepare-gpu-bindings',
552
892
  'bindings',
553
893
  name,
554
- 'buffer-unavailable',
894
+ 'program-unavailable',
555
895
  ),
556
896
  );
557
897
  }
558
- const availableEntries = entryItems.flatMap((entry) =>
559
- entry.item === undefined ? [] : [{ binding: entry.binding, item: entry.item }],
560
- );
898
+ const entryItems: BindingResourceItem[] = [];
899
+ for (const entry of descriptor.entries) {
900
+ if ('buffer' in entry) {
901
+ const item = bufferRefs.get(entry.buffer as object);
902
+ if (item === undefined || entry.buffer.generation !== input.generation) {
903
+ return err(
904
+ failure(
905
+ input.featureIdentity,
906
+ 'prepare-gpu-bindings',
907
+ 'bindings',
908
+ name,
909
+ 'buffer-unavailable',
910
+ ),
911
+ );
912
+ }
913
+ entryItems.push({
914
+ binding: entry.binding,
915
+ resource: { kind: 'buffer', value: { buffer: item.buffer } },
916
+ buffer: item,
917
+ });
918
+ continue;
919
+ }
920
+ const prepared = entry.resource;
921
+ if (prepared.reference.generation !== input.generation) {
922
+ return err(
923
+ failure(
924
+ input.featureIdentity,
925
+ 'prepare-gpu-bindings',
926
+ 'bindings',
927
+ name,
928
+ 'resource-generation-mismatch',
929
+ ),
930
+ );
931
+ }
932
+ if (prepared.kind === 'buffer') {
933
+ const item = bufferRefs.get(prepared.reference as object);
934
+ if (item === undefined) {
935
+ return err(
936
+ failure(
937
+ input.featureIdentity,
938
+ 'prepare-gpu-bindings',
939
+ 'bindings',
940
+ name,
941
+ 'buffer-unavailable',
942
+ ),
943
+ );
944
+ }
945
+ entryItems.push({
946
+ binding: entry.binding,
947
+ resource: { kind: 'buffer', value: { buffer: item.buffer } },
948
+ buffer: item,
949
+ });
950
+ continue;
951
+ }
952
+ if (prepared.kind === 'texture-view') {
953
+ const item = textureViewRefs.get(prepared.reference as object);
954
+ if (item === undefined) {
955
+ return err(
956
+ failure(
957
+ input.featureIdentity,
958
+ 'prepare-gpu-bindings',
959
+ 'bindings',
960
+ name,
961
+ 'texture-view-unavailable',
962
+ ),
963
+ );
964
+ }
965
+ entryItems.push({
966
+ binding: entry.binding,
967
+ resource: { kind: 'textureView', value: item.resource },
968
+ textureView: item,
969
+ });
970
+ continue;
971
+ }
972
+ const item = samplerRefs.get(prepared.reference as object);
973
+ if (item === undefined) {
974
+ return err(
975
+ failure(
976
+ input.featureIdentity,
977
+ 'prepare-gpu-bindings',
978
+ 'bindings',
979
+ name,
980
+ 'sampler-unavailable',
981
+ ),
982
+ );
983
+ }
984
+ entryItems.push({
985
+ binding: entry.binding,
986
+ resource: { kind: 'sampler', value: item.resource },
987
+ sampler: item,
988
+ });
989
+ }
561
990
  const signature = stable({
562
991
  program: program.name,
563
- entries: availableEntries.map((entry) => [entry.binding, entry.item.name]),
992
+ entries: entryItems.map((entry) => [
993
+ entry.binding,
994
+ entry.buffer?.name ?? entry.textureView?.name ?? entry.sampler?.name,
995
+ entry.resource.kind,
996
+ ]),
564
997
  });
565
- const prior = bindings.get(name);
998
+ const prior = bindings.get(name) ?? parkedBindings.get(name)?.item;
566
999
  if (prior !== undefined) {
1000
+ activateBindings(prior);
567
1001
  touchBindings(prior);
568
1002
  return prior.signature === signature
569
1003
  ? ok(prior.reference)
@@ -595,12 +1029,9 @@ function createRenderFeatureGpuWorkSession(input: {
595
1029
  const created = input.device.createBindGroup({
596
1030
  label: name,
597
1031
  layout,
598
- entries: availableEntries.map((entry) => ({
1032
+ entries: entryItems.map((entry) => ({
599
1033
  binding: entry.binding,
600
- resource: {
601
- kind: 'buffer' as const,
602
- value: { buffer: entry.item.buffer },
603
- },
1034
+ resource: entry.resource,
604
1035
  })),
605
1036
  });
606
1037
  if (!created.ok) {
@@ -622,7 +1053,10 @@ function createRenderFeatureGpuWorkSession(input: {
622
1053
  signature,
623
1054
  reference,
624
1055
  program,
625
- buffers: availableEntries,
1056
+ entries: entryItems,
1057
+ buffers: entryItems.flatMap((entry) =>
1058
+ entry.buffer === undefined ? [] : [{ binding: entry.binding, item: entry.buffer }],
1059
+ ),
626
1060
  bindGroup: created.value,
627
1061
  };
628
1062
  bindings.set(name, item);
@@ -633,8 +1067,11 @@ function createRenderFeatureGpuWorkSession(input: {
633
1067
 
634
1068
  return {
635
1069
  beginFrame: () => {
1070
+ frameSerial += 1;
636
1071
  touchedPrograms.clear();
637
1072
  touchedBuffers.clear();
1073
+ touchedTextureViews.clear();
1074
+ touchedSamplers.clear();
638
1075
  touchedBindings.clear();
639
1076
  },
640
1077
  retainBindings: (references) => {
@@ -651,12 +1088,16 @@ function createRenderFeatureGpuWorkSession(input: {
651
1088
  ),
652
1089
  );
653
1090
  }
1091
+ activateBindings(item);
654
1092
  touchBindings(item);
655
1093
  }
656
1094
  return ok(undefined);
657
1095
  },
658
1096
  prepareProgram,
659
1097
  prepareBuffer,
1098
+ prepareBufferResource,
1099
+ prepareTextureView,
1100
+ prepareSampler,
660
1101
  prepareBindings,
661
1102
  resolveComputePass: (featureIdentity, descriptor) => {
662
1103
  const program = programRefs.get(descriptor.program as object);
@@ -743,10 +1184,39 @@ function createRenderFeatureGpuWorkSession(input: {
743
1184
  const pipeline = program.pipelines.get(dispatch.entryPoint);
744
1185
  const dispatchBinding = dispatchBindings[index];
745
1186
  if (pipeline === undefined || dispatchBinding === undefined) continue;
1187
+ const lateBindings = dispatchBinding.entries.some(
1188
+ (entry) => entry.textureView?.logicalTarget !== undefined,
1189
+ )
1190
+ ? {
1191
+ resolveBindGroup: (resolve: (target: RenderFeatureTargetHandle) => TextureView) => {
1192
+ const layout =
1193
+ program.bindGroupLayout ??
1194
+ (pipeline as ComputePipeline & RhiComputePipelineOps).getBindGroupLayout(0);
1195
+ const created = input.device.createBindGroup({
1196
+ label: dispatchBinding.name,
1197
+ layout,
1198
+ entries: dispatchBinding.entries.map((entry) => ({
1199
+ binding: entry.binding,
1200
+ resource:
1201
+ entry.textureView?.logicalTarget === undefined
1202
+ ? entry.resource
1203
+ : {
1204
+ kind: 'textureView' as const,
1205
+ value: resolve(entry.textureView.logicalTarget),
1206
+ },
1207
+ })),
1208
+ });
1209
+ if (!created.ok) throw created.error;
1210
+ return created.value;
1211
+ },
1212
+ }
1213
+ : {};
1214
+
746
1215
  if (dispatch.workgroups !== undefined) {
747
1216
  resolvedDispatches.push({
748
1217
  pipeline,
749
1218
  bindGroup: dispatchBinding.bindGroup,
1219
+ ...lateBindings,
750
1220
  workgroups: [
751
1221
  dispatch.workgroups[0],
752
1222
  dispatch.workgroups[1] ?? 1,
@@ -760,6 +1230,7 @@ function createRenderFeatureGpuWorkSession(input: {
760
1230
  resolvedDispatches.push({
761
1231
  pipeline,
762
1232
  bindGroup: dispatchBinding.bindGroup,
1233
+ ...lateBindings,
763
1234
  indirectBuffer: indirectItem.buffer,
764
1235
  indirectOffset: dispatch.indirect.offset,
765
1236
  });
@@ -819,6 +1290,18 @@ function createRenderFeatureGpuWorkSession(input: {
819
1290
  resolvedBuffers.set(item, accesses);
820
1291
  }
821
1292
  return ok({
1293
+ sampledTargets: [
1294
+ ...new Set(
1295
+ dispatchBindings.flatMap(
1296
+ (item) =>
1297
+ item?.entries.flatMap((entry) =>
1298
+ entry.textureView?.logicalTarget === undefined
1299
+ ? []
1300
+ : [entry.textureView.logicalTarget],
1301
+ ) ?? [],
1302
+ ),
1303
+ ),
1304
+ ],
822
1305
  buffers: [...resolvedBuffers].flatMap(([item, accesses]) =>
823
1306
  [...accesses].map((access) => ({
824
1307
  name: item.name,
@@ -833,28 +1316,111 @@ function createRenderFeatureGpuWorkSession(input: {
833
1316
  },
834
1317
  resolveBuffer: (reference) => {
835
1318
  const item = bufferRefs.get(reference as object);
836
- if (item !== undefined) touchBuffer(item);
1319
+ if (item !== undefined) {
1320
+ activateBuffer(item);
1321
+ touchBuffer(item);
1322
+ }
837
1323
  return item === undefined
838
1324
  ? undefined
839
1325
  : { buffer: item.buffer, size: item.size, physicalUsage: item.physicalUsage };
840
1326
  },
841
1327
  retireUntouched: () => {
1328
+ const retired: BufferItem[] = [];
1329
+ const park = <T extends { readonly name: string }>(
1330
+ active: Map<string, T>,
1331
+ parked: Map<string, { readonly item: T; readonly frame: number }>,
1332
+ touched: Set<T>,
1333
+ retire: (item: T) => void,
1334
+ ): void => {
1335
+ for (const [name, item] of active) {
1336
+ if (touched.has(item)) continue;
1337
+ active.delete(name);
1338
+ if (parksUntouched) parked.set(name, { item, frame: frameSerial });
1339
+ else retire(item);
1340
+ }
1341
+ };
842
1342
  for (const [name, item] of bindings) {
843
1343
  if (touchedBindings.has(item)) continue;
844
1344
  bindings.delete(name);
845
- bindingRefs.delete(item.reference as object);
1345
+ if (parksUntouched && canParkBinding(item)) {
1346
+ parkedBindings.set(name, { item, frame: frameSerial });
1347
+ } else {
1348
+ bindingRefs.delete(item.reference as object);
1349
+ }
846
1350
  }
847
- for (const [name, item] of programs) {
848
- if (touchedPrograms.has(item)) continue;
849
- programs.delete(name);
1351
+ park(programs, parkedPrograms, touchedPrograms, (item) => {
850
1352
  programRefs.delete(item.reference as object);
851
- }
852
- const retired: BufferItem[] = [];
853
- for (const [name, item] of buffers) {
854
- if (touchedBuffers.has(item)) continue;
855
- buffers.delete(name);
856
- bufferRefs.delete(item.reference as object);
857
- retired.push(item);
1353
+ });
1354
+ if (parksUntouched) {
1355
+ for (const [name, item] of buffers) {
1356
+ if (touchedBuffers.has(item)) continue;
1357
+ buffers.delete(name);
1358
+ if (item.owned) parkedBuffers.set(name, { item, frame: frameSerial });
1359
+ else bufferRefs.delete(item.reference as object);
1360
+ }
1361
+ for (const [name, item] of textureViews) {
1362
+ if (touchedTextureViews.has(item)) continue;
1363
+ textureViews.delete(name);
1364
+ textureViewRefs.delete(item.reference as object);
1365
+ }
1366
+ for (const [name, item] of samplers) {
1367
+ if (touchedSamplers.has(item)) continue;
1368
+ samplers.delete(name);
1369
+ samplerRefs.delete(item.reference as object);
1370
+ }
1371
+ const evictBefore = frameSerial - VFX_PARKED_RESOURCE_FRAME_LIMIT;
1372
+ const evictBuffers = (): void => {
1373
+ for (const [name, parked] of parkedBuffers) {
1374
+ if (parked.frame > evictBefore && parkedBuffers.size <= VFX_PARKED_RESOURCE_LIMIT)
1375
+ break;
1376
+ parkedBuffers.delete(name);
1377
+ bufferRefs.delete(parked.item.reference as object);
1378
+ for (const [bindingName, binding] of parkedBindings) {
1379
+ if (binding.item.buffers.some((entry) => entry.item === parked.item)) {
1380
+ parkedBindings.delete(bindingName);
1381
+ bindingRefs.delete(binding.item.reference as object);
1382
+ }
1383
+ }
1384
+ retired.push(parked.item);
1385
+ }
1386
+ };
1387
+ evictBuffers();
1388
+ for (const [name, parked] of parkedPrograms) {
1389
+ if (parked.frame > evictBefore && parkedPrograms.size <= VFX_PARKED_RESOURCE_LIMIT) {
1390
+ break;
1391
+ }
1392
+ parkedPrograms.delete(name);
1393
+ programRefs.delete(parked.item.reference as object);
1394
+ for (const [bindingName, binding] of parkedBindings) {
1395
+ if (binding.item.program !== parked.item) continue;
1396
+ parkedBindings.delete(bindingName);
1397
+ bindingRefs.delete(binding.item.reference as object);
1398
+ }
1399
+ }
1400
+ for (const [name, parked] of parkedBindings) {
1401
+ if (parked.frame > evictBefore && parkedBindings.size <= VFX_PARKED_RESOURCE_LIMIT) {
1402
+ break;
1403
+ }
1404
+ parkedBindings.delete(name);
1405
+ bindingRefs.delete(parked.item.reference as object);
1406
+ }
1407
+ } else {
1408
+ for (const [name, item] of buffers) {
1409
+ if (touchedBuffers.has(item)) continue;
1410
+ buffers.delete(name);
1411
+ bufferRefs.delete(item.reference as object);
1412
+ retired.push(item);
1413
+ }
1414
+ for (const [name, item] of textureViews) {
1415
+ if (touchedTextureViews.has(item)) continue;
1416
+ textureViews.delete(name);
1417
+ textureViewRefs.delete(item.reference as object);
1418
+ }
1419
+ for (const [name, item] of samplers) {
1420
+ if (touchedSamplers.has(item)) continue;
1421
+ samplers.delete(name);
1422
+ samplerRefs.delete(item.reference as object);
1423
+ }
858
1424
  }
859
1425
  if (retired.length === 0) return [];
860
1426
  let released = false;
@@ -865,6 +1431,7 @@ function createRenderFeatureGpuWorkSession(input: {
865
1431
  released = true;
866
1432
  let first: RenderError | undefined;
867
1433
  for (const item of retired) {
1434
+ if (!item.owned) continue;
868
1435
  const destroyed = input.device.destroyBuffer(item.buffer);
869
1436
  if (!destroyed.ok && first === undefined) {
870
1437
  first = failure(
@@ -883,7 +1450,12 @@ function createRenderFeatureGpuWorkSession(input: {
883
1450
  },
884
1451
  dispose: () => {
885
1452
  let first: RenderError | undefined;
886
- for (const item of buffers.values()) {
1453
+ const allBuffers = new Set<BufferItem>([
1454
+ ...buffers.values(),
1455
+ ...Array.from(parkedBuffers.values(), ({ item }) => item),
1456
+ ]);
1457
+ for (const item of allBuffers) {
1458
+ if (!item.owned) continue;
887
1459
  const destroyed = input.device.destroyBuffer(item.buffer);
888
1460
  if (!destroyed.ok && first === undefined) {
889
1461
  first = failure(
@@ -896,8 +1468,18 @@ function createRenderFeatureGpuWorkSession(input: {
896
1468
  }
897
1469
  }
898
1470
  programs.clear();
1471
+ parkedPrograms.clear();
899
1472
  buffers.clear();
1473
+ parkedBuffers.clear();
900
1474
  bindings.clear();
1475
+ parkedBindings.clear();
1476
+ textureViews.clear();
1477
+ textureViewRefs.clear();
1478
+ samplers.clear();
1479
+ samplerRefs.clear();
1480
+ bufferRefs.clear();
1481
+ programRefs.clear();
1482
+ bindingRefs.clear();
901
1483
  return first === undefined ? ok(undefined) : err(first);
902
1484
  },
903
1485
  };