@forgeax/engine-render 0.1.33 → 0.1.35

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 +1062 -127
  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/device-feature-admission.d.ts +2 -2
  11. package/dist/assembly/dynamic-geometry-host.d.ts +4 -1
  12. package/dist/assembly/dynamic-geometry-host.d.ts.map +1 -1
  13. package/dist/assembly/dynamic-geometry-runtime.d.ts +1 -1
  14. package/dist/assembly/dynamic-geometry-runtime.d.ts.map +1 -1
  15. package/dist/assembly/factory.d.ts +1 -1
  16. package/dist/assembly/factory.d.ts.map +1 -1
  17. package/dist/assembly/host-contract.d.ts +6 -5
  18. package/dist/assembly/host-contract.d.ts.map +1 -1
  19. package/dist/assembly/material/assembly.d.ts.map +1 -1
  20. package/dist/assembly/material/pipeline-helpers.d.ts +5 -0
  21. package/dist/assembly/material/pipeline-helpers.d.ts.map +1 -1
  22. package/dist/assembly/material-shader-policy.d.ts +16 -2
  23. package/dist/assembly/material-shader-policy.d.ts.map +1 -1
  24. package/dist/assembly/material-shader-prewarm.d.ts.map +1 -1
  25. package/dist/assembly/recovery/device-loss-fanout.d.ts.map +1 -1
  26. package/dist/assembly/recovery/renderer-recover.d.ts +2 -0
  27. package/dist/assembly/recovery/renderer-recover.d.ts.map +1 -1
  28. package/dist/assembly/render-feature-post-processes.d.ts +6 -0
  29. package/dist/assembly/render-feature-post-processes.d.ts.map +1 -0
  30. package/dist/assembly/render-target-host.d.ts +5 -0
  31. package/dist/assembly/render-target-host.d.ts.map +1 -1
  32. package/dist/assembly/renderer-facade.d.ts.map +1 -1
  33. package/dist/assembly/renderer-feature-inspection.d.ts +1 -1
  34. package/dist/assembly/renderer-feature-inspection.d.ts.map +1 -1
  35. package/dist/assembly/renderer-frame-transaction.d.ts +12 -0
  36. package/dist/assembly/renderer-frame-transaction.d.ts.map +1 -1
  37. package/dist/assembly/renderer-inspection.d.ts +11 -0
  38. package/dist/assembly/renderer-inspection.d.ts.map +1 -1
  39. package/dist/assembly/webgpu-pbr-ready.d.ts +1 -0
  40. package/dist/assembly/webgpu-pbr-ready.d.ts.map +1 -1
  41. package/dist/assembly/webgpu-ready-per-pass.d.ts +39 -0
  42. package/dist/assembly/webgpu-ready-per-pass.d.ts.map +1 -0
  43. package/dist/assembly/webgpu-ready.d.ts +1 -1
  44. package/dist/assembly/webgpu-ready.d.ts.map +1 -1
  45. package/dist/assembly/webgpu-renderer-bootstrap.d.ts.map +1 -1
  46. package/dist/assembly/webgpu-renderer-observation-owner.d.ts +35 -0
  47. package/dist/assembly/webgpu-renderer-observation-owner.d.ts.map +1 -0
  48. package/dist/assembly/webgpu-renderer.d.ts +2 -1
  49. package/dist/assembly/webgpu-renderer.d.ts.map +1 -1
  50. package/dist/authoring.mjs +2 -4
  51. package/dist/authoring.mjs.map +1 -1
  52. package/dist/barrel-distortion.d.ts +47 -0
  53. package/dist/barrel-distortion.d.ts.map +1 -0
  54. package/dist/chunk-3XUBWRY2.mjs +1842 -0
  55. package/dist/chunk-3XUBWRY2.mjs.map +1 -0
  56. package/dist/{chunk-OO3DRYK7.mjs → chunk-G6HDNGY7.mjs} +2400 -1767
  57. package/dist/chunk-G6HDNGY7.mjs.map +1 -0
  58. package/dist/{chunk-ZDQWGQW7.mjs → chunk-LM5IE7GF.mjs} +4 -4
  59. package/dist/{chunk-ZDQWGQW7.mjs.map → chunk-LM5IE7GF.mjs.map} +1 -1
  60. package/dist/{chunk-VOZWDM3L.mjs → chunk-LNIUIKQ7.mjs} +1514 -498
  61. package/dist/chunk-LNIUIKQ7.mjs.map +1 -0
  62. package/dist/chunk-MXTWKZO4.mjs +3268 -0
  63. package/dist/chunk-MXTWKZO4.mjs.map +1 -0
  64. package/dist/chunk-MZ4C7EHF.mjs +6942 -0
  65. package/dist/chunk-MZ4C7EHF.mjs.map +1 -0
  66. package/dist/chunk-RIPAEGI6.mjs +48 -0
  67. package/dist/chunk-RIPAEGI6.mjs.map +1 -0
  68. package/dist/{chunk-LEAXOMYJ.mjs → chunk-SGPUJW3F.mjs} +117 -5
  69. package/dist/chunk-SGPUJW3F.mjs.map +1 -0
  70. package/dist/{chunk-PA5DRJNI.mjs → chunk-X2KA6WHM.mjs} +29 -4
  71. package/dist/chunk-X2KA6WHM.mjs.map +1 -0
  72. package/dist/{chunk-BLXGONR2.mjs → chunk-XSFB7XXQ.mjs} +51 -4
  73. package/dist/chunk-XSFB7XXQ.mjs.map +1 -0
  74. package/dist/cloud/density.d.ts +55 -0
  75. package/dist/cloud/density.d.ts.map +1 -0
  76. package/dist/cloud/extract.d.ts +25 -0
  77. package/dist/cloud/extract.d.ts.map +1 -0
  78. package/dist/cloud/feature.d.ts +57 -0
  79. package/dist/cloud/feature.d.ts.map +1 -0
  80. package/dist/cloud/frame-context.d.ts +8 -0
  81. package/dist/cloud/frame-context.d.ts.map +1 -0
  82. package/dist/cloud/inspection.d.ts +59 -0
  83. package/dist/cloud/inspection.d.ts.map +1 -0
  84. package/dist/cloud/optics.d.ts +56 -0
  85. package/dist/cloud/optics.d.ts.map +1 -0
  86. package/dist/cloud/parameters.d.ts +73 -0
  87. package/dist/cloud/parameters.d.ts.map +1 -0
  88. package/dist/cloud/resources.d.ts +60 -0
  89. package/dist/cloud/resources.d.ts.map +1 -0
  90. package/dist/cloud/shadow.d.ts +42 -0
  91. package/dist/cloud/shadow.d.ts.map +1 -0
  92. package/dist/cloud/temporal.d.ts +74 -0
  93. package/dist/cloud/temporal.d.ts.map +1 -0
  94. package/dist/components/barrel-distortion.d.ts +13 -0
  95. package/dist/components/barrel-distortion.d.ts.map +1 -0
  96. package/dist/components/cloud-layer.d.ts +29 -0
  97. package/dist/components/cloud-layer.d.ts.map +1 -0
  98. package/dist/components/index.d.ts +2 -0
  99. package/dist/components/index.d.ts.map +1 -1
  100. package/dist/components/instances.d.ts +20 -6
  101. package/dist/components/instances.d.ts.map +1 -1
  102. package/dist/construct-renderer.d.ts +1 -1
  103. package/dist/construct-renderer.d.ts.map +1 -1
  104. package/dist/construct-renderer.mjs +8406 -5785
  105. package/dist/construct-renderer.mjs.map +1 -1
  106. package/dist/device/gpu-residency.d.ts +19 -19
  107. package/dist/device/gpu-residency.d.ts.map +1 -1
  108. package/dist/dynamic-geometry.d.ts +5 -1
  109. package/dist/dynamic-geometry.d.ts.map +1 -1
  110. package/dist/errors/cloud.d.ts +59 -0
  111. package/dist/errors/cloud.d.ts.map +1 -0
  112. package/dist/errors/render.d.ts +20 -5
  113. package/dist/errors/render.d.ts.map +1 -1
  114. package/dist/examples/single-layer-medium-surface.d.ts +47 -0
  115. package/dist/examples/single-layer-medium-surface.d.ts.map +1 -0
  116. package/dist/extract/camera.d.ts.map +1 -1
  117. package/dist/extract/contracts.d.ts +5 -1
  118. package/dist/extract/contracts.d.ts.map +1 -1
  119. package/dist/extract/material-context.d.ts +7 -0
  120. package/dist/extract/material-context.d.ts.map +1 -0
  121. package/dist/features/barrel-distortion.d.ts +29 -0
  122. package/dist/features/barrel-distortion.d.ts.map +1 -0
  123. package/dist/features/error-reporting.d.ts +6 -2
  124. package/dist/features/error-reporting.d.ts.map +1 -1
  125. package/dist/features/host.d.ts +15 -0
  126. package/dist/features/host.d.ts.map +1 -1
  127. package/dist/features/plan.d.ts +10 -0
  128. package/dist/features/plan.d.ts.map +1 -1
  129. package/dist/features/render-graph-contribution.d.ts +5 -0
  130. package/dist/features/render-graph-contribution.d.ts.map +1 -1
  131. package/dist/features/render-graph-raster.d.ts +1 -0
  132. package/dist/features/render-graph-raster.d.ts.map +1 -1
  133. package/dist/features/targets.d.ts +2 -0
  134. package/dist/features/targets.d.ts.map +1 -1
  135. package/dist/features/types.d.ts +48 -0
  136. package/dist/features/types.d.ts.map +1 -1
  137. package/dist/fullscreen-post-process-pass.d.ts +15 -7
  138. package/dist/fullscreen-post-process-pass.d.ts.map +1 -1
  139. package/dist/glyph-text-layout-system.d.ts +1 -1
  140. package/dist/glyph-text-layout-system.d.ts.map +1 -1
  141. package/dist/gpu-dirty-ranges.d.ts +11 -0
  142. package/dist/gpu-dirty-ranges.d.ts.map +1 -0
  143. package/dist/gpu-driven/batch-topology.d.ts +17 -0
  144. package/dist/gpu-driven/batch-topology.d.ts.map +1 -1
  145. package/dist/gpu-driven/material-artifacts.d.ts +6 -0
  146. package/dist/gpu-driven/material-artifacts.d.ts.map +1 -1
  147. package/dist/gpu-driven/prepared-draw.d.ts.map +1 -1
  148. package/dist/gpu-driven/production-raster-material.d.ts +178 -0
  149. package/dist/gpu-driven/production-raster-material.d.ts.map +1 -0
  150. package/dist/gpu-driven/production-raster.d.ts +47 -3
  151. package/dist/gpu-driven/production-raster.d.ts.map +1 -1
  152. package/dist/gpu-driven/resource-allocation.d.ts +31 -0
  153. package/dist/gpu-driven/resource-allocation.d.ts.map +1 -0
  154. package/dist/gpu-driven/shadow-ownership.d.ts +14 -0
  155. package/dist/gpu-driven/shadow-ownership.d.ts.map +1 -0
  156. package/dist/gpu-driven/view-gpu.d.ts +26 -2
  157. package/dist/gpu-driven/view-gpu.d.ts.map +1 -1
  158. package/dist/gpu-scene.d.ts +5 -0
  159. package/dist/gpu-scene.d.ts.map +1 -1
  160. package/dist/hdrp-buffers.d.ts +2 -2
  161. package/dist/hdrp-buffers.d.ts.map +1 -1
  162. package/dist/ibl/frame-resources.d.ts.map +1 -1
  163. package/dist/ibl/skylight-bind-group.d.ts +14 -5
  164. package/dist/ibl/skylight-bind-group.d.ts.map +1 -1
  165. package/dist/index.d.ts +30 -7
  166. package/dist/index.d.ts.map +1 -1
  167. package/dist/index.mjs +780 -9
  168. package/dist/index.mjs.map +1 -1
  169. package/dist/inspection-types.d.ts +135 -1
  170. package/dist/inspection-types.d.ts.map +1 -1
  171. package/dist/instance-buffer-cache.d.ts +4 -4
  172. package/dist/instance-buffer-cache.d.ts.map +1 -1
  173. package/dist/instances.d.ts +47 -100
  174. package/dist/instances.d.ts.map +1 -1
  175. package/dist/internal.mjs +7 -8
  176. package/dist/internal.mjs.map +1 -1
  177. package/dist/pbr-pipeline.d.ts +22 -4
  178. package/dist/pbr-pipeline.d.ts.map +1 -1
  179. package/dist/pipeline/single-layer-medium-passes.d.ts +73 -0
  180. package/dist/pipeline/single-layer-medium-passes.d.ts.map +1 -0
  181. package/dist/pipeline/standard-forward-lane.d.ts.map +1 -1
  182. package/dist/pipeline/standard-output/graph.d.ts.map +1 -1
  183. package/dist/pipeline/standard-output/lut-gpu.d.ts +2 -2
  184. package/dist/pipeline/standard-output/lut-gpu.d.ts.map +1 -1
  185. package/dist/pipeline/standard-output/resources.d.ts +2 -2
  186. package/dist/pipeline/standard-output/resources.d.ts.map +1 -1
  187. package/dist/pipeline/standard-output/types.d.ts +4 -2
  188. package/dist/pipeline/standard-output/types.d.ts.map +1 -1
  189. package/dist/pipeline/standard-pipeline.d.ts.map +1 -1
  190. package/dist/pipeline/standard-post.d.ts.map +1 -1
  191. package/dist/pipeline-builder.d.ts +1 -1
  192. package/dist/pipeline-builder.d.ts.map +1 -1
  193. package/dist/plugin.d.ts.map +1 -1
  194. package/dist/prepare/prepared-graphics-resolver.d.ts +2 -0
  195. package/dist/prepare/prepared-graphics-resolver.d.ts.map +1 -1
  196. package/dist/publication/contract.d.ts +77 -0
  197. package/dist/publication/contract.d.ts.map +1 -0
  198. package/dist/publication/dependencies.d.ts +7 -0
  199. package/dist/publication/dependencies.d.ts.map +1 -0
  200. package/dist/publication/prepare-geometry.d.ts +9 -0
  201. package/dist/publication/prepare-geometry.d.ts.map +1 -0
  202. package/dist/publication/programs.d.ts +5 -0
  203. package/dist/publication/programs.d.ts.map +1 -0
  204. package/dist/publication/publisher.d.ts +33 -0
  205. package/dist/publication/publisher.d.ts.map +1 -0
  206. package/dist/publication/receiver.d.ts +29 -0
  207. package/dist/publication/receiver.d.ts.map +1 -0
  208. package/dist/publication/resource-scope.d.ts +18 -0
  209. package/dist/publication/resource-scope.d.ts.map +1 -0
  210. package/dist/publication/targets.d.ts +33 -0
  211. package/dist/publication/targets.d.ts.map +1 -0
  212. package/dist/publication/video.d.ts +5 -0
  213. package/dist/publication/video.d.ts.map +1 -0
  214. package/dist/record/barrel-distortion-frame.d.ts +15 -0
  215. package/dist/record/barrel-distortion-frame.d.ts.map +1 -0
  216. package/dist/record/dynamic-geometry-consumption.d.ts +10 -2
  217. package/dist/record/dynamic-geometry-consumption.d.ts.map +1 -1
  218. package/dist/record/fold-buckets.d.ts +95 -0
  219. package/dist/record/fold-buckets.d.ts.map +1 -0
  220. package/dist/record/fold-instance-buffer.d.ts +6 -0
  221. package/dist/record/fold-instance-buffer.d.ts.map +1 -0
  222. package/dist/record/frame-lighting.d.ts +1 -0
  223. package/dist/record/frame-lighting.d.ts.map +1 -1
  224. package/dist/record/frame-snapshot.d.ts +43 -9
  225. package/dist/record/frame-snapshot.d.ts.map +1 -1
  226. package/dist/record/frame.d.ts +15 -65
  227. package/dist/record/frame.d.ts.map +1 -1
  228. package/dist/record/gpu-draw-receipts.d.ts +11 -0
  229. package/dist/record/gpu-draw-receipts.d.ts.map +1 -0
  230. package/dist/record/gpu-timing.d.ts +8 -0
  231. package/dist/record/gpu-timing.d.ts.map +1 -1
  232. package/dist/record/helpers.d.ts +2 -2
  233. package/dist/record/helpers.d.ts.map +1 -1
  234. package/dist/record/main-pass-geometry.d.ts +22 -6
  235. package/dist/record/main-pass-geometry.d.ts.map +1 -1
  236. package/dist/record/main-pass-material.d.ts +14 -10
  237. package/dist/record/main-pass-material.d.ts.map +1 -1
  238. package/dist/record/main-pass-sprite-draws.d.ts +3 -16
  239. package/dist/record/main-pass-sprite-draws.d.ts.map +1 -1
  240. package/dist/record/main-pass.d.ts +13 -2
  241. package/dist/record/main-pass.d.ts.map +1 -1
  242. package/dist/record/motion-blur-receipt.d.ts +11 -0
  243. package/dist/record/motion-blur-receipt.d.ts.map +1 -0
  244. package/dist/record/prepared-material-bindings.d.ts +3 -3
  245. package/dist/record/prepared-material-bindings.d.ts.map +1 -1
  246. package/dist/record/probe-blend-buffer.d.ts +16 -0
  247. package/dist/record/probe-blend-buffer.d.ts.map +1 -0
  248. package/dist/record/recovery-pipeline.d.ts.map +1 -1
  249. package/dist/record/render-context.d.ts +24 -5
  250. package/dist/record/render-context.d.ts.map +1 -1
  251. package/dist/record/shadow-pass.d.ts +2 -0
  252. package/dist/record/shadow-pass.d.ts.map +1 -1
  253. package/dist/record/skybox-post-pass.d.ts +1 -1
  254. package/dist/record/skybox-post-pass.d.ts.map +1 -1
  255. package/dist/record/sprite-instance-buffer.d.ts +31 -0
  256. package/dist/record/sprite-instance-buffer.d.ts.map +1 -0
  257. package/dist/record/target-capture-graph.d.ts +19 -0
  258. package/dist/record/target-capture-graph.d.ts.map +1 -0
  259. package/dist/record/typed-frame-graph.d.ts +24 -15
  260. package/dist/record/typed-frame-graph.d.ts.map +1 -1
  261. package/dist/record/view-ubo.d.ts +11 -3
  262. package/dist/record/view-ubo.d.ts.map +1 -1
  263. package/dist/record/volume-params.d.ts +9 -0
  264. package/dist/record/volume-params.d.ts.map +1 -0
  265. package/dist/recovery/render-system-candidate.d.ts +14 -4
  266. package/dist/recovery/render-system-candidate.d.ts.map +1 -1
  267. package/dist/reflection/record-owner.d.ts.map +1 -1
  268. package/dist/render-contract.d.ts +46 -5
  269. package/dist/render-contract.d.ts.map +1 -1
  270. package/dist/render-graph-primitives.d.ts.map +1 -1
  271. package/dist/render-pipeline.d.ts +103 -2
  272. package/dist/render-pipeline.d.ts.map +1 -1
  273. package/dist/render-system-extract-tail.d.ts +3 -2
  274. package/dist/render-system-extract-tail.d.ts.map +1 -1
  275. package/dist/render-system-extract.d.ts +18 -9
  276. package/dist/render-system-extract.d.ts.map +1 -1
  277. package/dist/render-system-presentation.d.ts +23 -0
  278. package/dist/render-system-presentation.d.ts.map +1 -0
  279. package/dist/render-system-producer-roots.d.ts +10 -0
  280. package/dist/render-system-producer-roots.d.ts.map +1 -0
  281. package/dist/render-system-projections.d.ts +3 -2
  282. package/dist/render-system-projections.d.ts.map +1 -1
  283. package/dist/render-system-residency.d.ts +12 -0
  284. package/dist/render-system-residency.d.ts.map +1 -0
  285. package/dist/render-system.d.ts +22 -21
  286. package/dist/render-system.d.ts.map +1 -1
  287. package/dist/scene/probe-blend.d.ts +27 -0
  288. package/dist/scene/probe-blend.d.ts.map +1 -1
  289. package/dist/scene/render-scene.d.ts +18 -7
  290. package/dist/scene/render-scene.d.ts.map +1 -1
  291. package/dist/scene/render-source.d.ts +42 -0
  292. package/dist/scene/render-source.d.ts.map +1 -0
  293. package/dist/scene/source-systems.d.ts +6 -0
  294. package/dist/scene/source-systems.d.ts.map +1 -0
  295. package/dist/ssao-buffers.d.ts +9 -0
  296. package/dist/ssao-buffers.d.ts.map +1 -1
  297. package/dist/surface/dynamic-input.d.ts +133 -0
  298. package/dist/surface/dynamic-input.d.ts.map +1 -0
  299. package/dist/surface/gpu-driven.d.ts +41 -0
  300. package/dist/surface/gpu-driven.d.ts.map +1 -0
  301. package/dist/surface/submission-observation.d.ts +136 -0
  302. package/dist/surface/submission-observation.d.ts.map +1 -0
  303. package/dist/systems/skin-palette-allocator.d.ts.map +1 -1
  304. package/dist/systems/skin-palette-types.d.ts +10 -0
  305. package/dist/systems/skin-palette-types.d.ts.map +1 -1
  306. package/dist/systems/transparent-dispatch.d.ts +2 -2
  307. package/dist/systems/transparent-dispatch.d.ts.map +1 -1
  308. package/dist/systems/transparent-sort-config.d.ts +2 -1
  309. package/dist/systems/transparent-sort-config.d.ts.map +1 -1
  310. package/dist/temporal/gpu.d.ts +13 -1
  311. package/dist/temporal/gpu.d.ts.map +1 -1
  312. package/dist/temporal/index.mjs +6 -7
  313. package/dist/temporal/inspection.d.ts.map +1 -1
  314. package/dist/temporal/standard-scene-data.d.ts.map +1 -1
  315. package/dist/temporal/target-coverage-attachment.d.ts.map +1 -1
  316. package/dist/transmission/single-layer-medium.d.ts +89 -0
  317. package/dist/transmission/single-layer-medium.d.ts.map +1 -0
  318. package/dist/typed-render-graph-primitives.d.ts +14 -2
  319. package/dist/typed-render-graph-primitives.d.ts.map +1 -1
  320. package/dist/volume/component.d.ts +9 -4
  321. package/dist/volume/component.d.ts.map +1 -1
  322. package/dist/volume/extract.d.ts +1 -1
  323. package/dist/volume/extract.d.ts.map +1 -1
  324. package/dist/volume/inspection.d.ts +2 -0
  325. package/dist/volume/inspection.d.ts.map +1 -1
  326. package/dist/volume/passes.d.ts +4 -1
  327. package/dist/volume/passes.d.ts.map +1 -1
  328. package/dist/volume/resources.d.ts.map +1 -1
  329. package/package.json +22 -21
  330. package/src/__tests__/atmosphere-daylight.dawn.test.ts +72 -0
  331. package/src/__tests__/auto-exposure-transaction.integration.test.ts +4 -9
  332. package/src/__tests__/barrel-distortion-lkg.integration.test.ts +353 -0
  333. package/src/__tests__/barrel-distortion.dawn.test.ts +41 -0
  334. package/src/__tests__/barrel-distortion.unit.test.ts +364 -0
  335. package/src/__tests__/construct-renderer-identity.unit.test.ts +49 -0
  336. package/src/__tests__/detached-recovery-graph.unit.test.ts +277 -0
  337. package/src/__tests__/device-feature-admission.unit.test.ts +3 -2
  338. package/src/__tests__/device-loss-fanout.unit.test.ts +36 -1
  339. package/src/__tests__/docs-gate-green.unit.test.ts +112 -1
  340. package/src/__tests__/factory-contract.integration.test.ts +295 -45
  341. package/src/__tests__/feature-depth-input.dawn.test.ts +129 -2
  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-material-artifacts.unit.test.ts +143 -0
  347. package/src/__tests__/gpu-driven-pbr.dawn.test.ts +5 -6
  348. package/src/__tests__/gpu-driven-production.integration.test.ts +482 -3
  349. package/src/__tests__/gpu-driven-shadow-views.dawn.test.ts +6 -5
  350. package/src/__tests__/gpu-driven-view-gpu-evidence.ts +94 -6
  351. package/src/__tests__/gpu-driven-view-graph.integration.test.ts +18 -2
  352. package/src/__tests__/gpu-driven-view.browser.test.ts +5 -8
  353. package/src/__tests__/gpu-driven-view.dawn.test.ts +6 -2
  354. package/src/__tests__/gpu-driven-view.unit.test.ts +1 -1
  355. package/src/__tests__/gpu-pass-timing-lifecycle.integration.test.ts +1 -0
  356. package/src/__tests__/gpu-pass-timing.browser.test.ts +6 -4
  357. package/src/__tests__/gpu-pass-timing.rhi-null.unit.test.ts +1 -0
  358. package/src/__tests__/gpu-scene.unit.test.ts +119 -9
  359. package/src/__tests__/instance-allocation-failure.unit.test.ts +57 -0
  360. package/src/__tests__/instances-culling.integration.test.ts +10 -36
  361. package/src/__tests__/instances-store.unit.test.ts +97 -305
  362. package/src/__tests__/instances-world-ownership.integration.test.ts +62 -0
  363. package/src/__tests__/ktx2-basis-gpu-consumer.dawn.test.ts +4 -1
  364. package/src/__tests__/main-pass-material-medium-selection.unit.test.ts +145 -0
  365. package/src/__tests__/material-shader-prewarm.unit.test.ts +59 -0
  366. package/src/__tests__/material-snapshot-mutation.integration.test.ts +39 -1
  367. package/src/__tests__/materials-standard-contract.unit.test.ts +0 -1
  368. package/src/__tests__/morph-culling-reentry.dawn.test.ts +5 -5
  369. package/src/__tests__/morph-visual-evidence.integration.test.ts +8 -7
  370. package/src/__tests__/motion-blur-compute.dawn.test.ts +13 -7
  371. package/src/__tests__/motion-blur.pixel.integration.test.ts +2 -2
  372. package/src/__tests__/nineslice-handle-surface.unit.test.ts +4 -4
  373. package/src/__tests__/pbr-view-layout.unit.test.ts +9 -0
  374. package/src/__tests__/physical-clearcoat.integration.test.ts +66 -8
  375. package/src/__tests__/physical-material-budget.unit.test.ts +40 -0
  376. package/src/__tests__/prepared-graphics-capability.unit.test.ts +66 -2
  377. package/src/__tests__/probe-bindings.unit.test.ts +582 -1
  378. package/src/__tests__/probe-scene-dirty.integration.test.ts +28 -1
  379. package/src/__tests__/receipt-observation-retirement.unit.test.ts +65 -0
  380. package/src/__tests__/recovery-candidate-prepare.contract.test.ts +69 -0
  381. package/src/__tests__/render-error-code-owner.test-d.ts +8 -0
  382. package/src/__tests__/render-feature-diagnostics.unit.test.ts +15 -2
  383. package/src/__tests__/render-feature-error-reporting.unit.test.ts +21 -1
  384. package/src/__tests__/render-feature-prepared-diagnostics.unit.test.ts +10 -1
  385. package/src/__tests__/render-feature-retry.unit.test.ts +12 -1
  386. package/src/__tests__/render-scene-mixed-updates.integration.test.ts +145 -19
  387. package/src/__tests__/render-scene-projection.unit.test.ts +36 -11
  388. package/src/__tests__/render-scene-temporal-retry.unit.test.ts +20 -20
  389. package/src/__tests__/render-target-probe-soak.perf.test.ts +2 -2
  390. package/src/__tests__/render-temporal-environment-consumer.browser.test.ts +3 -3
  391. package/src/__tests__/render-temporal-environment-consumer.dawn.test.ts +5 -2
  392. package/src/__tests__/renderer-factory-material-contract.unit.test.ts +42 -8
  393. package/src/__tests__/renderer-frame-generation-fence.integration.test.ts +16 -0
  394. package/src/__tests__/renderer-frame-transaction.integration.test.ts +26 -10
  395. package/src/__tests__/resource-allocation.unit.test.ts +123 -0
  396. package/src/__tests__/single-layer-medium-passes.unit.test.ts +275 -0
  397. package/src/__tests__/skin-motion-regression.unit.test.ts +70 -1
  398. package/src/__tests__/skin-palette-recycling.dawn.test.ts +97 -0
  399. package/src/__tests__/skinned-shadow-caster.test.ts +15 -0
  400. package/src/__tests__/ssr-carrier-public-contract.unit.test.ts +21 -0
  401. package/src/__tests__/ssr-gpu-dispatch.browser.test.ts +4 -4
  402. package/src/__tests__/ssr-gpu-dispatch.dawn.test.ts +2 -2
  403. package/src/__tests__/ssr-gpu-dispatch.ts +1 -1
  404. package/src/__tests__/ssr-receiver-coverage.dawn.test.ts +6 -2
  405. package/src/__tests__/standard-output-chain-contract.unit.test.ts +28 -0
  406. package/src/__tests__/standard-pbr-artifact-assembly.unit.test.ts +46 -1
  407. package/src/__tests__/standard-pipeline.integration.test.ts +182 -1
  408. package/src/__tests__/surface-dynamic-buffer-lifecycle.unit.test.ts +506 -0
  409. package/src/__tests__/surface-submission-observation.unit.test.ts +812 -0
  410. package/src/__tests__/temporal-history-lifecycle.unit.test.ts +32 -0
  411. package/src/__tests__/temporal-performance.integration.test.ts +3 -3
  412. package/src/__tests__/visibility-instances.integration.test.ts +7 -19
  413. package/src/__tests__/visibility-producer-matrix.integration.test.ts +9 -20
  414. package/src/__tests__/volume-optics-oracle.unit.test.ts +4 -2
  415. package/src/__tests__/volumetric-fog-budget-recovery.integration.test.ts +30 -20
  416. package/src/__tests__/volumetric-fog-errors.unit.test.ts +4 -3
  417. package/src/__tests__/volumetric-fog-multiple.unit.test.ts +55 -0
  418. package/src/__tests__/volumetric-fog-spot-frame-optics.integration.test.ts +1 -1
  419. package/src/__tests__/volumetric-fog-stage-readback.dawn.test.ts +113 -9
  420. package/src/__tests__/volumetric-fog-topology.unit.test.ts +5 -3
  421. package/src/assembly/backend-contract.ts +30 -0
  422. package/src/assembly/barrel-distortion-inspection.ts +22 -0
  423. package/src/assembly/canvas-draw-guard.ts +11 -0
  424. package/src/assembly/cloud-shadow-entry.ts +22 -0
  425. package/src/assembly/device-feature-admission.ts +2 -2
  426. package/src/assembly/dynamic-geometry-host.ts +65 -37
  427. package/src/assembly/dynamic-geometry-runtime.ts +7 -1
  428. package/src/assembly/factory.ts +2 -30
  429. package/src/assembly/host-contract.ts +8 -5
  430. package/src/assembly/material/assembly.ts +25 -13
  431. package/src/assembly/material/pipeline-helpers.ts +53 -12
  432. package/src/assembly/material-shader-policy.ts +55 -0
  433. package/src/assembly/material-shader-prewarm.ts +21 -10
  434. package/src/assembly/recovery/device-loss-fanout.ts +13 -0
  435. package/src/assembly/recovery/renderer-recover.ts +50 -18
  436. package/src/assembly/render-feature-post-processes.ts +54 -0
  437. package/src/assembly/render-target-host.ts +57 -47
  438. package/src/assembly/renderer-facade.ts +7 -2
  439. package/src/assembly/renderer-feature-inspection.ts +8 -2
  440. package/src/assembly/renderer-frame-transaction.ts +23 -0
  441. package/src/assembly/renderer-inspection.ts +28 -0
  442. package/src/assembly/skin-palette-owner.ts +1 -1
  443. package/src/assembly/temporal-post-process-prewarm.ts +3 -3
  444. package/src/assembly/webgpu-pbr-ready.ts +9 -1
  445. package/src/assembly/webgpu-ready-per-pass.ts +104 -0
  446. package/src/assembly/webgpu-ready.ts +116 -62
  447. package/src/assembly/webgpu-renderer-bootstrap.ts +0 -12
  448. package/src/assembly/webgpu-renderer-observation-owner.ts +222 -0
  449. package/src/assembly/webgpu-renderer.ts +303 -313
  450. package/src/assembly/webgpu-vertex-layouts.ts +1 -1
  451. package/src/barrel-distortion.ts +247 -0
  452. package/src/cloud/__tests__/cloud-density-parity.dawn.test.ts +173 -0
  453. package/src/cloud/__tests__/cloud-layer-framebuffer-y.dawn.test.ts +265 -0
  454. package/src/cloud/__tests__/cloud-layer.browser.test.ts +432 -0
  455. package/src/cloud/__tests__/cloud-layer.unit.test.ts +634 -0
  456. package/src/cloud/density.ts +600 -0
  457. package/src/cloud/extract.ts +110 -0
  458. package/src/cloud/feature.ts +1810 -0
  459. package/src/cloud/frame-context.ts +42 -0
  460. package/src/cloud/inspection.ts +130 -0
  461. package/src/cloud/optics.ts +285 -0
  462. package/src/cloud/parameters.ts +255 -0
  463. package/src/cloud/resources.ts +122 -0
  464. package/src/cloud/shadow.ts +167 -0
  465. package/src/cloud/temporal.ts +226 -0
  466. package/src/components/barrel-distortion.ts +46 -0
  467. package/src/components/cloud-layer.ts +47 -0
  468. package/src/components/index.ts +2 -0
  469. package/src/components/instances.ts +18 -45
  470. package/src/components/sprite-instances.ts +1 -1
  471. package/src/construct-renderer.ts +1 -1
  472. package/src/device/gpu-residency.ts +26 -25
  473. package/src/dynamic-geometry.ts +12 -1
  474. package/src/errors/cloud.ts +103 -0
  475. package/src/errors/render.ts +47 -8
  476. package/src/examples/single-layer-medium-surface.ts +59 -0
  477. package/src/extract/camera.ts +15 -1
  478. package/src/extract/contracts.ts +5 -0
  479. package/src/extract/material-context.ts +21 -0
  480. package/src/features/barrel-distortion.ts +172 -0
  481. package/src/features/error-reporting.ts +26 -6
  482. package/src/features/host.ts +128 -19
  483. package/src/features/plan.ts +10 -0
  484. package/src/features/render-graph-contribution.ts +9 -0
  485. package/src/features/render-graph-raster.ts +45 -3
  486. package/src/features/targets.ts +66 -0
  487. package/src/features/types.ts +51 -0
  488. package/src/fullscreen-post-process-pass.ts +41 -9
  489. package/src/glyph-text-layout-system.ts +2 -2
  490. package/src/gpu-dirty-ranges.ts +48 -0
  491. package/src/gpu-driven/batch-topology.ts +53 -0
  492. package/src/gpu-driven/material-artifacts.ts +33 -25
  493. package/src/gpu-driven/prepared-draw.ts +12 -4
  494. package/src/gpu-driven/production-raster-material.ts +1894 -0
  495. package/src/gpu-driven/production-raster.ts +825 -784
  496. package/src/gpu-driven/resource-allocation.ts +142 -0
  497. package/src/gpu-driven/shadow-ownership.ts +71 -0
  498. package/src/gpu-driven/view-gpu.ts +164 -10
  499. package/src/gpu-scene.ts +75 -84
  500. package/src/hdrp-buffers.ts +4 -3
  501. package/src/ibl/frame-resources.ts +0 -1
  502. package/src/ibl/skylight-bind-group.ts +62 -32
  503. package/src/index.ts +205 -9
  504. package/src/inspection-types.ts +162 -0
  505. package/src/instance-buffer-cache.ts +4 -4
  506. package/src/instances.ts +152 -569
  507. package/src/pbr-pipeline.ts +230 -30
  508. package/src/pipeline/single-layer-medium-passes.ts +267 -0
  509. package/src/pipeline/standard-forward-lane.ts +313 -57
  510. package/src/pipeline/standard-output/graph.ts +8 -2
  511. package/src/pipeline/standard-output/lut-gpu.ts +3 -3
  512. package/src/pipeline/standard-output/resources.ts +2 -2
  513. package/src/pipeline/standard-output/types.ts +12 -1
  514. package/src/pipeline/standard-pipeline.ts +291 -18
  515. package/src/pipeline/standard-post.ts +90 -24
  516. package/src/pipeline-builder.ts +1 -1
  517. package/src/plugin.ts +4 -0
  518. package/src/points-lines/__tests__/points-lines.bench.ts +17 -8
  519. package/src/prepare/prepared-graphics-resolver.ts +2 -0
  520. package/src/publication/__tests__/derived-geometry.integration.test.ts +177 -0
  521. package/src/publication/__tests__/features.integration.test.ts +122 -0
  522. package/src/publication/__tests__/programs.unit.test.ts +25 -0
  523. package/src/publication/__tests__/publication.integration.test.ts +370 -0
  524. package/src/publication/__tests__/targets.integration.test.ts +120 -0
  525. package/src/publication/__tests__/video.browser.test.ts +50 -0
  526. package/src/publication/contract.ts +104 -0
  527. package/src/publication/dependencies.ts +54 -0
  528. package/src/publication/prepare-geometry.ts +94 -0
  529. package/src/publication/programs.ts +45 -0
  530. package/src/publication/publisher.ts +618 -0
  531. package/src/publication/receiver.ts +297 -0
  532. package/src/publication/resource-scope.ts +31 -0
  533. package/src/publication/targets.ts +182 -0
  534. package/src/publication/video.ts +33 -0
  535. package/src/record/__tests__/main-pass-geometry.unit.test.ts +30 -0
  536. package/src/record/__tests__/material-bg-cache.unit.test.ts +15 -1
  537. package/src/record/__tests__/sprite-material-abi.unit.test.ts +9 -11
  538. package/src/record/__tests__/temporal-payload.unit.test.ts +1 -1
  539. package/src/record/__tests__/transparent-group2-selection.unit.test.ts +11 -0
  540. package/src/record/__tests__/typed-frame-graph-plan.unit.test.ts +1 -0
  541. package/src/record/__tests__/video-texture-view.unit.test.ts +9 -9
  542. package/src/record/__tests__/view-ubo-layout.unit.test.ts +4 -3
  543. package/src/record/barrel-distortion-frame.ts +110 -0
  544. package/src/record/dynamic-geometry-consumption.ts +39 -9
  545. package/src/record/fold-buckets.ts +855 -0
  546. package/src/record/fold-instance-buffer.ts +51 -0
  547. package/src/record/frame-lighting.ts +36 -2
  548. package/src/record/frame-snapshot.ts +45 -9
  549. package/src/record/frame.ts +258 -1105
  550. package/src/record/gpu-draw-receipts.ts +38 -0
  551. package/src/record/gpu-timing.ts +48 -5
  552. package/src/record/helpers.ts +2 -2
  553. package/src/record/main-pass-geometry.ts +272 -84
  554. package/src/record/main-pass-material.ts +102 -36
  555. package/src/record/main-pass-sprite-draws.ts +13 -217
  556. package/src/record/main-pass.ts +164 -27
  557. package/src/record/motion-blur-receipt.ts +91 -0
  558. package/src/record/prepared-material-bindings.ts +11 -6
  559. package/src/record/probe-blend-buffer.ts +180 -0
  560. package/src/record/recovery-pipeline.ts +35 -3
  561. package/src/record/render-context.ts +41 -5
  562. package/src/record/shadow-pass.ts +30 -4
  563. package/src/record/skybox-post-pass.ts +28 -4
  564. package/src/record/sprite-instance-buffer.ts +155 -0
  565. package/src/record/target-capture-graph.ts +258 -0
  566. package/src/record/typed-frame-graph.ts +776 -340
  567. package/src/record/view-ubo.ts +27 -4
  568. package/src/record/volume-params.ts +225 -0
  569. package/src/recovery/render-system-candidate.ts +243 -50
  570. package/src/reflection/record-owner.ts +7 -3
  571. package/src/render-contract.ts +54 -5
  572. package/src/render-graph-primitives.ts +7 -1
  573. package/src/render-pipeline.ts +130 -0
  574. package/src/render-system-extract-tail.ts +90 -78
  575. package/src/render-system-extract.ts +76 -76
  576. package/src/render-system-presentation.ts +56 -0
  577. package/src/render-system-producer-roots.ts +96 -0
  578. package/src/render-system-projections.ts +3 -2
  579. package/src/render-system-residency.ts +159 -0
  580. package/src/render-system.ts +421 -408
  581. package/src/scene/probe-blend.ts +96 -4
  582. package/src/scene/render-scene.ts +416 -337
  583. package/src/scene/render-source.ts +90 -0
  584. package/src/scene/source-systems.ts +33 -0
  585. package/src/ssao-buffers.ts +95 -2
  586. package/src/surface/__tests__/dynamic-input.unit.test.ts +374 -0
  587. package/src/surface/__tests__/gpu-driven.unit.test.ts +87 -0
  588. package/src/surface/dynamic-input.ts +658 -0
  589. package/src/surface/gpu-driven.ts +147 -0
  590. package/src/surface/submission-observation.ts +517 -0
  591. package/src/systems/skin-palette-allocator.ts +5 -1
  592. package/src/systems/skin-palette-types.ts +11 -0
  593. package/src/systems/transparent-dispatch.ts +2 -2
  594. package/src/systems/transparent-sort-config.ts +3 -1
  595. package/src/temporal/gpu.ts +101 -17
  596. package/src/temporal/inspection.ts +7 -1
  597. package/src/temporal/standard-scene-data.ts +5 -0
  598. package/src/temporal/target-coverage-attachment.ts +4 -0
  599. package/src/transmission/__tests__/single-layer-medium.unit.test.ts +149 -0
  600. package/src/transmission/__tests__/standard-transmission.dawn.test.ts +12 -11
  601. package/src/transmission/single-layer-medium.ts +322 -0
  602. package/src/typed-render-graph-primitives.ts +70 -2
  603. package/src/volume/component.ts +10 -9
  604. package/src/volume/extract.ts +11 -5
  605. package/src/volume/inspection.ts +3 -0
  606. package/src/volume/passes.ts +87 -4
  607. package/src/volume/resources.ts +2 -1
  608. package/dist/chunk-3RTCJTH4.mjs +0 -1610
  609. package/dist/chunk-3RTCJTH4.mjs.map +0 -1
  610. package/dist/chunk-BLXGONR2.mjs.map +0 -1
  611. package/dist/chunk-ILQ5MEZF.mjs +0 -32
  612. package/dist/chunk-ILQ5MEZF.mjs.map +0 -1
  613. package/dist/chunk-LEAXOMYJ.mjs.map +0 -1
  614. package/dist/chunk-NB2S7ZRX.mjs +0 -1783
  615. package/dist/chunk-NB2S7ZRX.mjs.map +0 -1
  616. package/dist/chunk-NNQL7CB3.mjs +0 -1713
  617. package/dist/chunk-NNQL7CB3.mjs.map +0 -1
  618. package/dist/chunk-OO3DRYK7.mjs.map +0 -1
  619. package/dist/chunk-PA5DRJNI.mjs.map +0 -1
  620. package/dist/chunk-PLAXOOX5.mjs +0 -1907
  621. package/dist/chunk-PLAXOOX5.mjs.map +0 -1
  622. package/dist/chunk-RXZ3RGOU.mjs +0 -53
  623. package/dist/chunk-RXZ3RGOU.mjs.map +0 -1
  624. package/dist/chunk-VOZWDM3L.mjs.map +0 -1
