@forgeax/engine-render 0.1.32 → 0.1.34

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (624) hide show
  1. package/README.md +1374 -142
  2. package/dist/assembly/analytic-fog-registration.d.ts +3 -0
  3. package/dist/assembly/analytic-fog-registration.d.ts.map +1 -0
  4. package/dist/assembly/backend-contract.d.ts +2 -0
  5. package/dist/assembly/backend-contract.d.ts.map +1 -1
  6. package/dist/assembly/barrel-distortion-inspection.d.ts +3 -0
  7. package/dist/assembly/barrel-distortion-inspection.d.ts.map +1 -0
  8. package/dist/assembly/canvas-draw-guard.d.ts +3 -0
  9. package/dist/assembly/canvas-draw-guard.d.ts.map +1 -0
  10. package/dist/assembly/cloud-shadow-entry.d.ts +4 -0
  11. package/dist/assembly/cloud-shadow-entry.d.ts.map +1 -0
  12. package/dist/assembly/dynamic-geometry-host.d.ts +4 -1
  13. package/dist/assembly/dynamic-geometry-host.d.ts.map +1 -1
  14. package/dist/assembly/dynamic-geometry-runtime.d.ts +1 -1
  15. package/dist/assembly/dynamic-geometry-runtime.d.ts.map +1 -1
  16. package/dist/assembly/factory.d.ts +1 -1
  17. package/dist/assembly/factory.d.ts.map +1 -1
  18. package/dist/assembly/fxaa-registration.d.ts +4 -0
  19. package/dist/assembly/fxaa-registration.d.ts.map +1 -0
  20. package/dist/assembly/host-contract.d.ts +3 -3
  21. package/dist/assembly/host-contract.d.ts.map +1 -1
  22. package/dist/assembly/lod-observation.d.ts +4 -0
  23. package/dist/assembly/lod-observation.d.ts.map +1 -0
  24. package/dist/assembly/material/assembly.d.ts.map +1 -1
  25. package/dist/assembly/material/pipeline-helpers.d.ts +5 -0
  26. package/dist/assembly/material/pipeline-helpers.d.ts.map +1 -1
  27. package/dist/assembly/material-shader-policy.d.ts +16 -2
  28. package/dist/assembly/material-shader-policy.d.ts.map +1 -1
  29. package/dist/assembly/material-shader-prewarm.d.ts.map +1 -1
  30. package/dist/assembly/motion-blur-registration.d.ts +3 -0
  31. package/dist/assembly/motion-blur-registration.d.ts.map +1 -0
  32. package/dist/assembly/recovery/device-loss-fanout.d.ts.map +1 -1
  33. package/dist/assembly/recovery/renderer-recover.d.ts +2 -0
  34. package/dist/assembly/recovery/renderer-recover.d.ts.map +1 -1
  35. package/dist/assembly/render-feature-post-processes.d.ts +6 -0
  36. package/dist/assembly/render-feature-post-processes.d.ts.map +1 -0
  37. package/dist/assembly/renderer-facade.d.ts.map +1 -1
  38. package/dist/assembly/renderer-feature-inspection.d.ts +1 -1
  39. package/dist/assembly/renderer-feature-inspection.d.ts.map +1 -1
  40. package/dist/assembly/renderer-frame-transaction.d.ts +12 -0
  41. package/dist/assembly/renderer-frame-transaction.d.ts.map +1 -1
  42. package/dist/assembly/renderer-inspection.d.ts +11 -0
  43. package/dist/assembly/renderer-inspection.d.ts.map +1 -1
  44. package/dist/assembly/temporal-post-process-prewarm.d.ts +13 -0
  45. package/dist/assembly/temporal-post-process-prewarm.d.ts.map +1 -0
  46. package/dist/assembly/webgpu-pbr-ready.d.ts +1 -0
  47. package/dist/assembly/webgpu-pbr-ready.d.ts.map +1 -1
  48. package/dist/assembly/webgpu-ready-contract.d.ts +4 -3
  49. package/dist/assembly/webgpu-ready-contract.d.ts.map +1 -1
  50. package/dist/assembly/webgpu-ready-per-pass.d.ts +39 -0
  51. package/dist/assembly/webgpu-ready-per-pass.d.ts.map +1 -0
  52. package/dist/assembly/webgpu-ready.d.ts +2 -2
  53. package/dist/assembly/webgpu-ready.d.ts.map +1 -1
  54. package/dist/assembly/webgpu-renderer-bootstrap.d.ts.map +1 -1
  55. package/dist/assembly/webgpu-renderer-observation-owner.d.ts +35 -0
  56. package/dist/assembly/webgpu-renderer-observation-owner.d.ts.map +1 -0
  57. package/dist/assembly/webgpu-renderer.d.ts +1 -1
  58. package/dist/assembly/webgpu-renderer.d.ts.map +1 -1
  59. package/dist/authoring.mjs +1 -1
  60. package/dist/barrel-distortion.d.ts +47 -0
  61. package/dist/barrel-distortion.d.ts.map +1 -0
  62. package/dist/bloom-admission.d.ts +13 -0
  63. package/dist/bloom-admission.d.ts.map +1 -0
  64. package/dist/{chunk-PA5DRJNI.mjs → chunk-ELJFJ2BU.mjs} +2 -2
  65. package/dist/chunk-ELJFJ2BU.mjs.map +1 -0
  66. package/dist/{chunk-JCIRYQ4V.mjs → chunk-HEB564WF.mjs} +10 -4
  67. package/dist/chunk-HEB564WF.mjs.map +1 -0
  68. package/dist/{chunk-JRIPCMYC.mjs → chunk-MKDIT2EM.mjs} +1584 -375
  69. package/dist/chunk-MKDIT2EM.mjs.map +1 -0
  70. package/dist/{chunk-S665NJNF.mjs → chunk-OCDLEI6I.mjs} +3 -3
  71. package/dist/{chunk-S665NJNF.mjs.map → chunk-OCDLEI6I.mjs.map} +1 -1
  72. package/dist/chunk-ODZWR6JQ.mjs +4927 -0
  73. package/dist/chunk-ODZWR6JQ.mjs.map +1 -0
  74. package/dist/{chunk-DRR7D3KX.mjs → chunk-SHFUFJ5N.mjs} +192 -18
  75. package/dist/chunk-SHFUFJ5N.mjs.map +1 -0
  76. package/dist/{chunk-4NNZQCL3.mjs → chunk-UI5SFODX.mjs} +223 -277
  77. package/dist/chunk-UI5SFODX.mjs.map +1 -0
  78. package/dist/{chunk-GWCEMDVR.mjs → chunk-UINHLCZA.mjs} +787 -80
  79. package/dist/chunk-UINHLCZA.mjs.map +1 -0
  80. package/dist/{chunk-6TFBXLRJ.mjs → chunk-WEX45HKH.mjs} +222 -337
  81. package/dist/chunk-WEX45HKH.mjs.map +1 -0
  82. package/dist/cloud/density.d.ts +55 -0
  83. package/dist/cloud/density.d.ts.map +1 -0
  84. package/dist/cloud/extract.d.ts +25 -0
  85. package/dist/cloud/extract.d.ts.map +1 -0
  86. package/dist/cloud/feature.d.ts +57 -0
  87. package/dist/cloud/feature.d.ts.map +1 -0
  88. package/dist/cloud/frame-context.d.ts +8 -0
  89. package/dist/cloud/frame-context.d.ts.map +1 -0
  90. package/dist/cloud/inspection.d.ts +59 -0
  91. package/dist/cloud/inspection.d.ts.map +1 -0
  92. package/dist/cloud/optics.d.ts +56 -0
  93. package/dist/cloud/optics.d.ts.map +1 -0
  94. package/dist/cloud/parameters.d.ts +73 -0
  95. package/dist/cloud/parameters.d.ts.map +1 -0
  96. package/dist/cloud/resources.d.ts +60 -0
  97. package/dist/cloud/resources.d.ts.map +1 -0
  98. package/dist/cloud/shadow.d.ts +42 -0
  99. package/dist/cloud/shadow.d.ts.map +1 -0
  100. package/dist/cloud/temporal.d.ts +74 -0
  101. package/dist/cloud/temporal.d.ts.map +1 -0
  102. package/dist/components/atmosphere.d.ts +2 -0
  103. package/dist/components/atmosphere.d.ts.map +1 -1
  104. package/dist/components/barrel-distortion.d.ts +13 -0
  105. package/dist/components/barrel-distortion.d.ts.map +1 -0
  106. package/dist/components/camera.d.ts +20 -4
  107. package/dist/components/camera.d.ts.map +1 -1
  108. package/dist/components/cloud-layer.d.ts +29 -0
  109. package/dist/components/cloud-layer.d.ts.map +1 -0
  110. package/dist/components/index.d.ts +2 -0
  111. package/dist/components/index.d.ts.map +1 -1
  112. package/dist/components/instances.d.ts +20 -6
  113. package/dist/components/instances.d.ts.map +1 -1
  114. package/dist/components/mesh-filter.d.ts +6 -5
  115. package/dist/components/mesh-filter.d.ts.map +1 -1
  116. package/dist/components/motion-blur.d.ts +1 -0
  117. package/dist/components/motion-blur.d.ts.map +1 -1
  118. package/dist/construct-renderer.d.ts +1 -1
  119. package/dist/construct-renderer.d.ts.map +1 -1
  120. package/dist/construct-renderer.mjs +9751 -3528
  121. package/dist/construct-renderer.mjs.map +1 -1
  122. package/dist/device/gpu-residency.d.ts +6 -0
  123. package/dist/device/gpu-residency.d.ts.map +1 -1
  124. package/dist/dynamic-geometry.d.ts +5 -1
  125. package/dist/dynamic-geometry.d.ts.map +1 -1
  126. package/dist/environment/analytic-fog.d.ts +6 -0
  127. package/dist/environment/analytic-fog.d.ts.map +1 -0
  128. package/dist/errors/cloud.d.ts +59 -0
  129. package/dist/errors/cloud.d.ts.map +1 -0
  130. package/dist/errors/render.d.ts +23 -5
  131. package/dist/errors/render.d.ts.map +1 -1
  132. package/dist/examples/single-layer-medium-surface.d.ts +47 -0
  133. package/dist/examples/single-layer-medium-surface.d.ts.map +1 -0
  134. package/dist/extract/camera.d.ts.map +1 -1
  135. package/dist/extract/contracts.d.ts +12 -1
  136. package/dist/extract/contracts.d.ts.map +1 -1
  137. package/dist/extract/environment.d.ts +2 -0
  138. package/dist/extract/environment.d.ts.map +1 -1
  139. package/dist/features/barrel-distortion.d.ts +29 -0
  140. package/dist/features/barrel-distortion.d.ts.map +1 -0
  141. package/dist/features/error-reporting.d.ts +17 -0
  142. package/dist/features/error-reporting.d.ts.map +1 -0
  143. package/dist/features/host.d.ts +15 -0
  144. package/dist/features/host.d.ts.map +1 -1
  145. package/dist/features/motion-blur/motion-blur-feature.d.ts +20 -2
  146. package/dist/features/motion-blur/motion-blur-feature.d.ts.map +1 -1
  147. package/dist/features/motion-blur/motion-blur-params.d.ts +21 -0
  148. package/dist/features/motion-blur/motion-blur-params.d.ts.map +1 -1
  149. package/dist/features/motion-blur/motion-blur-runtime.d.ts +54 -0
  150. package/dist/features/motion-blur/motion-blur-runtime.d.ts.map +1 -0
  151. package/dist/features/plan.d.ts +15 -4
  152. package/dist/features/plan.d.ts.map +1 -1
  153. package/dist/features/prepared-gpu-work.d.ts +9 -5
  154. package/dist/features/prepared-gpu-work.d.ts.map +1 -1
  155. package/dist/features/render-graph-compute.d.ts.map +1 -1
  156. package/dist/features/render-graph-contribution.d.ts +5 -0
  157. package/dist/features/render-graph-contribution.d.ts.map +1 -1
  158. package/dist/features/render-graph-raster.d.ts +1 -0
  159. package/dist/features/render-graph-raster.d.ts.map +1 -1
  160. package/dist/features/targets.d.ts +2 -0
  161. package/dist/features/targets.d.ts.map +1 -1
  162. package/dist/features/types.d.ts +44 -0
  163. package/dist/features/types.d.ts.map +1 -1
  164. package/dist/fullscreen-post-process-pass.d.ts +15 -7
  165. package/dist/fullscreen-post-process-pass.d.ts.map +1 -1
  166. package/dist/gpu-dirty-ranges.d.ts +11 -0
  167. package/dist/gpu-dirty-ranges.d.ts.map +1 -0
  168. package/dist/gpu-driven/batch-topology.d.ts +17 -0
  169. package/dist/gpu-driven/batch-topology.d.ts.map +1 -1
  170. package/dist/gpu-driven/material-artifacts.d.ts +6 -0
  171. package/dist/gpu-driven/material-artifacts.d.ts.map +1 -1
  172. package/dist/gpu-driven/prepared-draw.d.ts +7 -0
  173. package/dist/gpu-driven/prepared-draw.d.ts.map +1 -1
  174. package/dist/gpu-driven/production-raster-material.d.ts +178 -0
  175. package/dist/gpu-driven/production-raster-material.d.ts.map +1 -0
  176. package/dist/gpu-driven/production-raster.d.ts +50 -4
  177. package/dist/gpu-driven/production-raster.d.ts.map +1 -1
  178. package/dist/gpu-driven/resource-allocation.d.ts +31 -0
  179. package/dist/gpu-driven/resource-allocation.d.ts.map +1 -0
  180. package/dist/gpu-driven/shadow-ownership.d.ts +14 -0
  181. package/dist/gpu-driven/shadow-ownership.d.ts.map +1 -0
  182. package/dist/gpu-driven/view-gpu.d.ts +35 -2
  183. package/dist/gpu-driven/view-gpu.d.ts.map +1 -1
  184. package/dist/gpu-scene.d.ts +11 -1
  185. package/dist/gpu-scene.d.ts.map +1 -1
  186. package/dist/hdrp-buffers.d.ts +2 -2
  187. package/dist/hdrp-buffers.d.ts.map +1 -1
  188. package/dist/ibl/skylight-bind-group.d.ts +10 -1
  189. package/dist/ibl/skylight-bind-group.d.ts.map +1 -1
  190. package/dist/index.d.ts +31 -8
  191. package/dist/index.d.ts.map +1 -1
  192. package/dist/index.mjs +258 -8
  193. package/dist/index.mjs.map +1 -1
  194. package/dist/inspection-types.d.ts +178 -3
  195. package/dist/inspection-types.d.ts.map +1 -1
  196. package/dist/instance-buffer-cache.d.ts +4 -4
  197. package/dist/instance-buffer-cache.d.ts.map +1 -1
  198. package/dist/instances.d.ts +49 -94
  199. package/dist/instances.d.ts.map +1 -1
  200. package/dist/internal.mjs +7 -7
  201. package/dist/pbr-pipeline.d.ts +19 -1
  202. package/dist/pbr-pipeline.d.ts.map +1 -1
  203. package/dist/pipeline/single-layer-medium-passes.d.ts +73 -0
  204. package/dist/pipeline/single-layer-medium-passes.d.ts.map +1 -0
  205. package/dist/pipeline/standard-forward-lane.d.ts.map +1 -1
  206. package/dist/pipeline/standard-output/graph.d.ts.map +1 -1
  207. package/dist/pipeline/standard-output/types.d.ts +4 -2
  208. package/dist/pipeline/standard-output/types.d.ts.map +1 -1
  209. package/dist/pipeline/standard-pipeline.d.ts.map +1 -1
  210. package/dist/pipeline/standard-post.d.ts +28 -19
  211. package/dist/pipeline/standard-post.d.ts.map +1 -1
  212. package/dist/pipeline-builder.d.ts +1 -1
  213. package/dist/pipeline-builder.d.ts.map +1 -1
  214. package/dist/pipeline-spec.d.ts +2 -2
  215. package/dist/plugin.d.ts.map +1 -1
  216. package/dist/prepare/prepared-graphics-resolver.d.ts +2 -0
  217. package/dist/prepare/prepared-graphics-resolver.d.ts.map +1 -1
  218. package/dist/record/barrel-distortion-frame.d.ts +15 -0
  219. package/dist/record/barrel-distortion-frame.d.ts.map +1 -0
  220. package/dist/record/dynamic-geometry-consumption.d.ts +10 -2
  221. package/dist/record/dynamic-geometry-consumption.d.ts.map +1 -1
  222. package/dist/record/fold-buckets.d.ts +95 -0
  223. package/dist/record/fold-buckets.d.ts.map +1 -0
  224. package/dist/record/fold-instance-buffer.d.ts +6 -0
  225. package/dist/record/fold-instance-buffer.d.ts.map +1 -0
  226. package/dist/record/frame-lighting.d.ts +1 -0
  227. package/dist/record/frame-lighting.d.ts.map +1 -1
  228. package/dist/record/frame-snapshot.d.ts +40 -3
  229. package/dist/record/frame-snapshot.d.ts.map +1 -1
  230. package/dist/record/frame-targets.d.ts.map +1 -1
  231. package/dist/record/frame.d.ts +14 -62
  232. package/dist/record/frame.d.ts.map +1 -1
  233. package/dist/record/gpu-draw-receipts.d.ts +11 -0
  234. package/dist/record/gpu-draw-receipts.d.ts.map +1 -0
  235. package/dist/record/gpu-timing.d.ts +8 -0
  236. package/dist/record/gpu-timing.d.ts.map +1 -1
  237. package/dist/record/main-pass-geometry.d.ts +21 -5
  238. package/dist/record/main-pass-geometry.d.ts.map +1 -1
  239. package/dist/record/main-pass-material.d.ts +7 -1
  240. package/dist/record/main-pass-material.d.ts.map +1 -1
  241. package/dist/record/main-pass-sprite-draws.d.ts.map +1 -1
  242. package/dist/record/main-pass.d.ts +13 -2
  243. package/dist/record/main-pass.d.ts.map +1 -1
  244. package/dist/record/mesh-ssbo.d.ts +6 -5
  245. package/dist/record/mesh-ssbo.d.ts.map +1 -1
  246. package/dist/record/motion-blur-receipt.d.ts +11 -0
  247. package/dist/record/motion-blur-receipt.d.ts.map +1 -0
  248. package/dist/record/probe-blend-buffer.d.ts +16 -0
  249. package/dist/record/probe-blend-buffer.d.ts.map +1 -0
  250. package/dist/record/recovery-pipeline.d.ts.map +1 -1
  251. package/dist/record/render-context.d.ts +34 -31
  252. package/dist/record/render-context.d.ts.map +1 -1
  253. package/dist/record/shadow-pass.d.ts +2 -0
  254. package/dist/record/shadow-pass.d.ts.map +1 -1
  255. package/dist/record/skybox-post-pass.d.ts +6 -4
  256. package/dist/record/skybox-post-pass.d.ts.map +1 -1
  257. package/dist/record/typed-frame-graph.d.ts +22 -2
  258. package/dist/record/typed-frame-graph.d.ts.map +1 -1
  259. package/dist/record/view-ubo.d.ts +11 -3
  260. package/dist/record/view-ubo.d.ts.map +1 -1
  261. package/dist/record/volume-params.d.ts +9 -0
  262. package/dist/record/volume-params.d.ts.map +1 -0
  263. package/dist/recovery/render-system-candidate.d.ts +10 -0
  264. package/dist/recovery/render-system-candidate.d.ts.map +1 -1
  265. package/dist/reflection/record-owner.d.ts.map +1 -1
  266. package/dist/render-contract.d.ts +66 -8
  267. package/dist/render-contract.d.ts.map +1 -1
  268. package/dist/render-graph-primitives.d.ts.map +1 -1
  269. package/dist/render-pipeline.d.ts +106 -3
  270. package/dist/render-pipeline.d.ts.map +1 -1
  271. package/dist/render-system-extract-tail.d.ts +3 -2
  272. package/dist/render-system-extract-tail.d.ts.map +1 -1
  273. package/dist/render-system-extract.d.ts +24 -10
  274. package/dist/render-system-extract.d.ts.map +1 -1
  275. package/dist/render-system-presentation.d.ts +23 -0
  276. package/dist/render-system-presentation.d.ts.map +1 -0
  277. package/dist/render-system-producer-roots.d.ts +10 -0
  278. package/dist/render-system-producer-roots.d.ts.map +1 -0
  279. package/dist/render-system-residency.d.ts +12 -0
  280. package/dist/render-system-residency.d.ts.map +1 -0
  281. package/dist/render-system.d.ts +26 -15
  282. package/dist/render-system.d.ts.map +1 -1
  283. package/dist/scene/probe-blend.d.ts +27 -0
  284. package/dist/scene/probe-blend.d.ts.map +1 -1
  285. package/dist/scene/render-scene.d.ts +14 -5
  286. package/dist/scene/render-scene.d.ts.map +1 -1
  287. package/dist/ssao-buffers.d.ts +9 -0
  288. package/dist/ssao-buffers.d.ts.map +1 -1
  289. package/dist/surface/dynamic-input.d.ts +133 -0
  290. package/dist/surface/dynamic-input.d.ts.map +1 -0
  291. package/dist/surface/gpu-driven.d.ts +41 -0
  292. package/dist/surface/gpu-driven.d.ts.map +1 -0
  293. package/dist/surface/submission-observation.d.ts +136 -0
  294. package/dist/surface/submission-observation.d.ts.map +1 -0
  295. package/dist/systems/skin-palette-allocator.d.ts.map +1 -1
  296. package/dist/temporal/frame-coordinator.d.ts.map +1 -1
  297. package/dist/temporal/frame.d.ts +7 -0
  298. package/dist/temporal/frame.d.ts.map +1 -1
  299. package/dist/temporal/gpu.d.ts +13 -1
  300. package/dist/temporal/gpu.d.ts.map +1 -1
  301. package/dist/temporal/index.mjs +5 -5
  302. package/dist/temporal/inspection.d.ts.map +1 -1
  303. package/dist/temporal/standard-scene-data.d.ts.map +1 -1
  304. package/dist/temporal/target-coverage-attachment.d.ts.map +1 -1
  305. package/dist/temporal/view.d.ts +6 -1
  306. package/dist/temporal/view.d.ts.map +1 -1
  307. package/dist/transmission/single-layer-medium.d.ts +89 -0
  308. package/dist/transmission/single-layer-medium.d.ts.map +1 -0
  309. package/dist/typed-render-graph-primitives.d.ts +24 -9
  310. package/dist/typed-render-graph-primitives.d.ts.map +1 -1
  311. package/dist/volume/component.d.ts +9 -5
  312. package/dist/volume/component.d.ts.map +1 -1
  313. package/dist/volume/extract.d.ts +1 -1
  314. package/dist/volume/extract.d.ts.map +1 -1
  315. package/dist/volume/inspection.d.ts +2 -0
  316. package/dist/volume/inspection.d.ts.map +1 -1
  317. package/dist/volume/passes.d.ts +4 -1
  318. package/dist/volume/passes.d.ts.map +1 -1
  319. package/dist/volume/resources.d.ts.map +1 -1
  320. package/dist/volume/temporal.d.ts +3 -1
  321. package/dist/volume/temporal.d.ts.map +1 -1
  322. package/package.json +22 -21
  323. package/src/__tests__/analytic-fog-graph.unit.test.ts +199 -0
  324. package/src/__tests__/analytic-fog-optics.unit.test.ts +38 -0
  325. package/src/__tests__/atmosphere-daylight.dawn.test.ts +72 -0
  326. package/src/__tests__/barrel-distortion-lkg.integration.test.ts +353 -0
  327. package/src/__tests__/barrel-distortion.dawn.test.ts +41 -0
  328. package/src/__tests__/barrel-distortion.unit.test.ts +364 -0
  329. package/src/__tests__/bloom-exact-zero.unit.test.ts +112 -18
  330. package/src/__tests__/bloom-lifecycle.integration.test.ts +17 -4
  331. package/src/__tests__/construct-renderer-identity.unit.test.ts +49 -0
  332. package/src/__tests__/detached-recovery-graph.unit.test.ts +277 -0
  333. package/src/__tests__/device-loss-fanout.unit.test.ts +36 -1
  334. package/src/__tests__/docs-gate-green.unit.test.ts +112 -1
  335. package/src/__tests__/dynamic-resolution-plugin.integration.test.ts +20 -0
  336. package/src/__tests__/environment-fog-lanes.integration.test.ts +14 -0
  337. package/src/__tests__/environment-selection.unit.test.ts +12 -0
  338. package/src/__tests__/factory-contract.integration.test.ts +626 -113
  339. package/src/__tests__/feature-depth-input.dawn.test.ts +129 -2
  340. package/src/__tests__/frame-camera-selection.unit.test.ts +39 -1
  341. package/src/__tests__/frame-plan-contract.unit.test.ts +2 -0
  342. package/src/__tests__/fullscreen-feature-plan.unit.test.ts +14 -3
  343. package/src/__tests__/gpu-dirty-ranges.unit.test.ts +22 -0
  344. package/src/__tests__/gpu-driven-baseline.characterization.test.ts +16 -3
  345. package/src/__tests__/gpu-driven-batch-topology-pbr.unit.test.ts +12 -0
  346. package/src/__tests__/gpu-driven-indirect-raster-evidence.ts +2 -1
  347. package/src/__tests__/gpu-driven-material-artifacts.unit.test.ts +143 -0
  348. package/src/__tests__/gpu-driven-pbr.dawn.test.ts +2 -2
  349. package/src/__tests__/gpu-driven-production.integration.test.ts +482 -3
  350. package/src/__tests__/gpu-driven-shadow-views.dawn.test.ts +7 -6
  351. package/src/__tests__/gpu-driven-shadow-views.integration.test.ts +1 -1
  352. package/src/__tests__/gpu-driven-view-gpu-evidence.ts +103 -4
  353. package/src/__tests__/gpu-driven-view-graph.integration.test.ts +18 -2
  354. package/src/__tests__/gpu-driven-view.browser.test.ts +5 -8
  355. package/src/__tests__/gpu-driven-view.dawn.test.ts +6 -2
  356. package/src/__tests__/gpu-driven-view.unit.test.ts +1 -1
  357. package/src/__tests__/gpu-pass-timing-lifecycle.integration.test.ts +1 -0
  358. package/src/__tests__/gpu-pass-timing.browser.test.ts +6 -4
  359. package/src/__tests__/gpu-pass-timing.rhi-null.unit.test.ts +1 -0
  360. package/src/__tests__/gpu-resource-store-stride.unit.test.ts +12 -0
  361. package/src/__tests__/gpu-scene.unit.test.ts +210 -9
  362. package/src/__tests__/instance-allocation-failure.unit.test.ts +57 -0
  363. package/src/__tests__/instances-culling.integration.test.ts +10 -36
  364. package/src/__tests__/instances-store.unit.test.ts +105 -238
  365. package/src/__tests__/instances-world-ownership.integration.test.ts +62 -0
  366. package/src/__tests__/main-pass-material-medium-selection.unit.test.ts +146 -0
  367. package/src/__tests__/material-shader-prewarm.unit.test.ts +59 -0
  368. package/src/__tests__/material-snapshot-mutation.integration.test.ts +39 -1
  369. package/src/__tests__/mesh-submission-lifetime.unit.test.ts +31 -0
  370. package/src/__tests__/morph-culling-reentry.dawn.test.ts +5 -5
  371. package/src/__tests__/morph-visual-evidence.integration.test.ts +8 -7
  372. package/src/__tests__/motion-blur-compute.dawn.test.ts +589 -0
  373. package/src/__tests__/motion-blur.pixel.integration.test.ts +2 -2
  374. package/src/__tests__/nineslice-handle-surface.unit.test.ts +4 -4
  375. package/src/__tests__/pbr-view-layout.unit.test.ts +9 -0
  376. package/src/__tests__/physical-clearcoat.integration.test.ts +58 -0
  377. package/src/__tests__/prepared-gpu-driven-pbr.integration.test.ts +21 -0
  378. package/src/__tests__/prepared-graphics-capability.unit.test.ts +66 -2
  379. package/src/__tests__/prepared-graphics-lifecycle.unit.test.ts +86 -0
  380. package/src/__tests__/probe-bindings.unit.test.ts +582 -1
  381. package/src/__tests__/probe-scene-dirty.integration.test.ts +28 -1
  382. package/src/__tests__/public-surface.test-d.ts +8 -0
  383. package/src/__tests__/receipt-observation-retirement.unit.test.ts +65 -0
  384. package/src/__tests__/recovery-candidate-prepare.contract.test.ts +69 -0
  385. package/src/__tests__/render-error-code-owner.test-d.ts +9 -0
  386. package/src/__tests__/render-feature-diagnostics.unit.test.ts +15 -2
  387. package/src/__tests__/render-feature-error-reporting.unit.test.ts +44 -0
  388. package/src/__tests__/render-feature-prepared-diagnostics.unit.test.ts +10 -1
  389. package/src/__tests__/render-feature-retry.unit.test.ts +12 -1
  390. package/src/__tests__/render-feature-stage-fault-recovery.unit.test.ts +23 -0
  391. package/src/__tests__/render-scene-mixed-updates.integration.test.ts +145 -19
  392. package/src/__tests__/render-scene-projection.unit.test.ts +36 -11
  393. package/src/__tests__/render-scene-temporal-retry.unit.test.ts +37 -6
  394. package/src/__tests__/render-target-probe-soak.perf.test.ts +2 -2
  395. package/src/__tests__/render-temporal-environment-consumer.browser.test.ts +3 -3
  396. package/src/__tests__/render-temporal-environment-consumer.dawn.test.ts +5 -2
  397. package/src/__tests__/renderer-factory-material-contract.unit.test.ts +41 -7
  398. package/src/__tests__/renderer-frame-generation-fence.integration.test.ts +16 -0
  399. package/src/__tests__/renderer-frame-transaction.integration.test.ts +33 -11
  400. package/src/__tests__/resource-allocation.unit.test.ts +123 -0
  401. package/src/__tests__/shader-manifest-fixture.ts +4 -4
  402. package/src/__tests__/single-layer-medium-passes.unit.test.ts +275 -0
  403. package/src/__tests__/skin-motion-regression.unit.test.ts +70 -1
  404. package/src/__tests__/skin-palette-recycling.dawn.test.ts +97 -0
  405. package/src/__tests__/skinned-shadow-caster.test.ts +17 -0
  406. package/src/__tests__/ssr-carrier-public-contract.unit.test.ts +21 -0
  407. package/src/__tests__/ssr-gpu-dispatch.browser.test.ts +4 -4
  408. package/src/__tests__/ssr-gpu-dispatch.dawn.test.ts +2 -2
  409. package/src/__tests__/ssr-gpu-dispatch.ts +1 -1
  410. package/src/__tests__/ssr-receiver-coverage.dawn.test.ts +6 -2
  411. package/src/__tests__/standard-lighting-write.unit.test.ts +2 -1
  412. package/src/__tests__/standard-output-chain-contract.unit.test.ts +28 -0
  413. package/src/__tests__/standard-pbr-artifact-assembly.unit.test.ts +46 -1
  414. package/src/__tests__/standard-pipeline.dawn.test.ts +1 -1
  415. package/src/__tests__/standard-pipeline.integration.test.ts +200 -9
  416. package/src/__tests__/surface-dynamic-buffer-lifecycle.unit.test.ts +506 -0
  417. package/src/__tests__/surface-submission-observation.unit.test.ts +812 -0
  418. package/src/__tests__/temporal-history-lifecycle.unit.test.ts +32 -0
  419. package/src/__tests__/temporal-performance.integration.test.ts +3 -3
  420. package/src/__tests__/temporal-reset-matrix.unit.test.ts +10 -0
  421. package/src/__tests__/temporal-view.unit.test.ts +2 -1
  422. package/src/__tests__/typed-pipeline-topology.unit.test.ts +20 -4
  423. package/src/__tests__/visibility-instances.integration.test.ts +7 -19
  424. package/src/__tests__/visibility-producer-matrix.integration.test.ts +9 -20
  425. package/src/__tests__/volume-optics-oracle.unit.test.ts +7 -3
  426. package/src/__tests__/volumetric-fog-budget-recovery.integration.test.ts +189 -15
  427. package/src/__tests__/volumetric-fog-errors.unit.test.ts +4 -3
  428. package/src/__tests__/volumetric-fog-multiple.unit.test.ts +55 -0
  429. package/src/__tests__/volumetric-fog-spot-frame-optics.integration.test.ts +1 -1
  430. package/src/__tests__/volumetric-fog-stage-readback.dawn.test.ts +558 -68
  431. package/src/__tests__/volumetric-fog-temporal.unit.test.ts +27 -0
  432. package/src/__tests__/volumetric-fog-topology.unit.test.ts +23 -5
  433. package/src/assembly/analytic-fog-registration.ts +14 -0
  434. package/src/assembly/backend-contract.ts +30 -0
  435. package/src/assembly/barrel-distortion-inspection.ts +22 -0
  436. package/src/assembly/canvas-draw-guard.ts +11 -0
  437. package/src/assembly/cloud-shadow-entry.ts +22 -0
  438. package/src/assembly/dynamic-geometry-host.ts +65 -37
  439. package/src/assembly/dynamic-geometry-runtime.ts +7 -1
  440. package/src/assembly/factory.ts +2 -30
  441. package/src/assembly/fxaa-registration.ts +17 -0
  442. package/src/assembly/host-contract.ts +3 -3
  443. package/src/assembly/lod-observation.ts +12 -0
  444. package/src/assembly/material/assembly.ts +25 -13
  445. package/src/assembly/material/pipeline-helpers.ts +53 -12
  446. package/src/assembly/material-shader-policy.ts +55 -0
  447. package/src/assembly/material-shader-prewarm.ts +21 -10
  448. package/src/assembly/motion-blur-registration.ts +17 -0
  449. package/src/assembly/recovery/device-loss-fanout.ts +13 -0
  450. package/src/assembly/recovery/renderer-recover.ts +41 -18
  451. package/src/assembly/render-feature-post-processes.ts +54 -0
  452. package/src/assembly/renderer-facade.ts +6 -1
  453. package/src/assembly/renderer-feature-inspection.ts +8 -2
  454. package/src/assembly/renderer-frame-transaction.ts +23 -0
  455. package/src/assembly/renderer-inspection.ts +28 -0
  456. package/src/assembly/skin-palette-owner.ts +1 -1
  457. package/src/assembly/temporal-post-process-prewarm.ts +40 -0
  458. package/src/assembly/webgpu-pbr-ready.ts +9 -1
  459. package/src/assembly/webgpu-ready-contract.ts +8 -3
  460. package/src/assembly/webgpu-ready-per-pass.ts +104 -0
  461. package/src/assembly/webgpu-ready.ts +296 -306
  462. package/src/assembly/webgpu-renderer-bootstrap.ts +0 -12
  463. package/src/assembly/webgpu-renderer-observation-owner.ts +222 -0
  464. package/src/assembly/webgpu-renderer.ts +228 -281
  465. package/src/assembly/webgpu-vertex-layouts.ts +1 -1
  466. package/src/barrel-distortion.ts +247 -0
  467. package/src/bloom-admission.ts +21 -0
  468. package/src/cloud/__tests__/cloud-density-parity.dawn.test.ts +173 -0
  469. package/src/cloud/__tests__/cloud-layer-framebuffer-y.dawn.test.ts +265 -0
  470. package/src/cloud/__tests__/cloud-layer.browser.test.ts +432 -0
  471. package/src/cloud/__tests__/cloud-layer.unit.test.ts +634 -0
  472. package/src/cloud/density.ts +600 -0
  473. package/src/cloud/extract.ts +110 -0
  474. package/src/cloud/feature.ts +1810 -0
  475. package/src/cloud/frame-context.ts +42 -0
  476. package/src/cloud/inspection.ts +130 -0
  477. package/src/cloud/optics.ts +285 -0
  478. package/src/cloud/parameters.ts +255 -0
  479. package/src/cloud/resources.ts +122 -0
  480. package/src/cloud/shadow.ts +167 -0
  481. package/src/cloud/temporal.ts +226 -0
  482. package/src/components/__tests__/motion-blur.unit.test.ts +1 -0
  483. package/src/components/atmosphere.ts +4 -0
  484. package/src/components/barrel-distortion.ts +46 -0
  485. package/src/components/camera.ts +66 -10
  486. package/src/components/cloud-layer.ts +47 -0
  487. package/src/components/index.ts +2 -0
  488. package/src/components/instances.ts +18 -45
  489. package/src/components/mesh-filter.ts +11 -9
  490. package/src/components/motion-blur.ts +1 -0
  491. package/src/components/sprite-instances.ts +1 -1
  492. package/src/construct-renderer.ts +1 -1
  493. package/src/device/gpu-residency.ts +56 -12
  494. package/src/dynamic-geometry.ts +12 -1
  495. package/src/environment/analytic-fog.ts +44 -0
  496. package/src/environment/background.ts +2 -2
  497. package/src/errors/cloud.ts +103 -0
  498. package/src/errors/render.ts +58 -8
  499. package/src/examples/single-layer-medium-surface.ts +59 -0
  500. package/src/extract/camera.ts +35 -8
  501. package/src/extract/contracts.ts +12 -0
  502. package/src/extract/environment.ts +4 -0
  503. package/src/features/barrel-distortion.ts +172 -0
  504. package/src/features/error-reporting.ts +98 -0
  505. package/src/features/host.ts +138 -24
  506. package/src/features/motion-blur/__tests__/motion-blur-feature.unit.test.ts +111 -1
  507. package/src/features/motion-blur/__tests__/motion-blur-params.unit.test.ts +58 -3
  508. package/src/features/motion-blur/motion-blur-feature.ts +1519 -15
  509. package/src/features/motion-blur/motion-blur-params.ts +70 -2
  510. package/src/features/motion-blur/motion-blur-runtime.ts +176 -0
  511. package/src/features/plan.ts +33 -8
  512. package/src/features/prepared-gpu-work.ts +86 -35
  513. package/src/features/render-graph-compute.ts +13 -5
  514. package/src/features/render-graph-contribution.ts +11 -0
  515. package/src/features/render-graph-raster.ts +45 -3
  516. package/src/features/targets.ts +66 -0
  517. package/src/features/types.ts +47 -0
  518. package/src/fullscreen-post-process-pass.ts +41 -9
  519. package/src/gpu-dirty-ranges.ts +48 -0
  520. package/src/gpu-driven/batch-topology.ts +53 -0
  521. package/src/gpu-driven/material-artifacts.ts +35 -32
  522. package/src/gpu-driven/prepared-draw.ts +27 -14
  523. package/src/gpu-driven/production-raster-material.ts +1894 -0
  524. package/src/gpu-driven/production-raster.ts +904 -787
  525. package/src/gpu-driven/resource-allocation.ts +142 -0
  526. package/src/gpu-driven/shadow-ownership.ts +71 -0
  527. package/src/gpu-driven/view-gpu.ts +181 -10
  528. package/src/gpu-scene.ts +259 -101
  529. package/src/hdrp-buffers.ts +4 -3
  530. package/src/ibl/skylight-bind-group.ts +49 -7
  531. package/src/index.ts +228 -9
  532. package/src/inspection-types.ts +222 -2
  533. package/src/instance-buffer-cache.ts +4 -4
  534. package/src/instances.ts +151 -492
  535. package/src/pbr-pipeline.ts +219 -13
  536. package/src/pipeline/single-layer-medium-passes.ts +267 -0
  537. package/src/pipeline/standard-forward-lane.ts +313 -57
  538. package/src/pipeline/standard-output/graph.ts +8 -2
  539. package/src/pipeline/standard-output/types.ts +12 -1
  540. package/src/pipeline/standard-pipeline.ts +291 -18
  541. package/src/pipeline/standard-post.ts +397 -102
  542. package/src/pipeline-builder.ts +1 -1
  543. package/src/pipeline-spec.ts +5 -5
  544. package/src/plugin.ts +4 -0
  545. package/src/points-lines/__tests__/points-lines.bench.ts +17 -8
  546. package/src/points-lines/__tests__/view-ubo.unit.test.ts +2 -1
  547. package/src/prepare/prepared-graphics-resolver.ts +2 -0
  548. package/src/record/__tests__/main-pass-geometry.unit.test.ts +30 -0
  549. package/src/record/__tests__/sprite-material-abi.unit.test.ts +1 -1
  550. package/src/record/__tests__/temporal-payload.unit.test.ts +3 -2
  551. package/src/record/__tests__/transparent-group2-selection.unit.test.ts +11 -0
  552. package/src/record/__tests__/typed-frame-graph-plan.unit.test.ts +1 -0
  553. package/src/record/__tests__/view-ubo-layout.unit.test.ts +4 -3
  554. package/src/record/barrel-distortion-frame.ts +110 -0
  555. package/src/record/dynamic-geometry-consumption.ts +39 -9
  556. package/src/record/fold-buckets.ts +852 -0
  557. package/src/record/fold-instance-buffer.ts +51 -0
  558. package/src/record/frame-lighting.ts +36 -2
  559. package/src/record/frame-snapshot.ts +44 -4
  560. package/src/record/frame-targets.ts +10 -6
  561. package/src/record/frame.ts +373 -1099
  562. package/src/record/gpu-draw-receipts.ts +38 -0
  563. package/src/record/gpu-timing.ts +48 -5
  564. package/src/record/main-pass-geometry.ts +281 -83
  565. package/src/record/main-pass-material.ts +66 -4
  566. package/src/record/main-pass-sprite-draws.ts +13 -66
  567. package/src/record/main-pass.ts +156 -20
  568. package/src/record/mesh-ssbo.ts +43 -6
  569. package/src/record/motion-blur-receipt.ts +91 -0
  570. package/src/record/probe-blend-buffer.ts +180 -0
  571. package/src/record/recovery-pipeline.ts +35 -3
  572. package/src/record/render-context.ts +51 -31
  573. package/src/record/shadow-pass.ts +36 -2
  574. package/src/record/skybox-post-pass.ts +150 -200
  575. package/src/record/typed-frame-graph.ts +824 -44
  576. package/src/record/view-ubo.ts +26 -3
  577. package/src/record/volume-params.ts +225 -0
  578. package/src/recovery/render-system-candidate.ts +257 -52
  579. package/src/reflection/record-owner.ts +7 -3
  580. package/src/render-contract.ts +71 -8
  581. package/src/render-graph-primitives.ts +7 -1
  582. package/src/render-pipeline.ts +136 -1
  583. package/src/render-system-extract-tail.ts +72 -60
  584. package/src/render-system-extract.ts +117 -87
  585. package/src/render-system-presentation.ts +56 -0
  586. package/src/render-system-producer-roots.ts +96 -0
  587. package/src/render-system-residency.ts +159 -0
  588. package/src/render-system.ts +601 -482
  589. package/src/scene/probe-blend.ts +96 -4
  590. package/src/scene/render-scene.ts +431 -281
  591. package/src/ssao-buffers.ts +95 -2
  592. package/src/surface/__tests__/dynamic-input.unit.test.ts +374 -0
  593. package/src/surface/__tests__/gpu-driven.unit.test.ts +87 -0
  594. package/src/surface/dynamic-input.ts +658 -0
  595. package/src/surface/gpu-driven.ts +147 -0
  596. package/src/surface/submission-observation.ts +517 -0
  597. package/src/systems/skin-palette-allocator.ts +4 -1
  598. package/src/temporal/__tests__/temporal-frame-transaction.unit.test.ts +36 -0
  599. package/src/temporal/frame-coordinator.ts +8 -1
  600. package/src/temporal/frame.ts +20 -0
  601. package/src/temporal/gpu.ts +101 -17
  602. package/src/temporal/inspection.ts +7 -1
  603. package/src/temporal/standard-scene-data.ts +5 -0
  604. package/src/temporal/target-coverage-attachment.ts +4 -0
  605. package/src/temporal/view.ts +13 -2
  606. package/src/transmission/__tests__/single-layer-medium.unit.test.ts +149 -0
  607. package/src/transmission/__tests__/standard-transmission.dawn.test.ts +12 -11
  608. package/src/transmission/single-layer-medium.ts +322 -0
  609. package/src/typed-render-graph-primitives.ts +191 -50
  610. package/src/volume/component.ts +10 -10
  611. package/src/volume/extract.ts +11 -5
  612. package/src/volume/inspection.ts +3 -0
  613. package/src/volume/passes.ts +95 -8
  614. package/src/volume/resources.ts +2 -1
  615. package/src/volume/temporal.ts +11 -0
  616. package/dist/chunk-4NNZQCL3.mjs.map +0 -1
  617. package/dist/chunk-6TFBXLRJ.mjs.map +0 -1
  618. package/dist/chunk-DRR7D3KX.mjs.map +0 -1
  619. package/dist/chunk-GWCEMDVR.mjs.map +0 -1
  620. package/dist/chunk-JCIRYQ4V.mjs.map +0 -1
  621. package/dist/chunk-JRIPCMYC.mjs.map +0 -1
  622. package/dist/chunk-LULCA3OF.mjs +0 -1713
  623. package/dist/chunk-LULCA3OF.mjs.map +0 -1
  624. package/dist/chunk-PA5DRJNI.mjs.map +0 -1
