@forgeax/engine-render 0.1.33 → 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 (518) hide show
  1. package/README.md +1010 -124
  2. package/dist/assembly/backend-contract.d.ts +2 -0
  3. package/dist/assembly/backend-contract.d.ts.map +1 -1
  4. package/dist/assembly/barrel-distortion-inspection.d.ts +3 -0
  5. package/dist/assembly/barrel-distortion-inspection.d.ts.map +1 -0
  6. package/dist/assembly/canvas-draw-guard.d.ts +3 -0
  7. package/dist/assembly/canvas-draw-guard.d.ts.map +1 -0
  8. package/dist/assembly/cloud-shadow-entry.d.ts +4 -0
  9. package/dist/assembly/cloud-shadow-entry.d.ts.map +1 -0
  10. package/dist/assembly/dynamic-geometry-host.d.ts +4 -1
  11. package/dist/assembly/dynamic-geometry-host.d.ts.map +1 -1
  12. package/dist/assembly/dynamic-geometry-runtime.d.ts +1 -1
  13. package/dist/assembly/dynamic-geometry-runtime.d.ts.map +1 -1
  14. package/dist/assembly/factory.d.ts +1 -1
  15. package/dist/assembly/factory.d.ts.map +1 -1
  16. package/dist/assembly/host-contract.d.ts +3 -3
  17. package/dist/assembly/host-contract.d.ts.map +1 -1
  18. package/dist/assembly/material/assembly.d.ts.map +1 -1
  19. package/dist/assembly/material/pipeline-helpers.d.ts +5 -0
  20. package/dist/assembly/material/pipeline-helpers.d.ts.map +1 -1
  21. package/dist/assembly/material-shader-policy.d.ts +16 -2
  22. package/dist/assembly/material-shader-policy.d.ts.map +1 -1
  23. package/dist/assembly/material-shader-prewarm.d.ts.map +1 -1
  24. package/dist/assembly/recovery/device-loss-fanout.d.ts.map +1 -1
  25. package/dist/assembly/recovery/renderer-recover.d.ts +2 -0
  26. package/dist/assembly/recovery/renderer-recover.d.ts.map +1 -1
  27. package/dist/assembly/render-feature-post-processes.d.ts +6 -0
  28. package/dist/assembly/render-feature-post-processes.d.ts.map +1 -0
  29. package/dist/assembly/renderer-facade.d.ts.map +1 -1
  30. package/dist/assembly/renderer-feature-inspection.d.ts +1 -1
  31. package/dist/assembly/renderer-feature-inspection.d.ts.map +1 -1
  32. package/dist/assembly/renderer-frame-transaction.d.ts +12 -0
  33. package/dist/assembly/renderer-frame-transaction.d.ts.map +1 -1
  34. package/dist/assembly/renderer-inspection.d.ts +11 -0
  35. package/dist/assembly/renderer-inspection.d.ts.map +1 -1
  36. package/dist/assembly/webgpu-pbr-ready.d.ts +1 -0
  37. package/dist/assembly/webgpu-pbr-ready.d.ts.map +1 -1
  38. package/dist/assembly/webgpu-ready-per-pass.d.ts +39 -0
  39. package/dist/assembly/webgpu-ready-per-pass.d.ts.map +1 -0
  40. package/dist/assembly/webgpu-ready.d.ts +1 -1
  41. package/dist/assembly/webgpu-ready.d.ts.map +1 -1
  42. package/dist/assembly/webgpu-renderer-bootstrap.d.ts.map +1 -1
  43. package/dist/assembly/webgpu-renderer-observation-owner.d.ts +35 -0
  44. package/dist/assembly/webgpu-renderer-observation-owner.d.ts.map +1 -0
  45. package/dist/assembly/webgpu-renderer.d.ts +1 -1
  46. package/dist/assembly/webgpu-renderer.d.ts.map +1 -1
  47. package/dist/authoring.mjs +1 -1
  48. package/dist/barrel-distortion.d.ts +47 -0
  49. package/dist/barrel-distortion.d.ts.map +1 -0
  50. package/dist/{chunk-PA5DRJNI.mjs → chunk-ELJFJ2BU.mjs} +2 -2
  51. package/dist/chunk-ELJFJ2BU.mjs.map +1 -0
  52. package/dist/{chunk-ZDQWGQW7.mjs → chunk-HEB564WF.mjs} +4 -4
  53. package/dist/{chunk-ZDQWGQW7.mjs.map → chunk-HEB564WF.mjs.map} +1 -1
  54. package/dist/{chunk-VOZWDM3L.mjs → chunk-MKDIT2EM.mjs} +1307 -188
  55. package/dist/chunk-MKDIT2EM.mjs.map +1 -0
  56. package/dist/{chunk-LEAXOMYJ.mjs → chunk-OCDLEI6I.mjs} +3 -3
  57. package/dist/{chunk-LEAXOMYJ.mjs.map → chunk-OCDLEI6I.mjs.map} +1 -1
  58. package/dist/chunk-ODZWR6JQ.mjs +4927 -0
  59. package/dist/chunk-ODZWR6JQ.mjs.map +1 -0
  60. package/dist/{chunk-3RTCJTH4.mjs → chunk-SHFUFJ5N.mjs} +184 -13
  61. package/dist/chunk-SHFUFJ5N.mjs.map +1 -0
  62. package/dist/{chunk-OO3DRYK7.mjs → chunk-UI5SFODX.mjs} +176 -96
  63. package/dist/chunk-UI5SFODX.mjs.map +1 -0
  64. package/dist/{chunk-PLAXOOX5.mjs → chunk-UINHLCZA.mjs} +561 -79
  65. package/dist/chunk-UINHLCZA.mjs.map +1 -0
  66. package/dist/{chunk-NB2S7ZRX.mjs → chunk-WEX45HKH.mjs} +127 -386
  67. package/dist/chunk-WEX45HKH.mjs.map +1 -0
  68. package/dist/cloud/density.d.ts +55 -0
  69. package/dist/cloud/density.d.ts.map +1 -0
  70. package/dist/cloud/extract.d.ts +25 -0
  71. package/dist/cloud/extract.d.ts.map +1 -0
  72. package/dist/cloud/feature.d.ts +57 -0
  73. package/dist/cloud/feature.d.ts.map +1 -0
  74. package/dist/cloud/frame-context.d.ts +8 -0
  75. package/dist/cloud/frame-context.d.ts.map +1 -0
  76. package/dist/cloud/inspection.d.ts +59 -0
  77. package/dist/cloud/inspection.d.ts.map +1 -0
  78. package/dist/cloud/optics.d.ts +56 -0
  79. package/dist/cloud/optics.d.ts.map +1 -0
  80. package/dist/cloud/parameters.d.ts +73 -0
  81. package/dist/cloud/parameters.d.ts.map +1 -0
  82. package/dist/cloud/resources.d.ts +60 -0
  83. package/dist/cloud/resources.d.ts.map +1 -0
  84. package/dist/cloud/shadow.d.ts +42 -0
  85. package/dist/cloud/shadow.d.ts.map +1 -0
  86. package/dist/cloud/temporal.d.ts +74 -0
  87. package/dist/cloud/temporal.d.ts.map +1 -0
  88. package/dist/components/barrel-distortion.d.ts +13 -0
  89. package/dist/components/barrel-distortion.d.ts.map +1 -0
  90. package/dist/components/cloud-layer.d.ts +29 -0
  91. package/dist/components/cloud-layer.d.ts.map +1 -0
  92. package/dist/components/index.d.ts +2 -0
  93. package/dist/components/index.d.ts.map +1 -1
  94. package/dist/components/instances.d.ts +20 -6
  95. package/dist/components/instances.d.ts.map +1 -1
  96. package/dist/construct-renderer.d.ts +1 -1
  97. package/dist/construct-renderer.d.ts.map +1 -1
  98. package/dist/construct-renderer.mjs +6759 -2875
  99. package/dist/construct-renderer.mjs.map +1 -1
  100. package/dist/dynamic-geometry.d.ts +5 -1
  101. package/dist/dynamic-geometry.d.ts.map +1 -1
  102. package/dist/errors/cloud.d.ts +59 -0
  103. package/dist/errors/cloud.d.ts.map +1 -0
  104. package/dist/errors/render.d.ts +18 -4
  105. package/dist/errors/render.d.ts.map +1 -1
  106. package/dist/examples/single-layer-medium-surface.d.ts +47 -0
  107. package/dist/examples/single-layer-medium-surface.d.ts.map +1 -0
  108. package/dist/extract/camera.d.ts.map +1 -1
  109. package/dist/extract/contracts.d.ts +5 -1
  110. package/dist/extract/contracts.d.ts.map +1 -1
  111. package/dist/features/barrel-distortion.d.ts +29 -0
  112. package/dist/features/barrel-distortion.d.ts.map +1 -0
  113. package/dist/features/error-reporting.d.ts +6 -2
  114. package/dist/features/error-reporting.d.ts.map +1 -1
  115. package/dist/features/host.d.ts +10 -0
  116. package/dist/features/host.d.ts.map +1 -1
  117. package/dist/features/plan.d.ts +8 -0
  118. package/dist/features/plan.d.ts.map +1 -1
  119. package/dist/features/render-graph-contribution.d.ts +5 -0
  120. package/dist/features/render-graph-contribution.d.ts.map +1 -1
  121. package/dist/features/render-graph-raster.d.ts +1 -0
  122. package/dist/features/render-graph-raster.d.ts.map +1 -1
  123. package/dist/features/targets.d.ts +2 -0
  124. package/dist/features/targets.d.ts.map +1 -1
  125. package/dist/features/types.d.ts +44 -0
  126. package/dist/features/types.d.ts.map +1 -1
  127. package/dist/fullscreen-post-process-pass.d.ts +15 -7
  128. package/dist/fullscreen-post-process-pass.d.ts.map +1 -1
  129. package/dist/gpu-dirty-ranges.d.ts +11 -0
  130. package/dist/gpu-dirty-ranges.d.ts.map +1 -0
  131. package/dist/gpu-driven/batch-topology.d.ts +17 -0
  132. package/dist/gpu-driven/batch-topology.d.ts.map +1 -1
  133. package/dist/gpu-driven/material-artifacts.d.ts +6 -0
  134. package/dist/gpu-driven/material-artifacts.d.ts.map +1 -1
  135. package/dist/gpu-driven/prepared-draw.d.ts.map +1 -1
  136. package/dist/gpu-driven/production-raster-material.d.ts +178 -0
  137. package/dist/gpu-driven/production-raster-material.d.ts.map +1 -0
  138. package/dist/gpu-driven/production-raster.d.ts +47 -3
  139. package/dist/gpu-driven/production-raster.d.ts.map +1 -1
  140. package/dist/gpu-driven/resource-allocation.d.ts +31 -0
  141. package/dist/gpu-driven/resource-allocation.d.ts.map +1 -0
  142. package/dist/gpu-driven/shadow-ownership.d.ts +14 -0
  143. package/dist/gpu-driven/shadow-ownership.d.ts.map +1 -0
  144. package/dist/gpu-driven/view-gpu.d.ts +26 -2
  145. package/dist/gpu-driven/view-gpu.d.ts.map +1 -1
  146. package/dist/gpu-scene.d.ts +5 -0
  147. package/dist/gpu-scene.d.ts.map +1 -1
  148. package/dist/hdrp-buffers.d.ts +2 -2
  149. package/dist/hdrp-buffers.d.ts.map +1 -1
  150. package/dist/ibl/skylight-bind-group.d.ts +10 -1
  151. package/dist/ibl/skylight-bind-group.d.ts.map +1 -1
  152. package/dist/index.d.ts +27 -7
  153. package/dist/index.d.ts.map +1 -1
  154. package/dist/index.mjs +258 -8
  155. package/dist/index.mjs.map +1 -1
  156. package/dist/inspection-types.d.ts +135 -1
  157. package/dist/inspection-types.d.ts.map +1 -1
  158. package/dist/instance-buffer-cache.d.ts +4 -4
  159. package/dist/instance-buffer-cache.d.ts.map +1 -1
  160. package/dist/instances.d.ts +48 -100
  161. package/dist/instances.d.ts.map +1 -1
  162. package/dist/internal.mjs +7 -7
  163. package/dist/pbr-pipeline.d.ts +19 -1
  164. package/dist/pbr-pipeline.d.ts.map +1 -1
  165. package/dist/pipeline/single-layer-medium-passes.d.ts +73 -0
  166. package/dist/pipeline/single-layer-medium-passes.d.ts.map +1 -0
  167. package/dist/pipeline/standard-forward-lane.d.ts.map +1 -1
  168. package/dist/pipeline/standard-output/graph.d.ts.map +1 -1
  169. package/dist/pipeline/standard-output/types.d.ts +4 -2
  170. package/dist/pipeline/standard-output/types.d.ts.map +1 -1
  171. package/dist/pipeline/standard-pipeline.d.ts.map +1 -1
  172. package/dist/pipeline/standard-post.d.ts.map +1 -1
  173. package/dist/pipeline-builder.d.ts +1 -1
  174. package/dist/pipeline-builder.d.ts.map +1 -1
  175. package/dist/plugin.d.ts.map +1 -1
  176. package/dist/prepare/prepared-graphics-resolver.d.ts +2 -0
  177. package/dist/prepare/prepared-graphics-resolver.d.ts.map +1 -1
  178. package/dist/record/barrel-distortion-frame.d.ts +15 -0
  179. package/dist/record/barrel-distortion-frame.d.ts.map +1 -0
  180. package/dist/record/dynamic-geometry-consumption.d.ts +10 -2
  181. package/dist/record/dynamic-geometry-consumption.d.ts.map +1 -1
  182. package/dist/record/fold-buckets.d.ts +95 -0
  183. package/dist/record/fold-buckets.d.ts.map +1 -0
  184. package/dist/record/fold-instance-buffer.d.ts +6 -0
  185. package/dist/record/fold-instance-buffer.d.ts.map +1 -0
  186. package/dist/record/frame-lighting.d.ts +1 -0
  187. package/dist/record/frame-lighting.d.ts.map +1 -1
  188. package/dist/record/frame-snapshot.d.ts +37 -3
  189. package/dist/record/frame-snapshot.d.ts.map +1 -1
  190. package/dist/record/frame.d.ts +10 -61
  191. package/dist/record/frame.d.ts.map +1 -1
  192. package/dist/record/gpu-draw-receipts.d.ts +11 -0
  193. package/dist/record/gpu-draw-receipts.d.ts.map +1 -0
  194. package/dist/record/gpu-timing.d.ts +8 -0
  195. package/dist/record/gpu-timing.d.ts.map +1 -1
  196. package/dist/record/main-pass-geometry.d.ts +21 -5
  197. package/dist/record/main-pass-geometry.d.ts.map +1 -1
  198. package/dist/record/main-pass-material.d.ts +7 -1
  199. package/dist/record/main-pass-material.d.ts.map +1 -1
  200. package/dist/record/main-pass-sprite-draws.d.ts.map +1 -1
  201. package/dist/record/main-pass.d.ts +13 -2
  202. package/dist/record/main-pass.d.ts.map +1 -1
  203. package/dist/record/motion-blur-receipt.d.ts +11 -0
  204. package/dist/record/motion-blur-receipt.d.ts.map +1 -0
  205. package/dist/record/probe-blend-buffer.d.ts +16 -0
  206. package/dist/record/probe-blend-buffer.d.ts.map +1 -0
  207. package/dist/record/recovery-pipeline.d.ts.map +1 -1
  208. package/dist/record/render-context.d.ts +22 -3
  209. package/dist/record/render-context.d.ts.map +1 -1
  210. package/dist/record/shadow-pass.d.ts +2 -0
  211. package/dist/record/shadow-pass.d.ts.map +1 -1
  212. package/dist/record/skybox-post-pass.d.ts +1 -1
  213. package/dist/record/skybox-post-pass.d.ts.map +1 -1
  214. package/dist/record/typed-frame-graph.d.ts +22 -2
  215. package/dist/record/typed-frame-graph.d.ts.map +1 -1
  216. package/dist/record/view-ubo.d.ts +11 -3
  217. package/dist/record/view-ubo.d.ts.map +1 -1
  218. package/dist/record/volume-params.d.ts +9 -0
  219. package/dist/record/volume-params.d.ts.map +1 -0
  220. package/dist/recovery/render-system-candidate.d.ts +10 -0
  221. package/dist/recovery/render-system-candidate.d.ts.map +1 -1
  222. package/dist/reflection/record-owner.d.ts.map +1 -1
  223. package/dist/render-contract.d.ts +42 -4
  224. package/dist/render-contract.d.ts.map +1 -1
  225. package/dist/render-graph-primitives.d.ts.map +1 -1
  226. package/dist/render-pipeline.d.ts +103 -2
  227. package/dist/render-pipeline.d.ts.map +1 -1
  228. package/dist/render-system-extract-tail.d.ts +3 -2
  229. package/dist/render-system-extract-tail.d.ts.map +1 -1
  230. package/dist/render-system-extract.d.ts +16 -9
  231. package/dist/render-system-extract.d.ts.map +1 -1
  232. package/dist/render-system-presentation.d.ts +23 -0
  233. package/dist/render-system-presentation.d.ts.map +1 -0
  234. package/dist/render-system-producer-roots.d.ts +10 -0
  235. package/dist/render-system-producer-roots.d.ts.map +1 -0
  236. package/dist/render-system-residency.d.ts +12 -0
  237. package/dist/render-system-residency.d.ts.map +1 -0
  238. package/dist/render-system.d.ts +19 -14
  239. package/dist/render-system.d.ts.map +1 -1
  240. package/dist/scene/probe-blend.d.ts +27 -0
  241. package/dist/scene/probe-blend.d.ts.map +1 -1
  242. package/dist/scene/render-scene.d.ts +12 -5
  243. package/dist/scene/render-scene.d.ts.map +1 -1
  244. package/dist/ssao-buffers.d.ts +9 -0
  245. package/dist/ssao-buffers.d.ts.map +1 -1
  246. package/dist/surface/dynamic-input.d.ts +133 -0
  247. package/dist/surface/dynamic-input.d.ts.map +1 -0
  248. package/dist/surface/gpu-driven.d.ts +41 -0
  249. package/dist/surface/gpu-driven.d.ts.map +1 -0
  250. package/dist/surface/submission-observation.d.ts +136 -0
  251. package/dist/surface/submission-observation.d.ts.map +1 -0
  252. package/dist/systems/skin-palette-allocator.d.ts.map +1 -1
  253. package/dist/temporal/gpu.d.ts +13 -1
  254. package/dist/temporal/gpu.d.ts.map +1 -1
  255. package/dist/temporal/index.mjs +5 -5
  256. package/dist/temporal/inspection.d.ts.map +1 -1
  257. package/dist/temporal/standard-scene-data.d.ts.map +1 -1
  258. package/dist/temporal/target-coverage-attachment.d.ts.map +1 -1
  259. package/dist/transmission/single-layer-medium.d.ts +89 -0
  260. package/dist/transmission/single-layer-medium.d.ts.map +1 -0
  261. package/dist/typed-render-graph-primitives.d.ts +14 -2
  262. package/dist/typed-render-graph-primitives.d.ts.map +1 -1
  263. package/dist/volume/component.d.ts +9 -4
  264. package/dist/volume/component.d.ts.map +1 -1
  265. package/dist/volume/extract.d.ts +1 -1
  266. package/dist/volume/extract.d.ts.map +1 -1
  267. package/dist/volume/inspection.d.ts +2 -0
  268. package/dist/volume/inspection.d.ts.map +1 -1
  269. package/dist/volume/passes.d.ts +4 -1
  270. package/dist/volume/passes.d.ts.map +1 -1
  271. package/dist/volume/resources.d.ts.map +1 -1
  272. package/package.json +22 -21
  273. package/src/__tests__/atmosphere-daylight.dawn.test.ts +72 -0
  274. package/src/__tests__/barrel-distortion-lkg.integration.test.ts +353 -0
  275. package/src/__tests__/barrel-distortion.dawn.test.ts +41 -0
  276. package/src/__tests__/barrel-distortion.unit.test.ts +364 -0
  277. package/src/__tests__/construct-renderer-identity.unit.test.ts +49 -0
  278. package/src/__tests__/detached-recovery-graph.unit.test.ts +277 -0
  279. package/src/__tests__/device-loss-fanout.unit.test.ts +36 -1
  280. package/src/__tests__/docs-gate-green.unit.test.ts +112 -1
  281. package/src/__tests__/factory-contract.integration.test.ts +295 -45
  282. package/src/__tests__/feature-depth-input.dawn.test.ts +129 -2
  283. package/src/__tests__/fullscreen-feature-plan.unit.test.ts +14 -3
  284. package/src/__tests__/gpu-dirty-ranges.unit.test.ts +22 -0
  285. package/src/__tests__/gpu-driven-baseline.characterization.test.ts +16 -3
  286. package/src/__tests__/gpu-driven-batch-topology-pbr.unit.test.ts +12 -0
  287. package/src/__tests__/gpu-driven-material-artifacts.unit.test.ts +143 -0
  288. package/src/__tests__/gpu-driven-pbr.dawn.test.ts +2 -2
  289. package/src/__tests__/gpu-driven-production.integration.test.ts +482 -3
  290. package/src/__tests__/gpu-driven-shadow-views.dawn.test.ts +6 -5
  291. package/src/__tests__/gpu-driven-view-gpu-evidence.ts +94 -6
  292. package/src/__tests__/gpu-driven-view-graph.integration.test.ts +18 -2
  293. package/src/__tests__/gpu-driven-view.browser.test.ts +5 -8
  294. package/src/__tests__/gpu-driven-view.dawn.test.ts +6 -2
  295. package/src/__tests__/gpu-driven-view.unit.test.ts +1 -1
  296. package/src/__tests__/gpu-pass-timing-lifecycle.integration.test.ts +1 -0
  297. package/src/__tests__/gpu-pass-timing.browser.test.ts +6 -4
  298. package/src/__tests__/gpu-pass-timing.rhi-null.unit.test.ts +1 -0
  299. package/src/__tests__/gpu-scene.unit.test.ts +119 -9
  300. package/src/__tests__/instance-allocation-failure.unit.test.ts +57 -0
  301. package/src/__tests__/instances-culling.integration.test.ts +10 -36
  302. package/src/__tests__/instances-store.unit.test.ts +97 -305
  303. package/src/__tests__/instances-world-ownership.integration.test.ts +62 -0
  304. package/src/__tests__/main-pass-material-medium-selection.unit.test.ts +146 -0
  305. package/src/__tests__/material-shader-prewarm.unit.test.ts +59 -0
  306. package/src/__tests__/material-snapshot-mutation.integration.test.ts +39 -1
  307. package/src/__tests__/morph-culling-reentry.dawn.test.ts +5 -5
  308. package/src/__tests__/morph-visual-evidence.integration.test.ts +8 -7
  309. package/src/__tests__/motion-blur-compute.dawn.test.ts +13 -7
  310. package/src/__tests__/motion-blur.pixel.integration.test.ts +2 -2
  311. package/src/__tests__/nineslice-handle-surface.unit.test.ts +4 -4
  312. package/src/__tests__/pbr-view-layout.unit.test.ts +9 -0
  313. package/src/__tests__/physical-clearcoat.integration.test.ts +58 -0
  314. package/src/__tests__/prepared-graphics-capability.unit.test.ts +66 -2
  315. package/src/__tests__/probe-bindings.unit.test.ts +582 -1
  316. package/src/__tests__/probe-scene-dirty.integration.test.ts +28 -1
  317. package/src/__tests__/receipt-observation-retirement.unit.test.ts +65 -0
  318. package/src/__tests__/recovery-candidate-prepare.contract.test.ts +69 -0
  319. package/src/__tests__/render-error-code-owner.test-d.ts +7 -0
  320. package/src/__tests__/render-feature-diagnostics.unit.test.ts +15 -2
  321. package/src/__tests__/render-feature-error-reporting.unit.test.ts +21 -1
  322. package/src/__tests__/render-feature-prepared-diagnostics.unit.test.ts +10 -1
  323. package/src/__tests__/render-feature-retry.unit.test.ts +12 -1
  324. package/src/__tests__/render-scene-mixed-updates.integration.test.ts +145 -19
  325. package/src/__tests__/render-scene-projection.unit.test.ts +36 -11
  326. package/src/__tests__/render-scene-temporal-retry.unit.test.ts +20 -20
  327. package/src/__tests__/render-target-probe-soak.perf.test.ts +2 -2
  328. package/src/__tests__/render-temporal-environment-consumer.browser.test.ts +3 -3
  329. package/src/__tests__/render-temporal-environment-consumer.dawn.test.ts +5 -2
  330. package/src/__tests__/renderer-factory-material-contract.unit.test.ts +41 -7
  331. package/src/__tests__/renderer-frame-generation-fence.integration.test.ts +16 -0
  332. package/src/__tests__/renderer-frame-transaction.integration.test.ts +26 -10
  333. package/src/__tests__/resource-allocation.unit.test.ts +123 -0
  334. package/src/__tests__/single-layer-medium-passes.unit.test.ts +275 -0
  335. package/src/__tests__/skin-motion-regression.unit.test.ts +70 -1
  336. package/src/__tests__/skin-palette-recycling.dawn.test.ts +97 -0
  337. package/src/__tests__/skinned-shadow-caster.test.ts +15 -0
  338. package/src/__tests__/ssr-carrier-public-contract.unit.test.ts +21 -0
  339. package/src/__tests__/ssr-gpu-dispatch.browser.test.ts +4 -4
  340. package/src/__tests__/ssr-gpu-dispatch.dawn.test.ts +2 -2
  341. package/src/__tests__/ssr-gpu-dispatch.ts +1 -1
  342. package/src/__tests__/ssr-receiver-coverage.dawn.test.ts +6 -2
  343. package/src/__tests__/standard-output-chain-contract.unit.test.ts +28 -0
  344. package/src/__tests__/standard-pbr-artifact-assembly.unit.test.ts +46 -1
  345. package/src/__tests__/standard-pipeline.integration.test.ts +182 -1
  346. package/src/__tests__/surface-dynamic-buffer-lifecycle.unit.test.ts +506 -0
  347. package/src/__tests__/surface-submission-observation.unit.test.ts +812 -0
  348. package/src/__tests__/temporal-history-lifecycle.unit.test.ts +32 -0
  349. package/src/__tests__/temporal-performance.integration.test.ts +3 -3
  350. package/src/__tests__/visibility-instances.integration.test.ts +7 -19
  351. package/src/__tests__/visibility-producer-matrix.integration.test.ts +9 -20
  352. package/src/__tests__/volume-optics-oracle.unit.test.ts +4 -2
  353. package/src/__tests__/volumetric-fog-budget-recovery.integration.test.ts +30 -20
  354. package/src/__tests__/volumetric-fog-errors.unit.test.ts +4 -3
  355. package/src/__tests__/volumetric-fog-multiple.unit.test.ts +55 -0
  356. package/src/__tests__/volumetric-fog-spot-frame-optics.integration.test.ts +1 -1
  357. package/src/__tests__/volumetric-fog-stage-readback.dawn.test.ts +113 -9
  358. package/src/__tests__/volumetric-fog-topology.unit.test.ts +5 -3
  359. package/src/assembly/backend-contract.ts +30 -0
  360. package/src/assembly/barrel-distortion-inspection.ts +22 -0
  361. package/src/assembly/canvas-draw-guard.ts +11 -0
  362. package/src/assembly/cloud-shadow-entry.ts +22 -0
  363. package/src/assembly/dynamic-geometry-host.ts +65 -37
  364. package/src/assembly/dynamic-geometry-runtime.ts +7 -1
  365. package/src/assembly/factory.ts +2 -30
  366. package/src/assembly/host-contract.ts +3 -3
  367. package/src/assembly/material/assembly.ts +25 -13
  368. package/src/assembly/material/pipeline-helpers.ts +53 -12
  369. package/src/assembly/material-shader-policy.ts +55 -0
  370. package/src/assembly/material-shader-prewarm.ts +21 -10
  371. package/src/assembly/recovery/device-loss-fanout.ts +13 -0
  372. package/src/assembly/recovery/renderer-recover.ts +41 -18
  373. package/src/assembly/render-feature-post-processes.ts +54 -0
  374. package/src/assembly/renderer-facade.ts +4 -1
  375. package/src/assembly/renderer-feature-inspection.ts +8 -2
  376. package/src/assembly/renderer-frame-transaction.ts +23 -0
  377. package/src/assembly/renderer-inspection.ts +28 -0
  378. package/src/assembly/skin-palette-owner.ts +1 -1
  379. package/src/assembly/temporal-post-process-prewarm.ts +3 -3
  380. package/src/assembly/webgpu-pbr-ready.ts +9 -1
  381. package/src/assembly/webgpu-ready-per-pass.ts +104 -0
  382. package/src/assembly/webgpu-ready.ts +115 -61
  383. package/src/assembly/webgpu-renderer-bootstrap.ts +0 -12
  384. package/src/assembly/webgpu-renderer-observation-owner.ts +222 -0
  385. package/src/assembly/webgpu-renderer.ts +214 -252
  386. package/src/assembly/webgpu-vertex-layouts.ts +1 -1
  387. package/src/barrel-distortion.ts +247 -0
  388. package/src/cloud/__tests__/cloud-density-parity.dawn.test.ts +173 -0
  389. package/src/cloud/__tests__/cloud-layer-framebuffer-y.dawn.test.ts +265 -0
  390. package/src/cloud/__tests__/cloud-layer.browser.test.ts +432 -0
  391. package/src/cloud/__tests__/cloud-layer.unit.test.ts +634 -0
  392. package/src/cloud/density.ts +600 -0
  393. package/src/cloud/extract.ts +110 -0
  394. package/src/cloud/feature.ts +1810 -0
  395. package/src/cloud/frame-context.ts +42 -0
  396. package/src/cloud/inspection.ts +130 -0
  397. package/src/cloud/optics.ts +285 -0
  398. package/src/cloud/parameters.ts +255 -0
  399. package/src/cloud/resources.ts +122 -0
  400. package/src/cloud/shadow.ts +167 -0
  401. package/src/cloud/temporal.ts +226 -0
  402. package/src/components/barrel-distortion.ts +46 -0
  403. package/src/components/cloud-layer.ts +47 -0
  404. package/src/components/index.ts +2 -0
  405. package/src/components/instances.ts +18 -45
  406. package/src/components/sprite-instances.ts +1 -1
  407. package/src/construct-renderer.ts +1 -1
  408. package/src/dynamic-geometry.ts +12 -1
  409. package/src/errors/cloud.ts +103 -0
  410. package/src/errors/render.ts +44 -7
  411. package/src/examples/single-layer-medium-surface.ts +59 -0
  412. package/src/extract/camera.ts +15 -1
  413. package/src/extract/contracts.ts +5 -0
  414. package/src/features/barrel-distortion.ts +172 -0
  415. package/src/features/error-reporting.ts +26 -6
  416. package/src/features/host.ts +115 -14
  417. package/src/features/plan.ts +8 -0
  418. package/src/features/render-graph-contribution.ts +9 -0
  419. package/src/features/render-graph-raster.ts +45 -3
  420. package/src/features/targets.ts +66 -0
  421. package/src/features/types.ts +47 -0
  422. package/src/fullscreen-post-process-pass.ts +41 -9
  423. package/src/gpu-dirty-ranges.ts +48 -0
  424. package/src/gpu-driven/batch-topology.ts +53 -0
  425. package/src/gpu-driven/material-artifacts.ts +33 -25
  426. package/src/gpu-driven/prepared-draw.ts +12 -4
  427. package/src/gpu-driven/production-raster-material.ts +1894 -0
  428. package/src/gpu-driven/production-raster.ts +825 -784
  429. package/src/gpu-driven/resource-allocation.ts +142 -0
  430. package/src/gpu-driven/shadow-ownership.ts +71 -0
  431. package/src/gpu-driven/view-gpu.ts +164 -10
  432. package/src/gpu-scene.ts +75 -84
  433. package/src/hdrp-buffers.ts +4 -3
  434. package/src/ibl/skylight-bind-group.ts +49 -7
  435. package/src/index.ts +196 -9
  436. package/src/inspection-types.ts +162 -0
  437. package/src/instance-buffer-cache.ts +4 -4
  438. package/src/instances.ts +149 -569
  439. package/src/pbr-pipeline.ts +219 -13
  440. package/src/pipeline/single-layer-medium-passes.ts +267 -0
  441. package/src/pipeline/standard-forward-lane.ts +313 -57
  442. package/src/pipeline/standard-output/graph.ts +8 -2
  443. package/src/pipeline/standard-output/types.ts +12 -1
  444. package/src/pipeline/standard-pipeline.ts +291 -18
  445. package/src/pipeline/standard-post.ts +90 -24
  446. package/src/pipeline-builder.ts +1 -1
  447. package/src/plugin.ts +4 -0
  448. package/src/points-lines/__tests__/points-lines.bench.ts +17 -8
  449. package/src/prepare/prepared-graphics-resolver.ts +2 -0
  450. package/src/record/__tests__/main-pass-geometry.unit.test.ts +30 -0
  451. package/src/record/__tests__/sprite-material-abi.unit.test.ts +1 -1
  452. package/src/record/__tests__/temporal-payload.unit.test.ts +1 -1
  453. package/src/record/__tests__/transparent-group2-selection.unit.test.ts +11 -0
  454. package/src/record/__tests__/typed-frame-graph-plan.unit.test.ts +1 -0
  455. package/src/record/__tests__/view-ubo-layout.unit.test.ts +4 -3
  456. package/src/record/barrel-distortion-frame.ts +110 -0
  457. package/src/record/dynamic-geometry-consumption.ts +39 -9
  458. package/src/record/fold-buckets.ts +852 -0
  459. package/src/record/fold-instance-buffer.ts +51 -0
  460. package/src/record/frame-lighting.ts +36 -2
  461. package/src/record/frame-snapshot.ts +39 -3
  462. package/src/record/frame.ts +217 -1084
  463. package/src/record/gpu-draw-receipts.ts +38 -0
  464. package/src/record/gpu-timing.ts +48 -5
  465. package/src/record/main-pass-geometry.ts +251 -82
  466. package/src/record/main-pass-material.ts +66 -4
  467. package/src/record/main-pass-sprite-draws.ts +7 -65
  468. package/src/record/main-pass.ts +156 -20
  469. package/src/record/motion-blur-receipt.ts +91 -0
  470. package/src/record/probe-blend-buffer.ts +180 -0
  471. package/src/record/recovery-pipeline.ts +35 -3
  472. package/src/record/render-context.ts +39 -3
  473. package/src/record/shadow-pass.ts +30 -1
  474. package/src/record/skybox-post-pass.ts +28 -4
  475. package/src/record/typed-frame-graph.ts +770 -134
  476. package/src/record/view-ubo.ts +26 -3
  477. package/src/record/volume-params.ts +225 -0
  478. package/src/recovery/render-system-candidate.ts +235 -42
  479. package/src/reflection/record-owner.ts +7 -3
  480. package/src/render-contract.ts +48 -4
  481. package/src/render-graph-primitives.ts +7 -1
  482. package/src/render-pipeline.ts +130 -0
  483. package/src/render-system-extract-tail.ts +57 -61
  484. package/src/render-system-extract.ts +74 -76
  485. package/src/render-system-presentation.ts +56 -0
  486. package/src/render-system-producer-roots.ts +96 -0
  487. package/src/render-system-residency.ts +159 -0
  488. package/src/render-system.ts +347 -363
  489. package/src/scene/probe-blend.ts +96 -4
  490. package/src/scene/render-scene.ts +349 -280
  491. package/src/ssao-buffers.ts +95 -2
  492. package/src/surface/__tests__/dynamic-input.unit.test.ts +374 -0
  493. package/src/surface/__tests__/gpu-driven.unit.test.ts +87 -0
  494. package/src/surface/dynamic-input.ts +658 -0
  495. package/src/surface/gpu-driven.ts +147 -0
  496. package/src/surface/submission-observation.ts +517 -0
  497. package/src/systems/skin-palette-allocator.ts +4 -1
  498. package/src/temporal/gpu.ts +101 -17
  499. package/src/temporal/inspection.ts +7 -1
  500. package/src/temporal/standard-scene-data.ts +5 -0
  501. package/src/temporal/target-coverage-attachment.ts +4 -0
  502. package/src/transmission/__tests__/single-layer-medium.unit.test.ts +149 -0
  503. package/src/transmission/__tests__/standard-transmission.dawn.test.ts +12 -11
  504. package/src/transmission/single-layer-medium.ts +322 -0
  505. package/src/typed-render-graph-primitives.ts +70 -2
  506. package/src/volume/component.ts +10 -9
  507. package/src/volume/extract.ts +11 -5
  508. package/src/volume/inspection.ts +3 -0
  509. package/src/volume/passes.ts +87 -4
  510. package/src/volume/resources.ts +2 -1
  511. package/dist/chunk-3RTCJTH4.mjs.map +0 -1
  512. package/dist/chunk-NB2S7ZRX.mjs.map +0 -1
  513. package/dist/chunk-NNQL7CB3.mjs +0 -1713
  514. package/dist/chunk-NNQL7CB3.mjs.map +0 -1
  515. package/dist/chunk-OO3DRYK7.mjs.map +0 -1
  516. package/dist/chunk-PA5DRJNI.mjs.map +0 -1
  517. package/dist/chunk-PLAXOOX5.mjs.map +0 -1
  518. package/dist/chunk-VOZWDM3L.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;
