@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
@@ -3,6 +3,7 @@ import { createShaderModule, rhi } from '@forgeax/engine-rhi-webgpu';
3
3
  import { buildEngineShaderManifest } from '@forgeax/engine-vite-plugin-shader';
4
4
  import { describe, expect, it } from 'vitest';
5
5
  import { BYTES_PER_DIRECT_LIGHT_SLOT } from '../light-buffer-layout';
6
+ import { VIEW_UNIFORM_BYTES } from '../record/view-ubo';
6
7
  import { VOLUMETRIC_FOG_PARAMS_BYTES } from '../volume/resources';
7
8
 
8
9
  const MAP_READ = 0x0001;
@@ -42,6 +43,10 @@ interface VolumeStageReadbacks {
42
43
  }
43
44
 
44
45
  interface StageReadbackOptions {
46
+ readonly owners?: number;
47
+ readonly secondDensity?: number;
48
+ readonly thinSeparated?: boolean;
49
+ readonly reverse?: boolean;
45
50
  readonly sceneDepthClear?: number;
46
51
  readonly densityByte?: number;
47
52
  /** Optional RGBA8 density field for the production integrate stage. */
@@ -232,6 +237,7 @@ async function runInjectReadback(
232
237
  const frameIndex = options.frameIndex ?? 0;
233
238
  const shadowDepthClear = options.shadowDepthClear ?? 1;
234
239
  const integratorStepCount = options.integratorStepCount;
240
+ const owners = options.owners ?? 1;
235
241
  const device = await requestDevice();
236
242
  const moduleResult = await createShaderModule(device, {
237
243
  code: manifestShader('fn volume_inject'),
@@ -271,9 +277,17 @@ async function runInjectReadback(
271
277
  usage: TEXTURE_BINDING | TEXTURE_COPY_DST,
272
278
  textureBindingViewDimension: undefined,
273
279
  });
280
+ const secondDensityTexture = device.createTexture({
281
+ label: 'stage-readback.second-density',
282
+ size: { width: SIZE, height: SIZE, depthOrArrayLayers: SIZE },
283
+ dimension: '3d',
284
+ format: 'rgba8unorm',
285
+ usage: TEXTURE_BINDING | TEXTURE_COPY_DST,
286
+ textureBindingViewDimension: undefined,
287
+ });
274
288
  const outputTexture = device.createTexture({
275
289
  label: 'stage-readback.froxel',
276
- size: { width: SIZE, height: SIZE, depthOrArrayLayers: PACKED_LAYERS },
290
+ size: { width: SIZE, height: SIZE, depthOrArrayLayers: PACKED_LAYERS * owners },
277
291
  dimension: '2d',
278
292
  format: 'rgba8unorm',
279
293
  usage: STORAGE_BINDING | TEXTURE_COPY_SRC | TEXTURE_BINDING,
@@ -318,6 +332,7 @@ async function runInjectReadback(
318
332
  !sceneDepthTexture.ok ||
319
333
  !shadowTexture.ok ||
320
334
  !densityTexture.ok ||
335
+ !secondDensityTexture.ok ||
321
336
  !outputTexture.ok ||
322
337
  !historyTexture.ok ||
323
338
  !temporalTexture.ok ||
@@ -331,6 +346,7 @@ async function runInjectReadback(
331
346
  if (!sceneDepthView.ok || !shadowView.ok)
332
347
  throw new Error('Dawn volume stage readback unavailable: depth view allocation failed');
333
348
  const densityView = createView(device, densityTexture.value, '3d');
349
+ const secondDensityView = createView(device, secondDensityTexture.value, '3d');
334
350
  const outputView = createView(device, outputTexture.value, '2d-array');
335
351
  const historyView = createView(device, historyTexture.value, '2d');
336
352
  const temporalView = createView(device, temporalTexture.value, '2d');
@@ -338,7 +354,7 @@ async function runInjectReadback(
338
354
  const projectorView = createView(device, projectorTexture.value, '2d');
339
355
  const viewBuffer = device.createBuffer({
340
356
  label: 'stage-readback.view',
341
- size: 960,
357
+ size: VIEW_UNIFORM_BYTES,
342
358
  usage: 0x0040 | BUFFER_COPY_DST,
343
359
  });
344
360
  const paramsBuffer = device.createBuffer({
@@ -358,7 +374,7 @@ async function runInjectReadback(
358
374
  });
359
375
  const injectReadback = device.createBuffer({
360
376
  label: 'stage-readback.inject',
361
- size: BYTES_PER_ROW * SIZE * PACKED_LAYERS,
377
+ size: BYTES_PER_ROW * SIZE * PACKED_LAYERS * owners,
362
378
  usage: MAP_READ | BUFFER_COPY_DST,
363
379
  });
364
380
  const temporalReadback = device.createBuffer({
@@ -382,13 +398,16 @@ async function runInjectReadback(
382
398
  )
383
399
  throw new Error('Dawn volume stage readback unavailable: readback allocation failed');
384
400
 
385
- const viewData = new Float32Array(240);
401
+ const viewData = new Float32Array(VIEW_UNIFORM_BYTES / Float32Array.BYTES_PER_ELEMENT);
386
402
  for (const offset of [0, 28, 44, 60, 76, 92, 196, 212]) identityMatrix(viewData, offset);
387
403
  viewData[44 + 10] = viewDepthScale;
388
404
  viewData[24] = 0;
389
405
  viewData[25] = 0;
390
406
  viewData[26] = -1;
391
- viewData[124] = 0;
407
+ // Enable one real shadow cascade. Otherwise the stability falsifier sees
408
+ // only unshadowed texels (the old overlong readback supplied fake zeros).
409
+ viewData[108] = 10;
410
+ viewData[124] = 1;
392
411
  viewData[228] = 0.1;
393
412
  viewData[229] = 10;
394
413
  viewData[230] = 0;
@@ -402,6 +421,10 @@ async function runInjectReadback(
402
421
  paramsData.set([0, -1, 0, frameIndex], 20);
403
422
  paramsData.set([1, 1, 1, 0], 24);
404
423
  paramsData.set([maxDistance, 0, 0, 0], 28);
424
+ // `simulation.w` is the renderer-owned selected-sun cloud transmittance
425
+ // carrier. A fixture without a CloudLayer must retain the unshadowed
426
+ // #3197 baseline instead of reading the typed-array zero value.
427
+ paramsData[35] = 1;
405
428
  const lightData = new Uint8Array(CLUSTER_LIGHT_DATA_BYTES);
406
429
  if (options.localLight !== undefined) {
407
430
  paramsData[30] = options.localLight === 'point' ? 1 : 2;
@@ -414,6 +437,24 @@ async function runInjectReadback(
414
437
  16,
415
438
  );
416
439
  }
440
+ for (let index = 0; index < owners; index++)
441
+ paramsData.set(paramsData.slice(0, 36), 36 * (index + 1));
442
+ paramsData[3] = owners;
443
+ if (options.secondDensity !== undefined || options.thinSeparated) {
444
+ for (let index = 0; index < owners; index++) paramsData[36 * (index + 1) + 7] = 1;
445
+ }
446
+ if (options.thinSeparated) {
447
+ paramsData[38] = 0.1;
448
+ paramsData[42] = 0.101;
449
+ paramsData[74] = 0.899;
450
+ paramsData[78] = 0.9;
451
+ for (const offset of [44, 80]) paramsData.set([100, 100, 100], offset);
452
+ }
453
+ if (options.reverse) {
454
+ const first = paramsData.slice(36, 72);
455
+ paramsData.copyWithin(36, 72, 108);
456
+ paramsData.set(first, 72);
457
+ }
417
458
  const clusterUniformData = new Float32Array(8);
418
459
  const clusterGrid = new Uint32Array(clusterUniformData.buffer);
419
460
  clusterGrid[0] = 1;
@@ -444,6 +485,13 @@ async function runInjectReadback(
444
485
  );
445
486
  if (!densityWrite.ok)
446
487
  throw new Error('Dawn volume stage readback unavailable: density upload failed');
488
+ const secondDensityWrite = device.queue.writeTexture(
489
+ { texture: secondDensityTexture.value },
490
+ new Uint8Array(densityData.length).fill(options.secondDensity ?? 255),
491
+ { offset: 0, bytesPerRow: SIZE * 4, rowsPerImage: SIZE },
492
+ { width: SIZE, height: SIZE, depthOrArrayLayers: SIZE },
493
+ );
494
+ if (!secondDensityWrite.ok) throw secondDensityWrite.error;
447
495
  const projectorWrite = device.queue.writeTexture(
448
496
  { texture: projectorTexture.value },
449
497
  new Uint8Array([255, 255, 255, 255]),
@@ -467,6 +515,7 @@ async function runInjectReadback(
467
515
  },
468
516
  { binding: 7, visibility: 4, buffer: { type: 'read-only-storage' } },
469
517
  { binding: 8, visibility: 4, buffer: { type: 'uniform' } },
518
+ { binding: 9, visibility: 4, texture: { sampleType: 'depth', viewDimension: '2d' } },
470
519
  ],
471
520
  });
472
521
  if (!layout.ok) throw layout.error;
@@ -533,6 +582,13 @@ async function runInjectReadback(
533
582
  { binding: 11, visibility: 4, buffer: { type: 'uniform' } },
534
583
  { binding: 12, visibility: 4, texture: { sampleType: 'float', viewDimension: '2d' } },
535
584
  { binding: 13, visibility: 4, sampler: { type: 'filtering' } },
585
+ { binding: 16, visibility: 4, texture: { sampleType: 'float', viewDimension: '2d' } },
586
+ { binding: 17, visibility: 4, sampler: { type: 'filtering' } },
587
+ ...Array.from({ length: 7 }, (_, index) => ({
588
+ binding: 18 + index,
589
+ visibility: 4,
590
+ texture: { sampleType: 'float' as const, viewDimension: '3d' as const },
591
+ })),
536
592
  ],
537
593
  });
538
594
  if (!temporalLayout.ok) throw temporalLayout.error;
@@ -571,6 +627,7 @@ async function runInjectReadback(
571
627
  { binding: 6, resource: { kind: 'textureView', value: outputView } },
572
628
  { binding: 7, resource: { kind: 'buffer', value: { buffer: lightDataBuffer.value } } },
573
629
  { binding: 8, resource: { kind: 'buffer', value: { buffer: clusterUniformBuffer.value } } },
630
+ { binding: 9, resource: { kind: 'textureView', value: shadowView.value } },
574
631
  ],
575
632
  });
576
633
  if (!bindings.ok) throw bindings.error;
@@ -593,7 +650,10 @@ async function runInjectReadback(
593
650
  { binding: 3, resource: { kind: 'buffer', value: { buffer: paramsBuffer.value } } },
594
651
  { binding: 4, resource: { kind: 'buffer', value: { buffer: viewBuffer.value } } },
595
652
  { binding: 5, resource: { kind: 'sampler', value: densitySampler.value } },
596
- { binding: 6, resource: { kind: 'textureView', value: densityView } },
653
+ {
654
+ binding: 6,
655
+ resource: { kind: 'textureView', value: options.reverse ? secondDensityView : densityView },
656
+ },
597
657
  { binding: 7, resource: { kind: 'sampler', value: densitySampler.value } },
598
658
  { binding: 8, resource: { kind: 'textureView', value: historyView } },
599
659
  { binding: 9, resource: { kind: 'textureView', value: temporalView } },
@@ -601,6 +661,15 @@ async function runInjectReadback(
601
661
  { binding: 11, resource: { kind: 'buffer', value: { buffer: clusterUniformBuffer.value } } },
602
662
  { binding: 12, resource: { kind: 'textureView', value: projectorView } },
603
663
  { binding: 13, resource: { kind: 'sampler', value: densitySampler.value } },
664
+ { binding: 16, resource: { kind: 'textureView', value: projectorView } },
665
+ { binding: 17, resource: { kind: 'sampler', value: densitySampler.value } },
666
+ ...Array.from({ length: 7 }, (_, index) => ({
667
+ binding: 18 + index,
668
+ resource: {
669
+ kind: 'textureView' as const,
670
+ value: index === 0 && !options.reverse ? secondDensityView : densityView,
671
+ },
672
+ })),
604
673
  ],
605
674
  });
606
675
  if (!temporalBindings.ok) throw temporalBindings.error;
@@ -622,12 +691,12 @@ async function runInjectReadback(
622
691
  const compute = encoder.value.beginComputePass();
623
692
  compute.setPipeline(pipeline.value);
624
693
  compute.setBindGroup(0, bindings.value);
625
- compute.dispatchWorkgroups(1, 1, PACKED_LAYERS);
694
+ compute.dispatchWorkgroups(1, 1, PACKED_LAYERS * owners);
626
695
  compute.end();
627
696
  encoder.value.copyTextureToBuffer(
628
697
  { texture: outputTexture.value as never },
629
698
  { buffer: injectReadback.value as never, bytesPerRow: BYTES_PER_ROW, rowsPerImage: SIZE },
630
- { width: SIZE, height: SIZE, depthOrArrayLayers: PACKED_LAYERS },
699
+ { width: SIZE, height: SIZE, depthOrArrayLayers: PACKED_LAYERS * owners },
631
700
  );
632
701
  const integrateCompute = encoder.value.beginComputePass();
633
702
  integrateCompute.setPipeline(integratePipeline.value);
@@ -687,7 +756,7 @@ async function runInjectReadback(
687
756
  return { red, green, alpha };
688
757
  };
689
758
  return {
690
- inject: await decode(injectReadback.value, SIZE, 4, false),
759
+ inject: await decode(injectReadback.value, PACKED_LAYERS * owners, 4, false),
691
760
  temporal: await decode(temporalReadback.value, 1, BYTES_PER_PIXEL, true),
692
761
  integrate: await decode(integrateReadback.value, 1, BYTES_PER_PIXEL, true),
693
762
  };
@@ -726,6 +795,7 @@ describe('volumetric fog production stage readback on Dawn', () => {
726
795
  it('keeps static shadow visibility stable across renderer frame phases', async () => {
727
796
  const first = await runInjectReadback({ frameIndex: 0, shadowDepthClear: 0.5 });
728
797
  const next = await runInjectReadback({ frameIndex: 1, shadowDepthClear: 0.5 });
798
+ expect(first.inject.red).toHaveLength(SIZE * SIZE * PACKED_LAYERS);
729
799
  expect(first.inject).toEqual(next.inject);
730
800
  expect(first.inject.red.some((value) => value === 0)).toBe(true);
731
801
  expect(first.inject.red.some((value) => value > 0.9)).toBe(true);
@@ -799,6 +869,40 @@ describe('volumetric fog production stage readback on Dawn', () => {
799
869
  expect(Math.abs(production - reference)).toBeLessThan(0.002);
800
870
  });
801
871
 
872
+ it('samples independent density textures and is invariant under owner permutation', async () => {
873
+ const transparent = await runInjectReadback({
874
+ sceneDepthClear: 0.57,
875
+ owners: 2,
876
+ secondDensity: 0,
877
+ });
878
+ const half = await runInjectReadback({ sceneDepthClear: 0.57, owners: 2, secondDensity: 128 });
879
+ const reversed = await runInjectReadback({
880
+ sceneDepthClear: 0.57,
881
+ owners: 2,
882
+ secondDensity: 128,
883
+ reverse: true,
884
+ });
885
+ expect(transparent.integrate.alpha[0]).toBeCloseTo(Math.exp(-0.47), 3);
886
+ expect(half.integrate.alpha[0]).toBeCloseTo(Math.exp(-0.47 * (1 + 128 / 255)), 3);
887
+ expect(reversed.integrate.alpha).toEqual(half.integrate.alpha);
888
+ expect(reversed.integrate.red).toEqual(half.integrate.red);
889
+ });
890
+ it('does not miss thin local volumes separated by empty space', async () => {
891
+ const values = await runInjectReadback({ owners: 2, thinSeparated: true });
892
+ expect(values.integrate.alpha[0]).toBeCloseTo(Math.exp(-0.002 * 100), 3);
893
+ });
894
+ it('adds overlapping optical depth instead of rejecting or selecting one volume', async () => {
895
+ const one = await runInjectReadback({ sceneDepthClear: 0.57 });
896
+ const two = await runInjectReadback({ sceneDepthClear: 0.57, owners: 2 });
897
+ const expected = Math.exp(-0.47 * (2 * 1.5 ** 3 - 1) * 2);
898
+ expect(two.integrate.alpha[0]).toBeCloseTo(expected, 3);
899
+ expect(two.integrate.alpha[0]).toBeLessThan(one.integrate.alpha[0] ?? 0);
900
+ expect(two.integrate.red[0]).toBeGreaterThan(one.integrate.red[0] ?? 0);
901
+ });
902
+ it('integrates all eight admitted owners through the production parameter layout', async () => {
903
+ const values = await runInjectReadback({ sceneDepthClear: 0.57, owners: 8, extinction: 0.1 });
904
+ expect(values.integrate.alpha[0]).toBeCloseTo(Math.exp(-0.47 * (2 * 1.5 ** 3 - 1) * 0.8), 3);
905
+ });
802
906
  it('injects raw density then resolves a 2d integrated volume', async () => {
803
907
  const values = await runInjectReadback();
804
908
  // biome-ignore lint/suspicious/noConsole: stage readback is machine evidence
@@ -41,7 +41,7 @@ describe('volumetric fog RenderGraph topology', () => {
41
41
  it('integrates the ray independently of packed visibility depth', () => {
42
42
  const integrate = shaderSource('volume-integrate.wgsl');
43
43
  expect(integrate).toContain('for (var step = 0u; step < ray_step_count; step = step + 1u)');
44
- expect(integrate).toContain('let visibility_depth = max(textureNumLayers(froxel) * 4u, 1u);');
44
+ expect(integrate).toContain('let visibility_depth = max(owner_layers * 4u, 1u);');
45
45
  });
46
46
 
47
47
  it('keeps the Beer-Lambert extinction input physically non-negative', () => {
@@ -144,7 +144,7 @@ describe('volumetric fog RenderGraph topology', () => {
144
144
  expect(shaderSource('volume-inject.wgsl')).not.toContain('textureSampleLevel(density');
145
145
  expect(shaderSource('volume-inject.wgsl')).not.toContain('stratified32');
146
146
  expect(shaderSource('volume-inject.wgsl')).not.toContain('dither_unorm8');
147
- expect(shaderSource('volume-integrate.wgsl')).toContain('exp(-sigma_scale');
147
+ expect(shaderSource('volume-integrate.wgsl')).toContain('exp(-extinction * sample_length)');
148
148
  expect(shaderSource('volume-integrate.wgsl')).toContain('textureSampleLevel(froxel');
149
149
  expect(shaderSource('volume-integrate.wgsl')).toContain('textureStore(resolved');
150
150
  expect(shaderSource('volume-temporal.wgsl')).toContain('var lower');
@@ -194,7 +194,9 @@ describe('volumetric fog RenderGraph topology', () => {
194
194
  expect(frameSource).toContain('volumetricFogHistorySlot');
195
195
  expect(frameSource).toContain('volumetricFogHistorySignature');
196
196
  expect(frameSource).toContain('activeVolumetricFogSignature');
197
- expect(frameSource).toContain('params[32] = fog.worldTimeSeconds ?? 0');
197
+ expect(
198
+ readFileSync(fileURLToPath(new URL('../record/volume-params.ts', import.meta.url)), 'utf8'),
199
+ ).toContain('params[32] = fog.worldTimeSeconds ?? 0');
198
200
  expect(
199
201
  readFileSync(fileURLToPath(new URL('../volume/temporal.ts', import.meta.url)), 'utf8'),
200
202
  ).toContain("reason: 'simulation-time'");
@@ -60,6 +60,36 @@ export interface RhiBackendPack {
60
60
  readonly instrumentation?: RhiBackendInstrumentation;
61
61
  }
62
62
 
63
+ /** Project a backend module into the Render-owned injected pack contract. */
64
+ export function loadRhiPack(
65
+ mod: Record<string, unknown>,
66
+ instrumentation?: RhiBackendPack['instrumentation'],
67
+ ): RhiBackendPack {
68
+ const rhi = mod.rhi as unknown as RhiBackendPack['rhi'];
69
+ const createShaderModule = mod.createShaderModule as
70
+ | RhiBackendPack['createShaderModule']
71
+ | undefined;
72
+ const createShaderModuleImmediate = mod.createShaderModuleImmediate as
73
+ | RhiBackendPack['createShaderModuleImmediate']
74
+ | undefined;
75
+ const translateErrorEventToRhiError = mod.translateErrorEventToRhiError as
76
+ | RhiBackendPack['translateErrorEventToRhiError']
77
+ | undefined;
78
+ const backendHandleAccessor = mod._internal_getRawDevice as unknown as
79
+ | RhiBackendPack['_internal_getRawDevice']
80
+ | undefined;
81
+ return {
82
+ rhi,
83
+ ...(createShaderModule === undefined ? {} : { createShaderModule }),
84
+ ...(createShaderModuleImmediate === undefined ? {} : { createShaderModuleImmediate }),
85
+ ...(translateErrorEventToRhiError === undefined ? {} : { translateErrorEventToRhiError }),
86
+ ...(backendHandleAccessor === undefined
87
+ ? {}
88
+ : { _internal_getRawDevice: backendHandleAccessor }),
89
+ ...(instrumentation === undefined ? {} : { instrumentation }),
90
+ };
91
+ }
92
+
63
93
  export interface EngineEnvironmentErrorDetail {
64
94
  readonly webgpuError?: RhiError | Error | undefined;
65
95
  readonly wgpuError?: RhiError | Error | undefined;
@@ -0,0 +1,22 @@
1
+ import type { BarrelDistortionInspection } from '../inspection-types';
2
+ import { projectBarrelDistortionInspection } from '../inspection-types';
3
+
4
+ export function inspectBarrelDistortion(
5
+ disposed: boolean,
6
+ deviceLost: boolean,
7
+ surfaceReleased: boolean,
8
+ frameId: number,
9
+ deviceGeneration: number,
10
+ inspection: BarrelDistortionInspection,
11
+ ): BarrelDistortionInspection {
12
+ if (disposed || deviceLost || surfaceReleased) {
13
+ return projectBarrelDistortionInspection({
14
+ effectiveMapping: undefined,
15
+ frameId,
16
+ deviceGeneration,
17
+ graphGeneration: 0,
18
+ lastKnownGood: false,
19
+ });
20
+ }
21
+ return projectBarrelDistortionInspection({ ...inspection, frameId });
22
+ }
@@ -0,0 +1,11 @@
1
+ import { RhiError } from '@forgeax/engine-rhi';
2
+
3
+ export function rejectZeroCanvasSize(width: number, height: number): RhiError | undefined {
4
+ return width > 0 && height > 0
5
+ ? undefined
6
+ : new RhiError({
7
+ code: 'rhi-not-available',
8
+ expected: 'canvas drawing buffer has positive width and height before drawing',
9
+ hint: 'restore a positive canvas width and height before retrying renderer.draw',
10
+ });
11
+ }
@@ -0,0 +1,22 @@
1
+ import type { MaterialShaderManifestEntry } from '@forgeax/engine-shader';
2
+ import type { ManifestEntry } from '@forgeax/engine-types';
3
+
4
+ /** Keep the cloud-shadow shader and View layout on one capability branch. */
5
+ function hasCloudShadowViewBindings(wgsl: string): boolean {
6
+ return /@group\(0\)\s*@binding\((?:16|17)\)\s/.test(wgsl);
7
+ }
8
+
9
+ export function selectCloudShadowCompatibleEntry(
10
+ entry: ManifestEntry,
11
+ materialEntry: MaterialShaderManifestEntry | undefined,
12
+ projectorAvailable: boolean,
13
+ ): ManifestEntry {
14
+ if (projectorAvailable || !hasCloudShadowViewBindings(entry.wgsl)) return entry;
15
+ const fallback = materialEntry?.variants.find(
16
+ (variant) =>
17
+ (!('PROJECTOR_AVAILABLE' in variant.defines) ||
18
+ variant.defines.PROJECTOR_AVAILABLE === false) &&
19
+ !hasCloudShadowViewBindings(variant.composedWgsl),
20
+ );
21
+ return fallback === undefined ? entry : { ...entry, wgsl: fallback.composedWgsl };
22
+ }
@@ -21,12 +21,12 @@ export function transmissionBackdropAvailable(limit: number | undefined): boolea
21
21
  }
22
22
  /**
23
23
  * The complete Standard physical root can declare all optional texture slots.
24
- * Its material group therefore needs one more sampled-texture entry than the
24
+ * Its material group therefore needs two more sampled-texture entries than the
25
25
  * extended-lighting topology alone. Request this ceiling when the adapter can
26
26
  * provide it; lower-capability devices remain fail-closed at material
27
27
  * pipeline admission instead of receiving an invalid WebGPU layout.
28
28
  */
29
- export const STANDARD_PHYSICAL_REQUIRED_SAMPLED_TEXTURES = 22;
29
+ export const STANDARD_PHYSICAL_REQUIRED_SAMPLED_TEXTURES = 23;
30
30
 
31
31
  export interface DeviceFeatureAdmissionOptions {
32
32
  readonly gpuPassTiming?: object | undefined;
@@ -15,6 +15,7 @@ import {
15
15
  type DynamicGeometryOrdering,
16
16
  type DynamicGeometryPrepareInput,
17
17
  type DynamicGeometryReceipt,
18
+ type DynamicGeometryRecordStageLane,
18
19
  sameCandidateCredential,
19
20
  } from '../dynamic-geometry';
20
21
 
@@ -191,11 +192,21 @@ export function createDynamicGeometryHost(options: {
191
192
  readonly currentGeneration: () => number;
192
193
  /** Renderer record-stage proof for the most recently submitted frame. */
193
194
  readonly isConsumedByRenderFrame: (candidate: DynamicGeometryCandidate) => boolean;
195
+ /** Renderer-owned lane fact for the most recently submitted frame. */
196
+ readonly recordStageLane?: (
197
+ candidate: DynamicGeometryCandidate,
198
+ ) => DynamicGeometryRecordStageLane | undefined;
194
199
  /** Existing temporal owner discards the old surface history after an ECS swap. */
195
200
  readonly onTopologyChanged?: () => void;
196
201
  }): DynamicGeometryHostImplementation {
197
- const { lifecycle, attachedWorlds, getGpuStore, currentGeneration, isConsumedByRenderFrame } =
198
- options;
202
+ const {
203
+ lifecycle,
204
+ attachedWorlds,
205
+ getGpuStore,
206
+ currentGeneration,
207
+ isConsumedByRenderFrame,
208
+ recordStageLane = () => undefined,
209
+ } = options;
199
210
  const hostCandidates = new Map<string, HostCandidateRecord>();
200
211
  let observedGeneration = -1;
201
212
  const releaseMeshLease = (record: HostCandidateRecord): DynamicGeometryError | undefined => {
@@ -858,44 +869,50 @@ export function createDynamicGeometryHost(options: {
858
869
  // instead of silently producing zero receipts.
859
870
  const publicationFixedStep = fixedStep ?? worldFixedStep;
860
871
  receipts.push(
861
- ...lifecycle.publishFrame(frame, [world], publicationFixedStep, (candidate) => {
862
- const candidateWorld = candidate.world as World;
863
- if (candidateWorld !== world || !attachedWorlds.has(candidateWorld)) return false;
864
- const hostRecord = candidateRecord(candidate);
865
- if (
866
- hostRecord === undefined ||
867
- !hostRecord.accepted ||
868
- !hasRenderableBinding(candidateWorld, candidate.entity) ||
869
- meshHandleOf(candidateWorld, candidate.entity) !== candidate.meshHandle ||
870
- !hasMaterialIdentity(
871
- candidateWorld,
872
- candidate.entity,
873
- candidate.mesh,
874
- candidate.materialIdentity,
875
- )
876
- )
877
- return false;
878
- if (!isConsumedByRenderFrame(candidate)) return false;
879
- const actualFixedStep = fixedStep ?? worldFixedStep;
880
- if (candidate.fixedStep === undefined || actualFixedStep === undefined) return false;
881
- // RenderFrameInput.fixedStep is an assertion from the host, not a
882
- // second clock. It may name a later World tick in a multi-fixed-step
883
- // host frame, but it cannot manufacture a step the attached World
884
- // has not actually published. An explicit mismatch remains a hard
885
- // rejection; omission uses the World-derived value above.
886
- if (worldFixedStep !== actualFixedStep || actualFixedStep < candidate.fixedStep)
887
- return false;
888
- if (candidate.physicsEntity !== undefined) {
889
- const publication = physicsPublicationOf(candidateWorld, candidate.physicsEntity);
872
+ ...lifecycle.publishFrame(
873
+ frame,
874
+ [world],
875
+ publicationFixedStep,
876
+ (candidate) => {
877
+ const candidateWorld = candidate.world as World;
878
+ if (candidateWorld !== world || !attachedWorlds.has(candidateWorld)) return false;
879
+ const hostRecord = candidateRecord(candidate);
890
880
  if (
891
- publication === undefined ||
892
- publication.fixedStep < candidate.fixedStep ||
893
- publication.revision !== candidate.revision
881
+ hostRecord === undefined ||
882
+ !hostRecord.accepted ||
883
+ !hasRenderableBinding(candidateWorld, candidate.entity) ||
884
+ meshHandleOf(candidateWorld, candidate.entity) !== candidate.meshHandle ||
885
+ !hasMaterialIdentity(
886
+ candidateWorld,
887
+ candidate.entity,
888
+ candidate.mesh,
889
+ candidate.materialIdentity,
890
+ )
894
891
  )
895
892
  return false;
896
- }
897
- return true;
898
- }),
893
+ if (!isConsumedByRenderFrame(candidate)) return false;
894
+ const actualFixedStep = fixedStep ?? worldFixedStep;
895
+ if (candidate.fixedStep === undefined || actualFixedStep === undefined) return false;
896
+ // RenderFrameInput.fixedStep is an assertion from the host, not a
897
+ // second clock. It may name a later World tick in a multi-fixed-step
898
+ // host frame, but it cannot manufacture a step the attached World
899
+ // has not actually published. An explicit mismatch remains a hard
900
+ // rejection; omission uses the World-derived value above.
901
+ if (worldFixedStep !== actualFixedStep || actualFixedStep < candidate.fixedStep)
902
+ return false;
903
+ if (candidate.physicsEntity !== undefined) {
904
+ const publication = physicsPublicationOf(candidateWorld, candidate.physicsEntity);
905
+ if (
906
+ publication === undefined ||
907
+ publication.fixedStep < candidate.fixedStep ||
908
+ publication.revision !== candidate.revision
909
+ )
910
+ return false;
911
+ }
912
+ return true;
913
+ },
914
+ recordStageLane,
915
+ ),
899
916
  );
900
917
  }
901
918
  for (const receipt of receipts) {
@@ -931,6 +948,11 @@ export function createRendererDynamicGeometryHost(options: {
931
948
  entity: number,
932
949
  meshHandle: DynamicGeometryCandidate['meshHandle'],
933
950
  ) => boolean;
951
+ readonly dynamicGeometryRecordStageLane: (
952
+ world: World,
953
+ entity: number,
954
+ meshHandle: DynamicGeometryCandidate['meshHandle'],
955
+ ) => DynamicGeometryRecordStageLane | undefined;
934
956
  };
935
957
  }): DynamicGeometryHostImplementation {
936
958
  const { renderSystem, ...hostOptions } = options;
@@ -943,6 +965,12 @@ export function createRendererDynamicGeometryHost(options: {
943
965
  candidate.entity ?? -1,
944
966
  candidate.meshHandle,
945
967
  ),
968
+ recordStageLane: (candidate) =>
969
+ renderSystem.dynamicGeometryRecordStageLane(
970
+ candidate.world as World,
971
+ candidate.entity ?? -1,
972
+ candidate.meshHandle,
973
+ ),
946
974
  });
947
975
  }
948
976
 
@@ -24,7 +24,7 @@ export function createDynamicGeometryRuntime(options: {
24
24
  readonly currentGeneration: () => number;
25
25
  readonly renderSystem: Pick<
26
26
  RenderSystem,
27
- 'invalidateGeometryHistory' | 'isDynamicGeometryConsumed'
27
+ 'invalidateGeometryHistory' | 'isDynamicGeometryConsumed' | 'dynamicGeometryRecordStageLane'
28
28
  >;
29
29
  }): DynamicGeometryRuntime {
30
30
  const lifecycle = createDynamicGeometryLifecycle();
@@ -40,6 +40,12 @@ export function createDynamicGeometryRuntime(options: {
40
40
  candidate.entity ?? -1,
41
41
  candidate.meshHandle,
42
42
  ),
43
+ recordStageLane: (candidate) =>
44
+ options.renderSystem.dynamicGeometryRecordStageLane(
45
+ candidate.world as World,
46
+ candidate.entity ?? -1,
47
+ candidate.meshHandle,
48
+ ),
43
49
  });
44
50
  return { lifecycle, host };
45
51
  }
@@ -3,7 +3,7 @@
3
3
  // and frame work live in webgpu-renderer.ts.
4
4
 
5
5
  import type { RendererOptions } from '../render-contract';
6
- import { EngineEnvironmentError, type RhiBackendPack } from './backend-contract';
6
+ import { EngineEnvironmentError, loadRhiPack, type RhiBackendPack } from './backend-contract';
7
7
  import type { BundlerOptions } from './bundler-contract';
8
8
  import type { RendererAssemblyImplementation } from './host-contract';
9
9
  import { toError } from './renderer-facade';
@@ -80,6 +80,7 @@ export {
80
80
  selectSkinPrewarmVariants,
81
81
  selectStandardPbrTransmissionPrewarmVariants,
82
82
  shouldDeferMissingPreparedMaterialShader,
83
+ stripCloudShadowBindingsForLowLimit,
83
84
  } from './webgpu-renderer';
84
85
 
85
86
  const GPU_ENVIRONMENT_ERROR_CODES = new Set([
@@ -104,35 +105,6 @@ function classifyEnvErrorReason(
104
105
  : `engine init failed (${name})`;
105
106
  }
106
107
 
107
- function loadRhiPack(
108
- mod: Record<string, unknown>,
109
- instrumentation?: RhiBackendPack['instrumentation'],
110
- ): RhiBackendPack {
111
- const rhi = mod.rhi as unknown as RhiBackendPack['rhi'];
112
- const createShaderModule = mod.createShaderModule as
113
- | RhiBackendPack['createShaderModule']
114
- | undefined;
115
- const createShaderModuleImmediate = mod.createShaderModuleImmediate as
116
- | RhiBackendPack['createShaderModuleImmediate']
117
- | undefined;
118
- const translateErrorEventToRhiError = mod.translateErrorEventToRhiError as
119
- | RhiBackendPack['translateErrorEventToRhiError']
120
- | undefined;
121
- const backendHandleAccessor = mod._internal_getRawDevice as unknown as
122
- | RhiBackendPack['_internal_getRawDevice']
123
- | undefined;
124
- return {
125
- rhi,
126
- ...(createShaderModule === undefined ? {} : { createShaderModule }),
127
- ...(createShaderModuleImmediate === undefined ? {} : { createShaderModuleImmediate }),
128
- ...(translateErrorEventToRhiError === undefined ? {} : { translateErrorEventToRhiError }),
129
- ...(backendHandleAccessor === undefined
130
- ? {}
131
- : { _internal_getRawDevice: backendHandleAccessor }),
132
- ...(instrumentation === undefined ? {} : { instrumentation }),
133
- };
134
- }
135
-
136
108
  /** Build a renderer after selecting the host-supplied backend pack. */
137
109
  export async function createRenderer(
138
110
  canvas: unknown,