@@ -42,6 +42,7 @@ import { VideoUploadUnsupportedError } from '../errors/render';
42
42
  import {
43
43
  assembleMaterialWithSkylightEntries,
44
44
  type SkylightBindGroupResources,
45
+ type SurfaceMediumBindGroupResources,
45
46
  type TextureInjectionResource,
46
47
  type TransmissionBindGroupResources,
47
48
  } from '../ibl/skylight-bind-group';
@@ -956,6 +957,12 @@ export interface PerSubmeshMaterialBgDeps {
956
957
  readonly sceneMaterialBuffer?: Buffer;
957
958
  /** Active transmission backdrop; undefined/null means layout placeholder. */
958
959
  readonly transmissionBackdropView?: TextureView | null;
960
+ /** Independent sampled raw depth for the active medium graph pass. */
961
+ readonly surfaceRawDepthView?: TextureView | null;
962
+ /** Nearest-layer color from the preceding medium graph pass. */
963
+ readonly surfaceNearestLayerView?: TextureView | null;
964
+ /** Nearest-layer depth from the preceding medium graph pass. */
965
+ readonly surfaceNearestDepthView?: TextureView | null;
959
966
  readonly bindGroupCounts: BindGroupCounts;
960
967
  readonly frameState: RenderFrameState;
961
968
  }