@@ -1,8 +1,8 @@
1
- import type { World } from '@forgeax/engine-ecs';
2
1
  import { probeVideoHighPerfUpload } from '@forgeax/engine-graphics-extras';
3
2
  import type { GraphResourceResolver } from '@forgeax/engine-render-graph';
4
3
  import {
5
4
  type BindGroup,
5
+ type Buffer,
6
6
  RhiError,
7
7
  type RhiRenderPassEncoder,
8
8
  type TextureView,
@@ -10,6 +10,7 @@ import {
10
10
  import type { PassKind, PassSelector } from '@forgeax/engine-types';
11
11
  import {
12
12
  createGpuDrivenLightingBindGroup,
13
+ createHdrpSkinUnifiedBindGroup,
13
14
  createHdrpUnifiedBindGroup,
14
15
  getOrCreateHdrpBuffers,
15
16
  } from '../hdrp-buffers';
@@ -17,10 +18,12 @@ import { getOrCreateIblCache } from '../ibl/IblPipelineCache';
17
18
  import type { SkylightBindGroupResources } from '../ibl/skylight-bind-group';
18
19
  import { buildBeginRenderPassDescriptor, standardTopologyBindGroupReady } from '../pipeline-spec';
19
20
  import { POINTS_LINES_MATERIAL_SHADER_ID } from '../points-lines/record';
21
+ import type { RenderResourceScope } from '../publication/resource-scope';
20
22
  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),
@@ -414,7 +529,7 @@ export function recordMainPass(
414
529
  identities: [
415
530
  getOpaqueResourceIdentity(skylightResources.irradianceSampler as object),
416
531
  getOpaqueResourceIdentity(skylightResources.prefilterSampler as object),
417
- getOpaqueResourceIdentity(skylightResources.brdfLutSampler as object),
532
+ getOpaqueResourceIdentity(skylightResources.irradianceSampler as object),
418
533
  ],
419
534
  },
420
535
  resources: {
@@ -434,7 +549,9 @@ export function recordMainPass(
434
549
  },
435
550
  brdfLut: {
436
551
  viewIdentity: getOpaqueResourceIdentity(skylightResources.brdfLutView as object),
437
- samplerIdentity: getOpaqueResourceIdentity(skylightResources.brdfLutSampler as object),
552
+ samplerIdentity: getOpaqueResourceIdentity(
553
+ skylightResources.irradianceSampler as object,
554
+ ),
438
555
  deviceGeneration: runtime.deviceScope.generation,
439
556
  },
440
557
  intensityBufferIdentity: getOpaqueResourceIdentity(
@@ -475,7 +592,7 @@ export function recordMainPass(
475
592
  // which cannot render a PBR decal). Captures only frame-stable closure
476
593
  // state; the caller passes the per-submesh material snapshot + entityKey
477
594
  // (for video texture routing) and sets the dynamic UBO offset itself.
478
- // Selection keys use the extracted frame index, never World.identity.
595
+ // Selection keys use the extracted frame index, never RenderResourceScope.identity.
479
596
  const hasProbeBindings = (c.reflectionProbes?.table.rows.length ?? 0) > 0;
480
597
  const worldIndices = hasProbeBindings
481
598
  ? new Map(
@@ -517,7 +634,6 @@ export function recordMainPass(
517
634
  skylightPrefilterView: skylightResources.prefilterView,
518
635
  prefilterSampler: row.sampler,
519
636
  brdfLutView: skylightResources.brdfLutView,
520
- brdfLutSampler: skylightResources.brdfLutSampler,
521
637
  intensityBuffer: row.uniformBuffer,
522
638
  };
523
639
  return { resources: probeResources, probeIndex: row.index };
@@ -535,11 +651,14 @@ export function recordMainPass(
535
651
  gpuDrivenSceneMaterialBuffer,
536
652
  }),
537
653
  ...(transmissionBackdropView === undefined ? {} : { transmissionBackdropView }),
654
+ ...(surfaceRawDepthView === undefined ? {} : { surfaceRawDepthView }),
655
+ ...(surfaceNearestLayerView === undefined ? {} : { surfaceNearestLayerView }),
656
+ ...(surfaceNearestDepthView === undefined ? {} : { surfaceNearestDepthView }),
538
657
  };
539
658
  const buildPerSubmeshMaterialBg = (
540
659
  submeshMaterial: MaterialSnapshot,
541
660
  entityKey: number,
542
- materialWorld: World = world,
661
+ materialWorld: RenderResourceScope = world,
543
662
  materialShaderId: string | undefined = submeshMaterial.materialShaderId,
544
663
  ): BindGroup =>
545
664
  buildPerSubmeshMaterialBgImpl(
@@ -558,6 +677,12 @@ export function recordMainPass(
558
677
  for (let materialSlot = 0; materialSlot < materialSlotCount; materialSlot += 1) {
559
678
  const material = materialSlots[materialSlot];
560
679
  if (material === undefined || (material.videoTextureFields?.size ?? 0) > 0) continue;
680
+ // A graph scene pass owns only the materials selected by its record
681
+ // mode. In particular, the opaque pass runs before the raw-depth
682
+ // producer and must not assemble medium bindings with resources that do
683
+ // not exist until the later nearest-layer/color passes. Keep holes for
684
+ // the other lanes; the GPU encoder validates the exact slot it consumes.
685
+ if (recordMode !== undefined && !matchesRecordMode(material, recordMode)) continue;
561
686
  const owner = materialSlotOwners[materialSlot];
562
687
  if (owner === undefined) continue;
563
688
  preparedMaterialBindGroups[materialSlot] = buildPerSubmeshMaterialBg(
@@ -624,7 +749,7 @@ export function recordMainPass(
624
749
  materialSlot: number,
625
750
  material: MaterialSnapshot,
626
751
  entityKey: number,
627
- materialWorld: World = world,
752
+ materialWorld: RenderResourceScope = world,
628
753
  materialShaderId: string | undefined = material.materialShaderId,
629
754
  ): BindGroup =>
630
755
  !hasProbeBindings &&
@@ -656,6 +781,13 @@ export function recordMainPass(
656
781
  selectedDispatch,
657
782
  colorFormats,
658
783
  options?.coverageOnly ?? false,
784
+ options?.fragmentEntryPoint,
785
+ recordMode === 'single-layer-medium-nearest-layer'
786
+ ? 'nearest-layer'
787
+ : recordMode === 'single-layer-medium-color'
788
+ ? 'color'
789
+ : undefined,
790
+ options?.transparentDepthWrite ?? false,
659
791
  );
660
792
  };
661
793
  if (c.profilePhase === undefined) {
@@ -676,7 +808,10 @@ export function recordMainPass(
676
808
  hint: 'publish the current frame view/light/shadow bind group before GPU raster',
677
809
  });
678
810
  }
679
- if (gpuDrivenStandardPbrFrameResources === undefined) {
811
+ if (
812
+ gpuDrivenStandardPbrFrameResources === undefined ||
813
+ gpuDrivenStandardPbrFrameResources.materialBindGroups.length === 0
814
+ ) {
680
815
  throw new RhiError({
681
816
  code: 'rhi-not-available',
682
817
  expected: 'complete main-pass Standard PBR material bind-group receipt',
@@ -688,6 +823,8 @@ export function recordMainPass(
688
823
  pass,
689
824
  options.gpuDriven.resources,
690
825
  gpuDrivenStandardPbrFrameResources,
826
+ options.gpuDrivenFilter,
827
+ options?.fragmentEntryPoint,
691
828
  );
692
829
  }
693
830
 
@@ -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
+ }
@@ -1,5 +1,4 @@
1
1
  import { resolveAssetHandle } from '@forgeax/engine-assets-runtime';
2
- import type { World } from '@forgeax/engine-ecs';
3
2
  import type { BindGroupEntry, BindGroupLayout, Buffer } from '@forgeax/engine-rhi';
4
3
  import { err, ok } from '@forgeax/engine-rhi';
5
4
  import {
@@ -14,6 +13,8 @@ import { transmissionBackdropAvailable } from '../assembly/device-feature-admiss
14
13
  import { GPU_BUFFER_USAGE_COPY_DST, GPU_BUFFER_USAGE_UNIFORM } from '../gpu-usage';
15
14
  import type { SkylightBindGroupResources } from '../ibl/skylight-bind-group';
16
15
  import { assembleMaterialWithSkylightEntries } from '../ibl/skylight-bind-group';
16
+ import type { RenderResourceScope } from '../publication/resource-scope';
17
+ import { renderAssetByGuid } from '../publication/resource-scope';
17
18
  import {
18
19
  applyParamSchemaDefaultsToUbo,
19
20
  applyParamSnapshotToUbo,
@@ -28,7 +29,7 @@ export type PreparedResolverCaches = {
28
29
  readonly preparedGroup0Pipelines: WeakSet<object>;
29
30
  readonly preparedViewOnlyPipelines: WeakSet<object>;
30
31
  readonly preparedRenderMaterialPipelines: WeakSet<object>;
31
- readonly preparedAssetHandles: WeakMap<World, Map<string, number>>;
32
+ readonly preparedAssetHandles: WeakMap<RenderResourceScope, Map<string, number>>;
32
33
  };
33
34
 
34
35
  export function createPreparedResolverCaches(): PreparedResolverCaches {
@@ -45,7 +46,7 @@ export function createPreparedResolverCaches(): PreparedResolverCaches {
45
46
  function preparedHandle<Brand extends string>(
46
47
  runtime: RenderSystemInternals,
47
48
  caches: PreparedResolverCaches,
48
- world: World,
49
+ world: RenderResourceScope,
49
50
  guid: string,
50
51
  brand: Brand,
51
52
  ): Handle<Brand, 'shared'> | undefined {
@@ -57,6 +58,8 @@ function preparedHandle<Brand extends string>(
57
58
  const key = `${brand}:${guid.toLowerCase()}`;
58
59
  const cached = handles.get(key);
59
60
  if (cached !== undefined) return cached as Handle<Brand, 'shared'>;
61
+ if ('resolveAsset' in world)
62
+ return world.handleForGuid(guid) as Handle<Brand, 'shared'> | undefined;
60
63
  const asset = runtime.assets.lookup(guid);
61
64
  if (asset === undefined) return undefined;
62
65
  const handle = world.allocSharedRef(brand, asset);
@@ -67,7 +70,7 @@ function preparedHandle<Brand extends string>(
67
70
  export function preparedMaterialBindings(
68
71
  runtime: RenderSystemInternals,
69
72
  caches: PreparedResolverCaches,
70
- worlds: readonly World[],
73
+ worlds: readonly RenderResourceScope[],
71
74
  materialShaderId: string,
72
75
  worldIndex: number,
73
76
  materialGuid: string,
@@ -75,7 +78,10 @@ export function preparedMaterialBindings(
75
78
  skylightResources?: SkylightBindGroupResources,
76
79
  ) {
77
80
  const world = worlds[worldIndex];
78
- const material = runtime.assets.lookup(materialGuid) as MaterialAsset | undefined;
81
+ const material =
82
+ world === undefined
83
+ ? undefined
84
+ : renderAssetByGuid<MaterialAsset>(world, runtime.assets, materialGuid);
79
85
  const pipelineState = runtime.getPipelineState();
80
86
  if (world === undefined || material?.kind !== 'material' || pipelineState === null) {
81
87
  return err(new Error('prepared material asset is unavailable'));
@@ -203,7 +209,6 @@ export function preparedMaterialBindings(
203
209
  prefilterView: fallback.prefilterView,
204
210
  prefilterSampler: fallback.sampler,
205
211
  brdfLutView: fallback.brdfLutView,
206
- brdfLutSampler: fallback.sampler,
207
212
  intensityBuffer: fallback.intensityBuffer,
208
213
  },
209
214
  transmissionBackdropAvailable(runtime.device.limits.maxSampledTexturesPerShaderStage)
@@ -0,0 +1,180 @@
1
+ import type { Buffer, RhiDevice } from '@forgeax/engine-rhi';
2
+ import { GpuBuffer } from '../gpu-resource';
3
+ import {
4
+ GPU_BUFFER_USAGE_COPY_DST,
5
+ GPU_BUFFER_USAGE_STORAGE,
6
+ GPU_BUFFER_USAGE_UNIFORM,
7
+ } from '../gpu-usage';
8
+ import type { ProbeBlendBufferProjection } from '../scene/probe-blend';
9
+ import {
10
+ PROBE_BLEND_RECORD_STRIDE,
11
+ type ProbeBlendRecord,
12
+ probeBlendRecordOffset,
13
+ } from '../scene/probe-blend-record';
14
+ import type { RenderFrameState } from './frame-snapshot';
15
+
16
+ export interface ProbeBlendBufferRecord {
17
+ readonly cacheKey: number;
18
+ readonly record: ProbeBlendRecord;
19
+ }
20
+
21
+ function isProbeBlendProjection(
22
+ input: ProbeBlendBufferProjection | readonly ProbeBlendBufferRecord[],
23
+ ): input is ProbeBlendBufferProjection {
24
+ return !Array.isArray(input);
25
+ }
26
+
27
+ function retireProbeBlendRecordBuffer(buffer: GpuBuffer): void {
28
+ const destroy = (): void => {
29
+ if (!buffer.isDestroyed) void buffer.destroy();
30
+ };
31
+ void buffer.device.queue.onSubmittedWorkDone().then(destroy, destroy);
32
+ }
33
+
34
+ function createCompleteProbeBlendBuffer(
35
+ device: RhiDevice,
36
+ requiredCapacity: number,
37
+ records: readonly ProbeBlendBufferRecord[],
38
+ ): {
39
+ readonly buffer: GpuBuffer;
40
+ readonly cache: ReadonlyMap<number, { readonly generation: number; readonly bytes: Uint8Array }>;
41
+ } {
42
+ const created = device.createBuffer({
43
+ label: 'probe-blend-records',
44
+ size: requiredCapacity * PROBE_BLEND_RECORD_STRIDE,
45
+ usage:
46
+ (device.caps.storageBuffer ? GPU_BUFFER_USAGE_STORAGE : GPU_BUFFER_USAGE_UNIFORM) |
47
+ GPU_BUFFER_USAGE_COPY_DST,
48
+ mappedAtCreation: false,
49
+ });
50
+ if (!created.ok) throw created.error;
51
+ const candidate = new GpuBuffer(device, created.value);
52
+ const cache = new Map<number, { readonly generation: number; readonly bytes: Uint8Array }>();
53
+ try {
54
+ for (const { cacheKey, record } of records) {
55
+ const uploaded = device.queue.writeBuffer(
56
+ candidate.handle,
57
+ probeBlendRecordOffset(record.objectKey),
58
+ record.bytes,
59
+ );
60
+ if (!uploaded.ok) throw uploaded.error;
61
+ cache.set(cacheKey, {
62
+ generation: record.generation,
63
+ bytes: new Uint8Array(record.bytes),
64
+ });
65
+ }
66
+ } catch (cause) {
67
+ void candidate.destroy();
68
+ throw cause;
69
+ }
70
+ return { buffer: candidate, cache };
71
+ }
72
+
73
+ /**
74
+ * Retain one device buffer for direct and scene-index ProbeBlend consumers.
75
+ * Capacity is settled before any upload so a growth cannot erase records
76
+ * written earlier in the same frame. Slot zero remains the producer sentinel;
77
+ * RenderScene object slot N occupies aligned record N+1.
78
+ */
79
+ export function ensureProbeBlendRecordBuffer(
80
+ device: RhiDevice,
81
+ frameState: Pick<
82
+ RenderFrameState,
83
+ | 'probeBlendRecordBuffer'
84
+ | 'probeBlendRecordBufferCapacity'
85
+ | 'probeBlendBuffers'
86
+ | 'probeBlendRecordProjection'
87
+ >,
88
+ input: ProbeBlendBufferProjection | readonly ProbeBlendBufferRecord[] | undefined,
89
+ ): Buffer | undefined {
90
+ const projection = input !== undefined && isProbeBlendProjection(input) ? input : undefined;
91
+ const records: readonly ProbeBlendBufferRecord[] =
92
+ input === undefined
93
+ ? []
94
+ : (projection?.records ?? (input as readonly ProbeBlendBufferRecord[]));
95
+ let buffer = frameState.probeBlendRecordBuffer;
96
+ const accepted = frameState.probeBlendRecordProjection;
97
+ if (
98
+ projection !== undefined &&
99
+ accepted?.projection === projection &&
100
+ accepted.device === device
101
+ ) {
102
+ if (records.length === 0) return undefined;
103
+ if (accepted.buffer === buffer && buffer !== undefined && !buffer.isDestroyed) {
104
+ return buffer.handle;
105
+ }
106
+ }
107
+ if (records.length === 0) {
108
+ if (projection !== undefined) {
109
+ frameState.probeBlendBuffers.clear();
110
+ frameState.probeBlendRecordProjection = {
111
+ projection,
112
+ device,
113
+ buffer: undefined,
114
+ };
115
+ }
116
+ return undefined;
117
+ }
118
+ const requiredCapacity =
119
+ projection?.capacity ??
120
+ records.reduce((capacity, { record }) => Math.max(capacity, record.objectKey + 2), 1);
121
+ const grows =
122
+ buffer === undefined ||
123
+ buffer.isDestroyed ||
124
+ buffer.device !== device ||
125
+ frameState.probeBlendRecordBufferCapacity < requiredCapacity;
126
+ const hasAcceptedBaseline =
127
+ projection !== undefined &&
128
+ accepted !== undefined &&
129
+ accepted.device === device &&
130
+ accepted.buffer === buffer &&
131
+ buffer !== undefined &&
132
+ !buffer.isDestroyed &&
133
+ accepted.projection.sourceIdentity === projection.sourceIdentity &&
134
+ accepted.projection.revision === projection.baseRevision;
135
+ const requiresCompletePublish =
136
+ grows ||
137
+ (projection !== undefined && (!hasAcceptedBaseline || projection.dirtyRecords.length > 1));
138
+ if (requiresCompletePublish) {
139
+ const candidate = createCompleteProbeBlendBuffer(device, requiredCapacity, records);
140
+ const previous = buffer;
141
+ buffer = candidate.buffer;
142
+ frameState.probeBlendRecordBuffer = candidate.buffer;
143
+ frameState.probeBlendRecordBufferCapacity = requiredCapacity;
144
+ frameState.probeBlendBuffers.clear();
145
+ for (const [key, value] of candidate.cache) frameState.probeBlendBuffers.set(key, value);
146
+ if (projection === undefined) delete frameState.probeBlendRecordProjection;
147
+ else frameState.probeBlendRecordProjection = { projection, device, buffer: candidate.buffer };
148
+ if (previous !== undefined) retireProbeBlendRecordBuffer(previous);
149
+ return candidate.buffer.handle;
150
+ }
151
+ if (buffer === undefined) return undefined;
152
+ const changed = projection?.dirtyRecords ?? records;
153
+ const cacheUpdates: [number, { readonly generation: number; readonly bytes: Uint8Array }][] = [];
154
+ for (const { cacheKey, record } of changed) {
155
+ const cached = frameState.probeBlendBuffers.get(cacheKey);
156
+ const unchanged =
157
+ cached !== undefined &&
158
+ cached.generation === record.generation &&
159
+ cached.bytes.length === record.bytes.length &&
160
+ cached.bytes.every((value, index) => value === record.bytes[index]);
161
+ if (unchanged) continue;
162
+ const uploaded = device.queue.writeBuffer(
163
+ buffer.handle,
164
+ probeBlendRecordOffset(record.objectKey),
165
+ record.bytes,
166
+ );
167
+ if (!uploaded.ok) throw uploaded.error;
168
+ cacheUpdates.push([
169
+ cacheKey,
170
+ { generation: record.generation, bytes: new Uint8Array(record.bytes) },
171
+ ]);
172
+ }
173
+ for (const [cacheKey, value] of cacheUpdates) frameState.probeBlendBuffers.set(cacheKey, value);
174
+ for (const cacheKey of projection?.removedCacheKeys ?? []) {
175
+ frameState.probeBlendBuffers.delete(cacheKey);
176
+ }
177
+ if (projection === undefined) delete frameState.probeBlendRecordProjection;
178
+ else frameState.probeBlendRecordProjection = { projection, device, buffer };
179
+ return buffer.handle;
180
+ }