@@ -814,7 +756,7 @@ function recordSpriteEntityDraws(
814
756
  spritePass.setBindGroup(1, spritePassBg, [materialSlot * MATERIAL_PER_ENTITY_STRIDE]);
815
757
  spritePass.setBindGroup(3, spriteInstancesBg);
816
758
  spritePass.drawIndexed(spriteEntry.mesh.indexCount, spriteInstanceCount, 0, 0, 0);
817
- c.onRenderableDraw?.(spriteEntry);
759
+ c.onRenderableDraw?.(spriteEntry, 0);
818
760
  }
819
761
  }
820
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
 
@@ -0,0 +1,91 @@
1
+ import { getRenderFeaturePlanExecutionProjection } from '../features/host';
2
+ import type { RenderFeaturePlannedFrame } from '../features/plan';
3
+ import type { MotionBlurExecutionPass, MotionBlurExecutionReceipt } from '../inspection-types';
4
+ import type { RenderFrameState } from './frame-snapshot';
5
+ import type { RenderSystemInternals } from './render-context';
6
+
7
+ /**
8
+ * Project one accepted Motion Blur compute execution from the same graph and
9
+ * resolved dispatch objects used by the encoder. A plan/capability candidate
10
+ * without both executed passes deliberately returns no receipt.
11
+ */
12
+ export function deriveMotionBlurExecutionReceipt(
13
+ internals: RenderSystemInternals,
14
+ frameState: RenderFrameState,
15
+ plans: readonly RenderFeaturePlannedFrame[],
16
+ ): MotionBlurExecutionReceipt | undefined {
17
+ const graph = frameState.compiledFrameGraph;
18
+ const deviceGeneration = internals.deviceScope?.generation;
19
+ if (graph === null || deviceGeneration === undefined) return undefined;
20
+ const info = graph.inspect();
21
+ const graphPasses = new Map(info.passes.map((pass) => [pass.name, pass]));
22
+ const summaryGraphPass = graphPasses.get('motion-blur-tile-summary');
23
+ const reconstructGraphPass = graphPasses.get('motion-blur');
24
+ if (summaryGraphPass?.kind !== 'compute' || reconstructGraphPass?.kind !== 'compute') {
25
+ return undefined;
26
+ }
27
+ const planned = plans.find((candidate) => candidate.featureIdentity === 'forgeax.motion-blur');
28
+ const execution =
29
+ planned === undefined ? undefined : getRenderFeaturePlanExecutionProjection(planned);
30
+ if (execution === undefined || execution.featureIdentity !== 'forgeax.motion-blur') {
31
+ return undefined;
32
+ }
33
+ const executionPass = (name: 'motion-blur-tile-summary' | 'motion-blur') =>
34
+ execution.passes.find((pass) => pass.name === name);
35
+ const summary = executionPass('motion-blur-tile-summary');
36
+ const reconstruct = executionPass('motion-blur');
37
+ if (
38
+ summary?.gpuCompute === undefined ||
39
+ reconstruct?.gpuCompute === undefined ||
40
+ summary.resolvedGpuCompute === undefined ||
41
+ reconstruct.resolvedGpuCompute === undefined
42
+ ) {
43
+ return undefined;
44
+ }
45
+ const directWorkgroups = (
46
+ pass: NonNullable<typeof summary.resolvedGpuCompute>,
47
+ ): readonly [number, number, number] | undefined => {
48
+ const dispatch = pass.dispatches[0];
49
+ if (dispatch === undefined || !('workgroups' in dispatch)) return undefined;
50
+ return dispatch.workgroups;
51
+ };
52
+ const summaryWorkgroups = directWorkgroups(summary.resolvedGpuCompute);
53
+ const reconstructWorkgroups = directWorkgroups(reconstruct.resolvedGpuCompute);
54
+ if (summaryWorkgroups === undefined || reconstructWorkgroups === undefined) return undefined;
55
+ const outputResource = info.resources.find(
56
+ (resource) =>
57
+ resource.label === 'motion-blurred-color' ||
58
+ reconstructGraphPass.accesses.some(
59
+ (access) => access.resource === resource.label && access.usage === 'storage-write',
60
+ ),
61
+ );
62
+ if (
63
+ outputResource?.descriptor.kind !== 'texture' ||
64
+ outputResource.descriptor.format !== 'rgba16float'
65
+ ) {
66
+ return undefined;
67
+ }
68
+ const summaryReceipt: MotionBlurExecutionPass = {
69
+ name: 'motion-blur-tile-summary',
70
+ kind: 'compute',
71
+ entryPoint: 'tile_summary',
72
+ workgroups: summaryWorkgroups,
73
+ };
74
+ const reconstructReceipt: MotionBlurExecutionPass = {
75
+ name: 'motion-blur',
76
+ kind: 'compute',
77
+ entryPoint: 'reconstruct',
78
+ workgroups: reconstructWorkgroups,
79
+ };
80
+ return Object.freeze({
81
+ frameId: frameState.frameNumber,
82
+ deviceGeneration,
83
+ // RenderGraphBuilder generations are process-global. The renderer's
84
+ // frame-state generation is the identity used by inspection and by the
85
+ // same-frame admission check below, so retain that owner-scoped value.
86
+ graphGeneration: frameState.graphGeneration,
87
+ program: 'motion-blur-compute' as const,
88
+ outputFormat: 'rgba16float' as const,
89
+ passes: [summaryReceipt, reconstructReceipt] as const,
90
+ });
91
+ }