@@ -1009,8 +1016,9 @@ export function isMaterialBgAssemblyCacheHit(
1009
1016
  materialResourceEpoch: number,
1010
1017
  transmissionBackdropView?: TextureView | null,
1011
1018
  sceneMaterialBuffer?: Buffer,
1019
+ surfaceRawDepthView?: TextureView | null,
1012
1020
  ): cached is MaterialBgAssemblyCacheEntry {
1013
- if (transmissionBackdropView != null) return false;
1021
+ if (transmissionBackdropView != null || surfaceRawDepthView != null) return false;
1014
1022
  return (
1015
1023
  cached?.material === material &&
1016
1024
  cached.materialResourceEpoch === materialResourceEpoch &&
@@ -1047,6 +1055,9 @@ export function buildPerSubmeshMaterialBg(
1047
1055
  materialBgShared,
1048
1056
  materialBgAssemblyCache,
1049
1057
  transmissionBackdropView,
1058
+ surfaceRawDepthView,
1059
+ surfaceNearestLayerView,
1060
+ surfaceNearestDepthView,
1050
1061
  bindGroupCounts,
1051
1062
  frameState,
1052
1063
  } = deps;
@@ -1059,6 +1070,39 @@ export function buildPerSubmeshMaterialBg(
1059
1070
  : `${materialWorld.identity}:${smMaterialHandle}:${materialShaderId ?? ''}:${selectedProbe?.probeIndex ?? 'sky'}`;
1060
1071
  const smHasVideoFields = (submeshMaterial.videoTextureFields?.size ?? 0) > 0;
1061
1072
  const smShaderId = materialShaderId;
1073
+ const selectedMaterialShaderArtifact =
1074
+ smShaderId === undefined ? undefined : runtime.getMaterialShaderArtifact?.(smShaderId);
1075
+ const selectedMediumShader =
1076
+ smShaderId === 'forgeax::single-layer-medium' ||
1077
+ selectedMaterialShaderArtifact?.receipt?.surface?.model === 'single-layer-medium';
1078
+ let surfaceMediumResources: SurfaceMediumBindGroupResources | undefined;
1079
+ if (selectedMediumShader) {
1080
+ if (surfaceRawDepthView == null) {
1081
+ throw new RhiError({
1082
+ code: 'rhi-descriptor-invalid',
1083
+ expected: 'single-layer medium material bind group has producer-owned raw depth',
1084
+ hint: 'admit the Surface material only from a graph pass with an available raw-depth pair',
1085
+ });
1086
+ }
1087
+ const nearestLayerView = surfaceNearestLayerView ?? transmissionBackdropView;
1088
+ const nearestDepthView = surfaceNearestDepthView ?? pipelineState.shadowFallbackTextureView;
1089
+ if (nearestLayerView == null || pipelineState.surfaceMediumDepthSampler === undefined) {
1090
+ throw new RhiError({
1091
+ code: 'rhi-descriptor-invalid',
1092
+ expected:
1093
+ 'single-layer medium material bind group has paired nearest resources and depth sampler',
1094
+ hint: 'publish the nearest-layer target and the non-filtering raw-depth sampler before recording the Surface pass',
1095
+ });
1096
+ }
1097
+ surfaceMediumResources = {
1098
+ rawDepthSampler: pipelineState.surfaceMediumDepthSampler,
1099
+ rawDepthView: surfaceRawDepthView,
1100
+ nearestLayerSampler: effectiveSkylightResources.prefilterSampler,
1101
+ nearestLayerView,
1102
+ nearestDepthSampler: pipelineState.surfaceMediumDepthSampler,
1103
+ nearestDepthView,
1104
+ };
1105
+ }
1062
1106
  // The cooked shader schema owns the resource ABI. A material snapshot may
1063
1107
  // carry only the authored values (for example a clearcoat-only root omits
1064
1108
  // the standard emissive/occlusion maps), while the Standard template still
@@ -1100,6 +1144,7 @@ export function buildPerSubmeshMaterialBg(
1100
1144
  store.materialResourceEpoch,
1101
1145
  transmissionBackdropView,
1102
1146
  sceneMaterialBuffer,
1147
+ surfaceRawDepthView,
1103
1148
  )
1104
1149
  ) {
1105
1150
  if (diagnosticsEnabled) {
@@ -1232,7 +1277,7 @@ export function buildPerSubmeshMaterialBg(
1232
1277
  // Physical Standard maps are deliberately appended after the stable IBL /
1233
1278
  // transmission tail. Keep their resource projection separate from the
1234
1279
  // user-region loop so the slot order is the same as
1235
- // `appendTextureInjection(afterTransmission, physicalFields)` in the
1280
+ // `appendTextureInjection(afterSurfaceMedium, physicalFields)` in the
1236
1281
  // layout owner.
1237
1282
  const physicalTextureInjections: TextureInjectionResource[] = [];
1238
1283
  for (let slot = 0; slot < physicalFields.length; slot += 1) {
@@ -1271,18 +1316,27 @@ export function buildPerSubmeshMaterialBg(
1271
1316
  transmissionBackdropView != null
1272
1317
  ? effectiveSkylightResources.prefilterSampler
1273
1318
  : pipelineState.defaultSampler;
1319
+ // The medium shader keeps the transmission backdrop pair in its fixed
1320
+ // group(1) ABI even on a device that cannot admit the ordinary Standard
1321
+ // transmission topology. Its Surface resources start at binding 10, so
1322
+ // retain a real backdrop pair here whenever the medium resources exist;
1323
+ // otherwise the raw-depth view would slide into binding 9 and Dawn would
1324
+ // reject the unfilterable r32float view as a filtering float texture.
1325
+ const keepMediumBackdropSlots = surfaceMediumResources !== undefined;
1274
1326
  const smMergedEntries = assembleMaterialWithSkylightEntries(
1275
1327
  smBaseEntries,
1276
1328
  effectiveSkylightResources,
1277
- transmissionBackdropAvailable(runtime.device.limits.maxSampledTexturesPerShaderStage)
1329
+ transmissionBackdropAvailable(runtime.device.limits.maxSampledTexturesPerShaderStage) ||
1330
+ keepMediumBackdropSlots
1278
1331
  ? ({
1279
1332
  sampler: transmissionSampler,
1280
1333
  ...(transmissionBackdropView === undefined
1281
- ? {}
1334
+ ? { backdropView: pipelineState.defaultWhiteTextureView }
1282
1335
  : { backdropView: transmissionBackdropView }),
1283
1336
  } satisfies TransmissionBindGroupResources)
1284
1337
  : null,
1285
1338
  physicalTextureInjections,
1339
+ surfaceMediumResources,
1286
1340
  );
1287
1341
  // Storage-capable devices share one Standard material BGL with the
1288
1342
  // scene-index GPU lane. Even direct draws need a complete entry for
@@ -1321,6 +1375,14 @@ export function buildPerSubmeshMaterialBg(
1321
1375
  entityKey,
1322
1376
  materialHandle: smMaterialHandle,
1323
1377
  shader: smShaderId,
1378
+ surfaceModel: submeshMaterial.surfaceModel,
1379
+ layoutIdentity: getOpaqueResourceIdentity(smMaterialBgl as object),
1380
+ bindings: smMergedEntries.map((entry) => entry.binding),
1381
+ graphResources: {
1382
+ rawDepth: surfaceRawDepthView != null,
1383
+ nearestLayer: surfaceNearestLayerView != null,
1384
+ nearestDepth: surfaceNearestDepthView != null,
1385
+ },
1324
1386
  paramSnapshot: submeshMaterial.paramSnapshot,
1325
1387
  handleTypes: materialCacheHandles.map((handle) => typeof handle),
1326
1388
  })}`,
@@ -26,6 +26,7 @@ import type {
26
26
  MaterialSnapshot,
27
27
  SpriteInstancesSnapshot,
28
28
  } from '../render-system-extract';
29
+ import { resolveFoldInstanceBuffer } from './fold-instance-buffer';
29
30
  import { worldEntityKey } from './frame-snapshot';
30
31
  import { recordGeometryDraws, resolveGeometryInstancesBindGroup } from './main-pass-geometry';
31
32
  import {
@@ -589,69 +590,10 @@ function recordSpriteEntityDraws(
589
590
  const spriteInst = spriteEntry.source.instances;
590
591
  const useFold = foldHeadBucket !== undefined && spriteInst === undefined;
591
592
  if (useFold && foldHeadBucket !== undefined) {
592
- // w6 (D-8): bucket transient buffer reuse composite cacheKey from
593
- // (materialHandle, layer, validatedOrdered head index) so the
594
- // existing `frameState.instanceBuffers` byteLength/archVersion path
595
- // covers static steady-state upload-skip. Numeric Map<number,…> key
596
- // requires a 32-bit-safe fold; we use a negative number-space prefix
597
- // (-1, -2, ...) by `((materialHandle << 16) | i)` shifted into the
598
- // negative half so it never collides with positive entity-Instances
599
- // cacheKeys (which are extracted from Instances component cacheKey
600
- // numeric ids, always non-negative). The `archVersion` proxy is
601
- // bucketSize (a structural-shape signal) so static frames hit the
602
- // cache.
603
- const bucketCacheKey = -1 - (((foldHeadBucket.materialHandle & 0xffff) << 16) | (i & 0xffff));
604
- const uniformFallback = runtime.device.caps.storageBuffer === false;
605
- const bucketPayload = uniformFallback
606
- ? foldHeadBucket.transforms
607
- : packInstanceStorageBuffer(foldHeadBucket.transforms);
608
- const bucketBytes = bucketPayload.byteLength;
609
- const bucketBufUsage = uniformFallback
610
- ? GPU_BUFFER_USAGE_UNIFORM | GPU_BUFFER_USAGE_COPY_DST
611
- : GPU_BUFFER_USAGE_STORAGE | GPU_BUFFER_USAGE_COPY_DST;
612
- const cachedBucket = frameState.instanceBuffers.get(bucketCacheKey);
613
- let activeBucket: InstanceBufferCacheEntry | null = null;
614
- if (
615
- cachedBucket !== undefined &&
616
- cachedBucket.uploadedArchVersion === foldHeadBucket.bucketSize &&
617
- cachedBucket.uploadedByteLength === bucketBytes
618
- ) {
619
- activeBucket = cachedBucket;
620
- } else if (bucketBytes > 0) {
621
- const bufRes = runtime.device.createBuffer({
622
- size: bucketBytes,
623
- usage: bucketBufUsage,
624
- mappedAtCreation: false,
625
- });
626
- if (!bufRes.ok) {
627
- runtime.errorRegistry.fire(bufRes.error);
628
- } else {
629
- if (cachedBucket !== undefined && !cachedBucket.buffer.isDestroyed) {
630
- const r = cachedBucket.buffer.destroy();
631
- if (!r.ok) runtime.errorRegistry.fire(r.error);
632
- }
633
- const newBuf = new GpuBuffer(runtime.device, bufRes.value);
634
- activeBucket = {
635
- buffer: newBuf,
636
- uploadedArchVersion: foldHeadBucket.bucketSize,
637
- uploadedByteLength: bucketBytes,
638
- };
639
- frameState.instanceBuffers.set(bucketCacheKey, activeBucket);
640
- }
641
- }
642
- if (activeBucket !== null) {
643
- const writeRes = runtime.device.queue.writeBuffer(
644
- activeBucket.buffer.handle,
645
- 0,
646
- bucketPayload,
647
- );
648
- if (!writeRes.ok) {
649
- runtime.errorRegistry.fire(writeRes.error);
650
- } else {
651
- spriteInstanceBuffer = activeBucket.buffer.handle;
652
- spriteInstanceCount = foldHeadBucket.bucketSize;
653
- }
654
- }
593
+ const buffer = resolveFoldInstanceBuffer(c, foldHeadBucket, i);
594
+ if (buffer === null) continue;
595
+ spriteInstanceBuffer = buffer;
596
+ spriteInstanceCount = foldHeadBucket.bucketSize;
655
597
  } else if (spriteInst !== undefined) {
656
598
  const uniformFallback = runtime.device.caps.storageBuffer === false;
657
599
  let spriteBufUsage = GPU_BUFFER_USAGE_STORAGE | GPU_BUFFER_USAGE_COPY_DST;
@@ -681,7 +623,7 @@ function recordSpriteEntityDraws(
681
623
  );
682
624
  spritePass.setBindGroup(3, spriteInstBg);
683
625
  spritePass.drawIndexed(spriteEntry.mesh.indexCount, spriteInstanceCount, 0, 0, 0);
684
- c.onRenderableDraw?.(spriteEntry);
626
+ c.onRenderableDraw?.(spriteEntry, 0);
685
627
  continue;
686
628
  }
687
629
  spriteBufUsage = GPU_BUFFER_USAGE_UNIFORM | GPU_BUFFER_USAGE_COPY_DST;
@@ -690,7 +632,12 @@ function recordSpriteEntityDraws(
690
632
  {
691
633
  const instancePayload = uniformFallback
692
634
  ? spriteInst.transforms
693
- : packInstanceStorageBuffer(spriteInst.transforms);
635
+ : packInstanceStorageBuffer(
636
+ spriteInst.transforms,
637
+ spriteEntry.source.temporal?.previousInstances?.transforms,
638
+ spriteInst.generations,
639
+ spriteEntry.source.temporal?.previousInstances?.generations,
640
+ );
694
641
  const requestedBytes = instancePayload.byteLength;
695
642
  const cap = runtime.device.limits.maxStorageBufferBindingSize;
696
643
  if (typeof cap === 'number' && requestedBytes > cap) {
@@ -809,7 +756,7 @@ function recordSpriteEntityDraws(
809
756
  spritePass.setBindGroup(1, spritePassBg, [materialSlot * MATERIAL_PER_ENTITY_STRIDE]);
810
757
  spritePass.setBindGroup(3, spriteInstancesBg);
811
758
  spritePass.drawIndexed(spriteEntry.mesh.indexCount, spriteInstanceCount, 0, 0, 0);
812
- c.onRenderableDraw?.(spriteEntry);
759
+ c.onRenderableDraw?.(spriteEntry, 0);
813
760
  }
814
761
  }
815
762
 
@@ -3,6 +3,7 @@ import { probeVideoHighPerfUpload } from '@forgeax/engine-graphics-extras';
3
3
  import type { GraphResourceResolver } from '@forgeax/engine-render-graph';
4
4
  import {
5
5
  type BindGroup,
6
+ type Buffer,
6
7
  RhiError,
7
8
  type RhiRenderPassEncoder,
8
9
  type TextureView,
@@ -10,6 +11,7 @@ import {
10
11
  import type { PassKind, PassSelector } from '@forgeax/engine-types';
11
12
  import {
12
13
  createGpuDrivenLightingBindGroup,
14
+ createHdrpSkinUnifiedBindGroup,
13
15
  createHdrpUnifiedBindGroup,
14
16
  getOrCreateHdrpBuffers,
15
17
  } from '../hdrp-buffers';
@@ -21,6 +23,7 @@ import type { ReflectionProbeSelectionResult } from '../reflection/projection';
21
23
  import type { RenderRecordPhase } from '../render-contract';
22
24
  import type {
23
25
  GpuDrivenStandardPbrFrameResources,
26
+ RenderPipelineGpuDrivenFilter,
24
27
  RenderPipelineGpuDrivenProjection,
25
28
  } from '../render-pipeline';
26
29
  import type { MaterialSnapshot } from '../render-system-extract';
@@ -65,12 +68,28 @@ export type MainPassOptions = {
65
68
  readonly depthView?: TextureView | null;
66
69
  readonly passKind?: PassKind;
67
70
  readonly clearColor?: readonly [number, number, number, number];
68
- readonly recordMode?: 'opaque' | 'transmission' | 'transparent';
71
+ readonly recordMode?:
72
+ | 'opaque'
73
+ | 'transmission'
74
+ | 'transparent'
75
+ | 'single-layer-medium-nearest-layer'
76
+ | 'single-layer-medium-color';
77
+ readonly gpuDrivenFilter?: RenderPipelineGpuDrivenFilter;
78
+ /** Write transparent fragment depth for depth-bounded medium transport. */
79
+ readonly transparentDepthWrite?: boolean;
69
80
  /** Exclude material/pass pairs already consumed by an earlier graph lane. */
70
81
  readonly excludeSelector?: PassSelector;
71
82
  /** Require the same material to contribute to another graph lane. */
72
83
  readonly includeSelector?: PassSelector;
73
84
  readonly transmissionBackdropView?: TextureView | null;
85
+ /** Independent sampled raw depth produced before the medium passes. */
86
+ readonly surfaceRawDepthView?: TextureView | null;
87
+ /** Nearest-layer color produced by the preceding medium pass. */
88
+ readonly surfaceNearestLayerView?: TextureView | null;
89
+ /** Nearest-layer depth produced by the preceding medium pass. */
90
+ readonly surfaceNearestDepthView?: TextureView | null;
91
+ /** Surface shader fragment entry selected by the typed pass owner. */
92
+ readonly fragmentEntryPoint?: string;
74
93
  /** Select the material temporal entry's binary coverage output. */
75
94
  readonly coverageOnly?: boolean;
76
95
  readonly gpuDriven?: {
@@ -89,29 +108,53 @@ function isTransmissionMaterial(material: MaterialSnapshot): boolean {
89
108
 
90
109
  function matchesRecordMode(
91
110
  material: MaterialSnapshot,
92
- mode: 'opaque' | 'transmission' | 'transparent',
111
+ mode:
112
+ | 'opaque'
113
+ | 'transmission'
114
+ | 'transparent'
115
+ | 'single-layer-medium-nearest-layer'
116
+ | 'single-layer-medium-color',
93
117
  ): boolean {
118
+ const medium =
119
+ material.surfaceModel === 'single-layer-medium' ||
120
+ material.materialShaderId === 'forgeax::single-layer-medium';
121
+ if (mode === 'single-layer-medium-nearest-layer' || mode === 'single-layer-medium-color') {
122
+ return medium;
123
+ }
94
124
  const transmission = isTransmissionMaterial(material);
95
125
  if (mode === 'transmission') return transmission;
96
- if (mode === 'transparent') return material.transparent === true && !transmission;
97
- return !transmission && material.transparent !== true;
126
+ if (mode === 'transparent') return material.transparent === true && !transmission && !medium;
127
+ return !transmission && material.transparent !== true && !medium;
98
128
  }
99
129
 
100
130
  function matchedMaterialsForRecordMode(
101
131
  c: _InternalRenderPipelineContext,
102
132
  matchedMaterials: ReadonlyMap<number, ReadonlySet<number>> | null,
103
- mode: 'opaque' | 'transmission' | 'transparent' | undefined,
133
+ mode:
134
+ | 'opaque'
135
+ | 'transmission'
136
+ | 'transparent'
137
+ | 'single-layer-medium-nearest-layer'
138
+ | 'single-layer-medium-color'
139
+ | undefined,
104
140
  ): ReadonlyMap<number, ReadonlySet<number>> | null {
105
141
  if (mode === undefined) return matchedMaterials;
142
+ const surfaceMode =
143
+ mode === 'single-layer-medium-nearest-layer' || mode === 'single-layer-medium-color';
106
144
  const filtered = new Map<number, ReadonlySet<number>>();
107
145
  for (const entry of c.validatedOrdered) {
108
146
  const dispatchHandles = matchedMaterials?.get(entry.renderableIndex);
109
- if (matchedMaterials !== null && dispatchHandles === undefined) continue;
110
- const candidateHandles =
111
- dispatchHandles ??
112
- (mode === 'transmission'
113
- ? []
114
- : entry.source.materials.map((material) => material.materialHandle ?? 0));
147
+ // Surface graph membership is owned by the resolved surface model. A
148
+ // Surface-authored pass does not need to duplicate the generic Forward
149
+ // LightMode tag: its prepared direct program already carries the pass
150
+ // specialization selected by the material producer.
151
+ if (!surfaceMode && matchedMaterials !== null && dispatchHandles === undefined) continue;
152
+ const candidateHandles = surfaceMode
153
+ ? entry.source.materials.map((material) => material.materialHandle ?? 0)
154
+ : (dispatchHandles ??
155
+ (mode === 'transmission'
156
+ ? []
157
+ : entry.source.materials.map((material) => material.materialHandle ?? 0)));
115
158
  const handles = new Set<number>();
116
159
  for (const handle of candidateHandles) {
117
160
  const material =
@@ -173,11 +216,19 @@ export function recordMainPass(
173
216
  const passKind = options?.passKind ?? 'forward';
174
217
  const recordMode = options?.recordMode;
175
218
  const transmissionBackdropView = options?.transmissionBackdropView;
176
- if (recordMode === 'transmission' && transmissionBackdropView == null) {
219
+ const surfaceRawDepthView = options?.surfaceRawDepthView;
220
+ const surfaceNearestLayerView = options?.surfaceNearestLayerView;
221
+ const surfaceNearestDepthView = options?.surfaceNearestDepthView;
222
+ if (
223
+ (recordMode === 'transmission' ||
224
+ recordMode === 'single-layer-medium-nearest-layer' ||
225
+ recordMode === 'single-layer-medium-color') &&
226
+ transmissionBackdropView == null
227
+ ) {
177
228
  throw new RhiError({
178
229
  code: 'webgpu-runtime-error',
179
- expected: 'transmissionBackdropView != null for transmission record mode',
180
- hint: 'the typed Standard transmission pass must resolve its private backdrop view',
230
+ expected: 'transmissionBackdropView != null for a backdrop-consuming record mode',
231
+ hint: 'the typed Standard backdrop pass must resolve its graph-paired color view',
181
232
  });
182
233
  }
183
234
  const colorViews = options?.colorViews ?? [geometryColorView];
@@ -224,12 +275,11 @@ export function recordMainPass(
224
275
  // fallback because the transient SSAO texture does not exist that early.
225
276
  // Built per frame (the SSAO target is a graph transient, so no cross-frame
226
277
  // cache); HDRP-only and SSAO-only, so URP and SSAO-off paths are untouched.
278
+ const hdrpBuffers = clusteredLighting
279
+ ? getOrCreateHdrpBuffers(runtime, frameState.installedPipelineConfig?.clusterGrid)
280
+ : null;
227
281
  let hdrpSsaoBindGroup: BindGroup | null = null;
228
- if (clusteredLighting && hdrpClusterBindGroup !== null && c.hdrpSsaoBlurredView !== undefined) {
229
- const hdrpBuffers = getOrCreateHdrpBuffers(
230
- runtime,
231
- frameState.installedPipelineConfig?.clusterGrid,
232
- );
282
+ if (hdrpClusterBindGroup !== null && c.hdrpSsaoBlurredView !== undefined) {
233
283
  if (hdrpBuffers !== null) {
234
284
  hdrpSsaoBindGroup = createHdrpUnifiedBindGroup(
235
285
  runtime,
@@ -242,6 +292,71 @@ export function recordMainPass(
242
292
  const meshGroup2: BindGroup | null = clusteredLighting
243
293
  ? (hdrpSsaoBindGroup ?? hdrpClusterBindGroup)
244
294
  : meshBindGroup;
295
+ if (gpuDrivenStandardPbrFrameResources !== undefined) {
296
+ // The GPU-driven owner prepares before transient graph resources exist;
297
+ // publish the actual Standard group(2) here, at the existing main-pass
298
+ // binding seam, immediately before indirect encoding.
299
+ gpuDrivenStandardPbrFrameResources.clusterBindGroup =
300
+ clusteredLighting && meshGroup2 !== null ? meshGroup2 : undefined;
301
+ if (hdrpBuffers === null) {
302
+ gpuDrivenStandardPbrFrameResources.clusterBindGroupForMesh = undefined;
303
+ gpuDrivenStandardPbrFrameResources.clusterBindGroupForSkin = undefined;
304
+ } else {
305
+ const projectedGroups = new Map<Buffer, BindGroup>();
306
+ gpuDrivenStandardPbrFrameResources.clusterBindGroupForMesh = (meshBuffer, bindingBytes) => {
307
+ const cached = projectedGroups.get(meshBuffer);
308
+ if (cached !== undefined) return cached;
309
+ const created = createHdrpUnifiedBindGroup(
310
+ runtime,
311
+ hdrpBuffers,
312
+ meshBuffer,
313
+ c.hdrpSsaoBlurredView === undefined
314
+ ? { enabled: false }
315
+ : { enabled: true, ssaoBlurredView: c.hdrpSsaoBlurredView },
316
+ bindingBytes,
317
+ );
318
+ if (created !== null) projectedGroups.set(meshBuffer, created);
319
+ return created ?? undefined;
320
+ };
321
+ const projectedSkinGroups = new Map<Buffer, Map<Buffer, Map<string, BindGroup>>>();
322
+ gpuDrivenStandardPbrFrameResources.clusterBindGroupForSkin = (
323
+ meshBuffer,
324
+ meshBindingBytes,
325
+ paletteBuffer,
326
+ paletteBindingWindowBytes,
327
+ ) => {
328
+ let meshGroups = projectedSkinGroups.get(meshBuffer);
329
+ if (meshGroups === undefined) {
330
+ meshGroups = new Map();
331
+ projectedSkinGroups.set(meshBuffer, meshGroups);
332
+ }
333
+ let paletteGroups = meshGroups.get(paletteBuffer);
334
+ if (paletteGroups === undefined) {
335
+ paletteGroups = new Map();
336
+ meshGroups.set(paletteBuffer, paletteGroups);
337
+ }
338
+ const bindingKey = `${meshBindingBytes}:${paletteBindingWindowBytes}`;
339
+ const cached = paletteGroups.get(bindingKey);
340
+ if (cached !== undefined) return cached;
341
+ const skinLayout = pipelineState.hdrpSkinMeshBindGroupLayout;
342
+ if (skinLayout === null) return undefined;
343
+ const created = createHdrpSkinUnifiedBindGroup(
344
+ runtime,
345
+ hdrpBuffers,
346
+ skinLayout,
347
+ meshBuffer,
348
+ paletteBuffer,
349
+ paletteBindingWindowBytes,
350
+ c.hdrpSsaoBlurredView === undefined
351
+ ? { enabled: false }
352
+ : { enabled: true, ssaoBlurredView: c.hdrpSsaoBlurredView },
353
+ meshBindingBytes,
354
+ );
355
+ if (created !== null) paletteGroups.set(bindingKey, created);
356
+ return created ?? undefined;
357
+ };
358
+ }
359
+ }
245
360
  // ── Geometry (main colour) pass ──────────────────────────────────
246
361
  // D-2: tracks whether the geometry pass was explicitly ended inside
247
362
  // the `if (validatedOrdered.length > 0)` block (sprite split path),
@@ -535,6 +650,9 @@ export function recordMainPass(
535
650
  gpuDrivenSceneMaterialBuffer,
536
651
  }),
537
652
  ...(transmissionBackdropView === undefined ? {} : { transmissionBackdropView }),
653
+ ...(surfaceRawDepthView === undefined ? {} : { surfaceRawDepthView }),
654
+ ...(surfaceNearestLayerView === undefined ? {} : { surfaceNearestLayerView }),
655
+ ...(surfaceNearestDepthView === undefined ? {} : { surfaceNearestDepthView }),
538
656
  };
539
657
  const buildPerSubmeshMaterialBg = (
540
658
  submeshMaterial: MaterialSnapshot,
@@ -558,6 +676,12 @@ export function recordMainPass(
558
676
  for (let materialSlot = 0; materialSlot < materialSlotCount; materialSlot += 1) {
559
677
  const material = materialSlots[materialSlot];
560
678
  if (material === undefined || (material.videoTextureFields?.size ?? 0) > 0) continue;
679
+ // A graph scene pass owns only the materials selected by its record
680
+ // mode. In particular, the opaque pass runs before the raw-depth
681
+ // producer and must not assemble medium bindings with resources that do
682
+ // not exist until the later nearest-layer/color passes. Keep holes for
683
+ // the other lanes; the GPU encoder validates the exact slot it consumes.
684
+ if (recordMode !== undefined && !matchesRecordMode(material, recordMode)) continue;
561
685
  const owner = materialSlotOwners[materialSlot];
562
686
  if (owner === undefined) continue;
563
687
  preparedMaterialBindGroups[materialSlot] = buildPerSubmeshMaterialBg(
@@ -656,6 +780,13 @@ export function recordMainPass(
656
780
  selectedDispatch,
657
781
  colorFormats,
658
782
  options?.coverageOnly ?? false,
783
+ options?.fragmentEntryPoint,
784
+ recordMode === 'single-layer-medium-nearest-layer'
785
+ ? 'nearest-layer'
786
+ : recordMode === 'single-layer-medium-color'
787
+ ? 'color'
788
+ : undefined,
789
+ options?.transparentDepthWrite ?? false,
659
790
  );
660
791
  };
661
792
  if (c.profilePhase === undefined) {
@@ -676,7 +807,10 @@ export function recordMainPass(
676
807
  hint: 'publish the current frame view/light/shadow bind group before GPU raster',
677
808
  });
678
809
  }
679
- if (gpuDrivenStandardPbrFrameResources === undefined) {
810
+ if (
811
+ gpuDrivenStandardPbrFrameResources === undefined ||
812
+ gpuDrivenStandardPbrFrameResources.materialBindGroups.length === 0
813
+ ) {
680
814
  throw new RhiError({
681
815
  code: 'rhi-not-available',
682
816
  expected: 'complete main-pass Standard PBR material bind-group receipt',
@@ -688,6 +822,8 @@ export function recordMainPass(
688
822
  pass,
689
823
  options.gpuDriven.resources,
690
824
  gpuDrivenStandardPbrFrameResources,
825
+ options.gpuDrivenFilter,
826
+ options?.fragmentEntryPoint,
691
827
  );
692
828
  }
693
829
 
@@ -43,23 +43,58 @@ export const MAX_UNIFORM_INSTANCES = 128;
43
43
  /** The storage-backed InstanceData layout is current + previous mat4. */
44
44
  export const INSTANCE_STORAGE_STRIDE_FLOATS = 32;
45
45
 
46
+ function hasStableGenerationColumn(generations: Uint32Array | undefined, count: number): boolean {
47
+ if (generations === undefined || generations.length !== count) return false;
48
+ const seen = new Set<number>();
49
+ for (const generation of generations) {
50
+ if (generation === 0 || seen.has(generation)) return false;
51
+ seen.add(generation);
52
+ }
53
+ return true;
54
+ }
55
+
46
56
  /**
47
57
  * Project the ECS transform snapshot into the storage-backed InstanceData
48
- * layout. The extract contract carries one current mat4 per instance; until
49
- * the ECS snapshot owns a previous-instance column, current is the honest
50
- * previous value as well. Uniform-backed variants keep the compact 16-float
51
- * payload and do not use this projection.
58
+ * layout. Unique identity generations select the previous matrix only when
59
+ * the producer proves that the instance survived. Replaced slots seed
60
+ * previous=current; reordered slots map back to the real prior ordinal so a
61
+ * compaction cannot exchange velocities. Uniform-backed variants keep the
62
+ * compact 16-float payload and do not use this projection.
52
63
  */
53
- export function packInstanceStorageBuffer(transforms: Float32Array): Float32Array {
64
+ export function packInstanceStorageBuffer(
65
+ transforms: Float32Array,
66
+ previousTransforms: Float32Array = transforms,
67
+ generations?: Uint32Array,
68
+ previousGenerations?: Uint32Array,
69
+ ): Float32Array {
54
70
  const count = Math.floor(transforms.length / 16);
55
71
  const out = new Float32Array(count * INSTANCE_STORAGE_STRIDE_FLOATS);
72
+ const previousCount = Math.floor(previousTransforms.length / 16);
73
+ const generationInput = generations !== undefined || previousGenerations !== undefined;
74
+ const identityProof =
75
+ hasStableGenerationColumn(generations, count) &&
76
+ hasStableGenerationColumn(previousGenerations, previousCount);
77
+ const previousIndexByGeneration = identityProof
78
+ ? new Map(
79
+ Array.from(previousGenerations ?? [], (generation, index) => [generation, index] as const),
80
+ )
81
+ : undefined;
56
82
  for (let i = 0; i < count; i++) {
57
83
  const sourceBase = i * 16;
58
84
  const targetBase = i * INSTANCE_STORAGE_STRIDE_FLOATS;
85
+ const previousIndex = identityProof
86
+ ? previousIndexByGeneration?.get(generations?.[i] ?? 0)
87
+ : !generationInput && previousCount === count
88
+ ? i
89
+ : undefined;
90
+ const sameIdentity = previousIndex !== undefined && previousIndex < previousCount;
91
+ const previousBase = (previousIndex ?? i) * 16;
59
92
  for (let k = 0; k < 16; k++) {
60
93
  const value = transforms[sourceBase + k] ?? 0;
61
94
  out[targetBase + k] = value;
62
- out[targetBase + 16 + k] = value;
95
+ out[targetBase + 16 + k] = sameIdentity
96
+ ? (previousTransforms[previousBase + k] ?? value)
97
+ : value;
63
98
  }
64
99
  }
65
100
  return out;
@@ -451,6 +486,7 @@ export function uploadMeshSsboBatch(
451
486
  _meshSsboScratchFloats[slot + 38] = 1;
452
487
  _meshSsboScratchFloats[slot + 43] = 1;
453
488
  _meshSsboScratchFloats[slot + 44] = 1;
489
+ _meshSsboScratchFloats[slot + 45] = 1;
454
490
  } else {
455
491
  const worldFromLocal = entry.source.transform.world;
456
492
  for (let k = 0; k < 16; k++) _meshSsboScratchFloats[slot + k] = worldFromLocal[k] ?? 0;
@@ -483,6 +519,7 @@ export function uploadMeshSsboBatch(
483
519
  }
484
520
  _meshSsboScratchFloats[slot + 44] =
485
521
  entry.source.temporal?.reactive === true || reactiveMaterial ? 1 : 0;
522
+ _meshSsboScratchFloats[slot + 45] = entry.source.temporal?.motionValid === false ? 0 : 1;
486
523
  }
487
524
  }
488
525
  if (neededBytes > 0) {