@forgeax/engine-render 0.1.33 → 0.1.34

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (518) hide show
  1. package/README.md +1010 -124
  2. package/dist/assembly/backend-contract.d.ts +2 -0
  3. package/dist/assembly/backend-contract.d.ts.map +1 -1
  4. package/dist/assembly/barrel-distortion-inspection.d.ts +3 -0
  5. package/dist/assembly/barrel-distortion-inspection.d.ts.map +1 -0
  6. package/dist/assembly/canvas-draw-guard.d.ts +3 -0
  7. package/dist/assembly/canvas-draw-guard.d.ts.map +1 -0
  8. package/dist/assembly/cloud-shadow-entry.d.ts +4 -0
  9. package/dist/assembly/cloud-shadow-entry.d.ts.map +1 -0
  10. package/dist/assembly/dynamic-geometry-host.d.ts +4 -1
  11. package/dist/assembly/dynamic-geometry-host.d.ts.map +1 -1
  12. package/dist/assembly/dynamic-geometry-runtime.d.ts +1 -1
  13. package/dist/assembly/dynamic-geometry-runtime.d.ts.map +1 -1
  14. package/dist/assembly/factory.d.ts +1 -1
  15. package/dist/assembly/factory.d.ts.map +1 -1
  16. package/dist/assembly/host-contract.d.ts +3 -3
  17. package/dist/assembly/host-contract.d.ts.map +1 -1
  18. package/dist/assembly/material/assembly.d.ts.map +1 -1
  19. package/dist/assembly/material/pipeline-helpers.d.ts +5 -0
  20. package/dist/assembly/material/pipeline-helpers.d.ts.map +1 -1
  21. package/dist/assembly/material-shader-policy.d.ts +16 -2
  22. package/dist/assembly/material-shader-policy.d.ts.map +1 -1
  23. package/dist/assembly/material-shader-prewarm.d.ts.map +1 -1
  24. package/dist/assembly/recovery/device-loss-fanout.d.ts.map +1 -1
  25. package/dist/assembly/recovery/renderer-recover.d.ts +2 -0
  26. package/dist/assembly/recovery/renderer-recover.d.ts.map +1 -1
  27. package/dist/assembly/render-feature-post-processes.d.ts +6 -0
  28. package/dist/assembly/render-feature-post-processes.d.ts.map +1 -0
  29. package/dist/assembly/renderer-facade.d.ts.map +1 -1
  30. package/dist/assembly/renderer-feature-inspection.d.ts +1 -1
  31. package/dist/assembly/renderer-feature-inspection.d.ts.map +1 -1
  32. package/dist/assembly/renderer-frame-transaction.d.ts +12 -0
  33. package/dist/assembly/renderer-frame-transaction.d.ts.map +1 -1
  34. package/dist/assembly/renderer-inspection.d.ts +11 -0
  35. package/dist/assembly/renderer-inspection.d.ts.map +1 -1
  36. package/dist/assembly/webgpu-pbr-ready.d.ts +1 -0
  37. package/dist/assembly/webgpu-pbr-ready.d.ts.map +1 -1
  38. package/dist/assembly/webgpu-ready-per-pass.d.ts +39 -0
  39. package/dist/assembly/webgpu-ready-per-pass.d.ts.map +1 -0
  40. package/dist/assembly/webgpu-ready.d.ts +1 -1
  41. package/dist/assembly/webgpu-ready.d.ts.map +1 -1
  42. package/dist/assembly/webgpu-renderer-bootstrap.d.ts.map +1 -1
  43. package/dist/assembly/webgpu-renderer-observation-owner.d.ts +35 -0
  44. package/dist/assembly/webgpu-renderer-observation-owner.d.ts.map +1 -0
  45. package/dist/assembly/webgpu-renderer.d.ts +1 -1
  46. package/dist/assembly/webgpu-renderer.d.ts.map +1 -1
  47. package/dist/authoring.mjs +1 -1
  48. package/dist/barrel-distortion.d.ts +47 -0
  49. package/dist/barrel-distortion.d.ts.map +1 -0
  50. package/dist/{chunk-PA5DRJNI.mjs → chunk-ELJFJ2BU.mjs} +2 -2
  51. package/dist/chunk-ELJFJ2BU.mjs.map +1 -0
  52. package/dist/{chunk-ZDQWGQW7.mjs → chunk-HEB564WF.mjs} +4 -4
  53. package/dist/{chunk-ZDQWGQW7.mjs.map → chunk-HEB564WF.mjs.map} +1 -1
  54. package/dist/{chunk-VOZWDM3L.mjs → chunk-MKDIT2EM.mjs} +1307 -188
  55. package/dist/chunk-MKDIT2EM.mjs.map +1 -0
  56. package/dist/{chunk-LEAXOMYJ.mjs → chunk-OCDLEI6I.mjs} +3 -3
  57. package/dist/{chunk-LEAXOMYJ.mjs.map → chunk-OCDLEI6I.mjs.map} +1 -1
  58. package/dist/chunk-ODZWR6JQ.mjs +4927 -0
  59. package/dist/chunk-ODZWR6JQ.mjs.map +1 -0
  60. package/dist/{chunk-3RTCJTH4.mjs → chunk-SHFUFJ5N.mjs} +184 -13
  61. package/dist/chunk-SHFUFJ5N.mjs.map +1 -0
  62. package/dist/{chunk-OO3DRYK7.mjs → chunk-UI5SFODX.mjs} +176 -96
  63. package/dist/chunk-UI5SFODX.mjs.map +1 -0
  64. package/dist/{chunk-PLAXOOX5.mjs → chunk-UINHLCZA.mjs} +561 -79
  65. package/dist/chunk-UINHLCZA.mjs.map +1 -0
  66. package/dist/{chunk-NB2S7ZRX.mjs → chunk-WEX45HKH.mjs} +127 -386
  67. package/dist/chunk-WEX45HKH.mjs.map +1 -0
  68. package/dist/cloud/density.d.ts +55 -0
  69. package/dist/cloud/density.d.ts.map +1 -0
  70. package/dist/cloud/extract.d.ts +25 -0
  71. package/dist/cloud/extract.d.ts.map +1 -0
  72. package/dist/cloud/feature.d.ts +57 -0
  73. package/dist/cloud/feature.d.ts.map +1 -0
  74. package/dist/cloud/frame-context.d.ts +8 -0
  75. package/dist/cloud/frame-context.d.ts.map +1 -0
  76. package/dist/cloud/inspection.d.ts +59 -0
  77. package/dist/cloud/inspection.d.ts.map +1 -0
  78. package/dist/cloud/optics.d.ts +56 -0
  79. package/dist/cloud/optics.d.ts.map +1 -0
  80. package/dist/cloud/parameters.d.ts +73 -0
  81. package/dist/cloud/parameters.d.ts.map +1 -0
  82. package/dist/cloud/resources.d.ts +60 -0
  83. package/dist/cloud/resources.d.ts.map +1 -0
  84. package/dist/cloud/shadow.d.ts +42 -0
  85. package/dist/cloud/shadow.d.ts.map +1 -0
  86. package/dist/cloud/temporal.d.ts +74 -0
  87. package/dist/cloud/temporal.d.ts.map +1 -0
  88. package/dist/components/barrel-distortion.d.ts +13 -0
  89. package/dist/components/barrel-distortion.d.ts.map +1 -0
  90. package/dist/components/cloud-layer.d.ts +29 -0
  91. package/dist/components/cloud-layer.d.ts.map +1 -0
  92. package/dist/components/index.d.ts +2 -0
  93. package/dist/components/index.d.ts.map +1 -1
  94. package/dist/components/instances.d.ts +20 -6
  95. package/dist/components/instances.d.ts.map +1 -1
  96. package/dist/construct-renderer.d.ts +1 -1
  97. package/dist/construct-renderer.d.ts.map +1 -1
  98. package/dist/construct-renderer.mjs +6759 -2875
  99. package/dist/construct-renderer.mjs.map +1 -1
  100. package/dist/dynamic-geometry.d.ts +5 -1
  101. package/dist/dynamic-geometry.d.ts.map +1 -1
  102. package/dist/errors/cloud.d.ts +59 -0
  103. package/dist/errors/cloud.d.ts.map +1 -0
  104. package/dist/errors/render.d.ts +18 -4
  105. package/dist/errors/render.d.ts.map +1 -1
  106. package/dist/examples/single-layer-medium-surface.d.ts +47 -0
  107. package/dist/examples/single-layer-medium-surface.d.ts.map +1 -0
  108. package/dist/extract/camera.d.ts.map +1 -1
  109. package/dist/extract/contracts.d.ts +5 -1
  110. package/dist/extract/contracts.d.ts.map +1 -1
  111. package/dist/features/barrel-distortion.d.ts +29 -0
  112. package/dist/features/barrel-distortion.d.ts.map +1 -0
  113. package/dist/features/error-reporting.d.ts +6 -2
  114. package/dist/features/error-reporting.d.ts.map +1 -1
  115. package/dist/features/host.d.ts +10 -0
  116. package/dist/features/host.d.ts.map +1 -1
  117. package/dist/features/plan.d.ts +8 -0
  118. package/dist/features/plan.d.ts.map +1 -1
  119. package/dist/features/render-graph-contribution.d.ts +5 -0
  120. package/dist/features/render-graph-contribution.d.ts.map +1 -1
  121. package/dist/features/render-graph-raster.d.ts +1 -0
  122. package/dist/features/render-graph-raster.d.ts.map +1 -1
  123. package/dist/features/targets.d.ts +2 -0
  124. package/dist/features/targets.d.ts.map +1 -1
  125. package/dist/features/types.d.ts +44 -0
  126. package/dist/features/types.d.ts.map +1 -1
  127. package/dist/fullscreen-post-process-pass.d.ts +15 -7
  128. package/dist/fullscreen-post-process-pass.d.ts.map +1 -1
  129. package/dist/gpu-dirty-ranges.d.ts +11 -0
  130. package/dist/gpu-dirty-ranges.d.ts.map +1 -0
  131. package/dist/gpu-driven/batch-topology.d.ts +17 -0
  132. package/dist/gpu-driven/batch-topology.d.ts.map +1 -1
  133. package/dist/gpu-driven/material-artifacts.d.ts +6 -0
  134. package/dist/gpu-driven/material-artifacts.d.ts.map +1 -1
  135. package/dist/gpu-driven/prepared-draw.d.ts.map +1 -1
  136. package/dist/gpu-driven/production-raster-material.d.ts +178 -0
  137. package/dist/gpu-driven/production-raster-material.d.ts.map +1 -0
  138. package/dist/gpu-driven/production-raster.d.ts +47 -3
  139. package/dist/gpu-driven/production-raster.d.ts.map +1 -1
  140. package/dist/gpu-driven/resource-allocation.d.ts +31 -0
  141. package/dist/gpu-driven/resource-allocation.d.ts.map +1 -0
  142. package/dist/gpu-driven/shadow-ownership.d.ts +14 -0
  143. package/dist/gpu-driven/shadow-ownership.d.ts.map +1 -0
  144. package/dist/gpu-driven/view-gpu.d.ts +26 -2
  145. package/dist/gpu-driven/view-gpu.d.ts.map +1 -1
  146. package/dist/gpu-scene.d.ts +5 -0
  147. package/dist/gpu-scene.d.ts.map +1 -1
  148. package/dist/hdrp-buffers.d.ts +2 -2
  149. package/dist/hdrp-buffers.d.ts.map +1 -1
  150. package/dist/ibl/skylight-bind-group.d.ts +10 -1
  151. package/dist/ibl/skylight-bind-group.d.ts.map +1 -1
  152. package/dist/index.d.ts +27 -7
  153. package/dist/index.d.ts.map +1 -1
  154. package/dist/index.mjs +258 -8
  155. package/dist/index.mjs.map +1 -1
  156. package/dist/inspection-types.d.ts +135 -1
  157. package/dist/inspection-types.d.ts.map +1 -1
  158. package/dist/instance-buffer-cache.d.ts +4 -4
  159. package/dist/instance-buffer-cache.d.ts.map +1 -1
  160. package/dist/instances.d.ts +48 -100
  161. package/dist/instances.d.ts.map +1 -1
  162. package/dist/internal.mjs +7 -7
  163. package/dist/pbr-pipeline.d.ts +19 -1
  164. package/dist/pbr-pipeline.d.ts.map +1 -1
  165. package/dist/pipeline/single-layer-medium-passes.d.ts +73 -0
  166. package/dist/pipeline/single-layer-medium-passes.d.ts.map +1 -0
  167. package/dist/pipeline/standard-forward-lane.d.ts.map +1 -1
  168. package/dist/pipeline/standard-output/graph.d.ts.map +1 -1
  169. package/dist/pipeline/standard-output/types.d.ts +4 -2
  170. package/dist/pipeline/standard-output/types.d.ts.map +1 -1
  171. package/dist/pipeline/standard-pipeline.d.ts.map +1 -1
  172. package/dist/pipeline/standard-post.d.ts.map +1 -1
  173. package/dist/pipeline-builder.d.ts +1 -1
  174. package/dist/pipeline-builder.d.ts.map +1 -1
  175. package/dist/plugin.d.ts.map +1 -1
  176. package/dist/prepare/prepared-graphics-resolver.d.ts +2 -0
  177. package/dist/prepare/prepared-graphics-resolver.d.ts.map +1 -1
  178. package/dist/record/barrel-distortion-frame.d.ts +15 -0
  179. package/dist/record/barrel-distortion-frame.d.ts.map +1 -0
  180. package/dist/record/dynamic-geometry-consumption.d.ts +10 -2
  181. package/dist/record/dynamic-geometry-consumption.d.ts.map +1 -1
  182. package/dist/record/fold-buckets.d.ts +95 -0
  183. package/dist/record/fold-buckets.d.ts.map +1 -0
  184. package/dist/record/fold-instance-buffer.d.ts +6 -0
  185. package/dist/record/fold-instance-buffer.d.ts.map +1 -0
  186. package/dist/record/frame-lighting.d.ts +1 -0
  187. package/dist/record/frame-lighting.d.ts.map +1 -1
  188. package/dist/record/frame-snapshot.d.ts +37 -3
  189. package/dist/record/frame-snapshot.d.ts.map +1 -1
  190. package/dist/record/frame.d.ts +10 -61
  191. package/dist/record/frame.d.ts.map +1 -1
  192. package/dist/record/gpu-draw-receipts.d.ts +11 -0
  193. package/dist/record/gpu-draw-receipts.d.ts.map +1 -0
  194. package/dist/record/gpu-timing.d.ts +8 -0
  195. package/dist/record/gpu-timing.d.ts.map +1 -1
  196. package/dist/record/main-pass-geometry.d.ts +21 -5
  197. package/dist/record/main-pass-geometry.d.ts.map +1 -1
  198. package/dist/record/main-pass-material.d.ts +7 -1
  199. package/dist/record/main-pass-material.d.ts.map +1 -1
  200. package/dist/record/main-pass-sprite-draws.d.ts.map +1 -1
  201. package/dist/record/main-pass.d.ts +13 -2
  202. package/dist/record/main-pass.d.ts.map +1 -1
  203. package/dist/record/motion-blur-receipt.d.ts +11 -0
  204. package/dist/record/motion-blur-receipt.d.ts.map +1 -0
  205. package/dist/record/probe-blend-buffer.d.ts +16 -0
  206. package/dist/record/probe-blend-buffer.d.ts.map +1 -0
  207. package/dist/record/recovery-pipeline.d.ts.map +1 -1
  208. package/dist/record/render-context.d.ts +22 -3
  209. package/dist/record/render-context.d.ts.map +1 -1
  210. package/dist/record/shadow-pass.d.ts +2 -0
  211. package/dist/record/shadow-pass.d.ts.map +1 -1
  212. package/dist/record/skybox-post-pass.d.ts +1 -1
  213. package/dist/record/skybox-post-pass.d.ts.map +1 -1
  214. package/dist/record/typed-frame-graph.d.ts +22 -2
  215. package/dist/record/typed-frame-graph.d.ts.map +1 -1
  216. package/dist/record/view-ubo.d.ts +11 -3
  217. package/dist/record/view-ubo.d.ts.map +1 -1
  218. package/dist/record/volume-params.d.ts +9 -0
  219. package/dist/record/volume-params.d.ts.map +1 -0
  220. package/dist/recovery/render-system-candidate.d.ts +10 -0
  221. package/dist/recovery/render-system-candidate.d.ts.map +1 -1
  222. package/dist/reflection/record-owner.d.ts.map +1 -1
  223. package/dist/render-contract.d.ts +42 -4
  224. package/dist/render-contract.d.ts.map +1 -1
  225. package/dist/render-graph-primitives.d.ts.map +1 -1
  226. package/dist/render-pipeline.d.ts +103 -2
  227. package/dist/render-pipeline.d.ts.map +1 -1
  228. package/dist/render-system-extract-tail.d.ts +3 -2
  229. package/dist/render-system-extract-tail.d.ts.map +1 -1
  230. package/dist/render-system-extract.d.ts +16 -9
  231. package/dist/render-system-extract.d.ts.map +1 -1
  232. package/dist/render-system-presentation.d.ts +23 -0
  233. package/dist/render-system-presentation.d.ts.map +1 -0
  234. package/dist/render-system-producer-roots.d.ts +10 -0
  235. package/dist/render-system-producer-roots.d.ts.map +1 -0
  236. package/dist/render-system-residency.d.ts +12 -0
  237. package/dist/render-system-residency.d.ts.map +1 -0
  238. package/dist/render-system.d.ts +19 -14
  239. package/dist/render-system.d.ts.map +1 -1
  240. package/dist/scene/probe-blend.d.ts +27 -0
  241. package/dist/scene/probe-blend.d.ts.map +1 -1
  242. package/dist/scene/render-scene.d.ts +12 -5
  243. package/dist/scene/render-scene.d.ts.map +1 -1
  244. package/dist/ssao-buffers.d.ts +9 -0
  245. package/dist/ssao-buffers.d.ts.map +1 -1
  246. package/dist/surface/dynamic-input.d.ts +133 -0
  247. package/dist/surface/dynamic-input.d.ts.map +1 -0
  248. package/dist/surface/gpu-driven.d.ts +41 -0
  249. package/dist/surface/gpu-driven.d.ts.map +1 -0
  250. package/dist/surface/submission-observation.d.ts +136 -0
  251. package/dist/surface/submission-observation.d.ts.map +1 -0
  252. package/dist/systems/skin-palette-allocator.d.ts.map +1 -1
  253. package/dist/temporal/gpu.d.ts +13 -1
  254. package/dist/temporal/gpu.d.ts.map +1 -1
  255. package/dist/temporal/index.mjs +5 -5
  256. package/dist/temporal/inspection.d.ts.map +1 -1
  257. package/dist/temporal/standard-scene-data.d.ts.map +1 -1
  258. package/dist/temporal/target-coverage-attachment.d.ts.map +1 -1
  259. package/dist/transmission/single-layer-medium.d.ts +89 -0
  260. package/dist/transmission/single-layer-medium.d.ts.map +1 -0
  261. package/dist/typed-render-graph-primitives.d.ts +14 -2
  262. package/dist/typed-render-graph-primitives.d.ts.map +1 -1
  263. package/dist/volume/component.d.ts +9 -4
  264. package/dist/volume/component.d.ts.map +1 -1
  265. package/dist/volume/extract.d.ts +1 -1
  266. package/dist/volume/extract.d.ts.map +1 -1
  267. package/dist/volume/inspection.d.ts +2 -0
  268. package/dist/volume/inspection.d.ts.map +1 -1
  269. package/dist/volume/passes.d.ts +4 -1
  270. package/dist/volume/passes.d.ts.map +1 -1
  271. package/dist/volume/resources.d.ts.map +1 -1
  272. package/package.json +22 -21
  273. package/src/__tests__/atmosphere-daylight.dawn.test.ts +72 -0
  274. package/src/__tests__/barrel-distortion-lkg.integration.test.ts +353 -0
  275. package/src/__tests__/barrel-distortion.dawn.test.ts +41 -0
  276. package/src/__tests__/barrel-distortion.unit.test.ts +364 -0
  277. package/src/__tests__/construct-renderer-identity.unit.test.ts +49 -0
  278. package/src/__tests__/detached-recovery-graph.unit.test.ts +277 -0
  279. package/src/__tests__/device-loss-fanout.unit.test.ts +36 -1
  280. package/src/__tests__/docs-gate-green.unit.test.ts +112 -1
  281. package/src/__tests__/factory-contract.integration.test.ts +295 -45
  282. package/src/__tests__/feature-depth-input.dawn.test.ts +129 -2
  283. package/src/__tests__/fullscreen-feature-plan.unit.test.ts +14 -3
  284. package/src/__tests__/gpu-dirty-ranges.unit.test.ts +22 -0
  285. package/src/__tests__/gpu-driven-baseline.characterization.test.ts +16 -3
  286. package/src/__tests__/gpu-driven-batch-topology-pbr.unit.test.ts +12 -0
  287. package/src/__tests__/gpu-driven-material-artifacts.unit.test.ts +143 -0
  288. package/src/__tests__/gpu-driven-pbr.dawn.test.ts +2 -2
  289. package/src/__tests__/gpu-driven-production.integration.test.ts +482 -3
  290. package/src/__tests__/gpu-driven-shadow-views.dawn.test.ts +6 -5
  291. package/src/__tests__/gpu-driven-view-gpu-evidence.ts +94 -6
  292. package/src/__tests__/gpu-driven-view-graph.integration.test.ts +18 -2
  293. package/src/__tests__/gpu-driven-view.browser.test.ts +5 -8
  294. package/src/__tests__/gpu-driven-view.dawn.test.ts +6 -2
  295. package/src/__tests__/gpu-driven-view.unit.test.ts +1 -1
  296. package/src/__tests__/gpu-pass-timing-lifecycle.integration.test.ts +1 -0
  297. package/src/__tests__/gpu-pass-timing.browser.test.ts +6 -4
  298. package/src/__tests__/gpu-pass-timing.rhi-null.unit.test.ts +1 -0
  299. package/src/__tests__/gpu-scene.unit.test.ts +119 -9
  300. package/src/__tests__/instance-allocation-failure.unit.test.ts +57 -0
  301. package/src/__tests__/instances-culling.integration.test.ts +10 -36
  302. package/src/__tests__/instances-store.unit.test.ts +97 -305
  303. package/src/__tests__/instances-world-ownership.integration.test.ts +62 -0
  304. package/src/__tests__/main-pass-material-medium-selection.unit.test.ts +146 -0
  305. package/src/__tests__/material-shader-prewarm.unit.test.ts +59 -0
  306. package/src/__tests__/material-snapshot-mutation.integration.test.ts +39 -1
  307. package/src/__tests__/morph-culling-reentry.dawn.test.ts +5 -5
  308. package/src/__tests__/morph-visual-evidence.integration.test.ts +8 -7
  309. package/src/__tests__/motion-blur-compute.dawn.test.ts +13 -7
  310. package/src/__tests__/motion-blur.pixel.integration.test.ts +2 -2
  311. package/src/__tests__/nineslice-handle-surface.unit.test.ts +4 -4
  312. package/src/__tests__/pbr-view-layout.unit.test.ts +9 -0
  313. package/src/__tests__/physical-clearcoat.integration.test.ts +58 -0
  314. package/src/__tests__/prepared-graphics-capability.unit.test.ts +66 -2
  315. package/src/__tests__/probe-bindings.unit.test.ts +582 -1
  316. package/src/__tests__/probe-scene-dirty.integration.test.ts +28 -1
  317. package/src/__tests__/receipt-observation-retirement.unit.test.ts +65 -0
  318. package/src/__tests__/recovery-candidate-prepare.contract.test.ts +69 -0
  319. package/src/__tests__/render-error-code-owner.test-d.ts +7 -0
  320. package/src/__tests__/render-feature-diagnostics.unit.test.ts +15 -2
  321. package/src/__tests__/render-feature-error-reporting.unit.test.ts +21 -1
  322. package/src/__tests__/render-feature-prepared-diagnostics.unit.test.ts +10 -1
  323. package/src/__tests__/render-feature-retry.unit.test.ts +12 -1
  324. package/src/__tests__/render-scene-mixed-updates.integration.test.ts +145 -19
  325. package/src/__tests__/render-scene-projection.unit.test.ts +36 -11
  326. package/src/__tests__/render-scene-temporal-retry.unit.test.ts +20 -20
  327. package/src/__tests__/render-target-probe-soak.perf.test.ts +2 -2
  328. package/src/__tests__/render-temporal-environment-consumer.browser.test.ts +3 -3
  329. package/src/__tests__/render-temporal-environment-consumer.dawn.test.ts +5 -2
  330. package/src/__tests__/renderer-factory-material-contract.unit.test.ts +41 -7
  331. package/src/__tests__/renderer-frame-generation-fence.integration.test.ts +16 -0
  332. package/src/__tests__/renderer-frame-transaction.integration.test.ts +26 -10
  333. package/src/__tests__/resource-allocation.unit.test.ts +123 -0
  334. package/src/__tests__/single-layer-medium-passes.unit.test.ts +275 -0
  335. package/src/__tests__/skin-motion-regression.unit.test.ts +70 -1
  336. package/src/__tests__/skin-palette-recycling.dawn.test.ts +97 -0
  337. package/src/__tests__/skinned-shadow-caster.test.ts +15 -0
  338. package/src/__tests__/ssr-carrier-public-contract.unit.test.ts +21 -0
  339. package/src/__tests__/ssr-gpu-dispatch.browser.test.ts +4 -4
  340. package/src/__tests__/ssr-gpu-dispatch.dawn.test.ts +2 -2
  341. package/src/__tests__/ssr-gpu-dispatch.ts +1 -1
  342. package/src/__tests__/ssr-receiver-coverage.dawn.test.ts +6 -2
  343. package/src/__tests__/standard-output-chain-contract.unit.test.ts +28 -0
  344. package/src/__tests__/standard-pbr-artifact-assembly.unit.test.ts +46 -1
  345. package/src/__tests__/standard-pipeline.integration.test.ts +182 -1
  346. package/src/__tests__/surface-dynamic-buffer-lifecycle.unit.test.ts +506 -0
  347. package/src/__tests__/surface-submission-observation.unit.test.ts +812 -0
  348. package/src/__tests__/temporal-history-lifecycle.unit.test.ts +32 -0
  349. package/src/__tests__/temporal-performance.integration.test.ts +3 -3
  350. package/src/__tests__/visibility-instances.integration.test.ts +7 -19
  351. package/src/__tests__/visibility-producer-matrix.integration.test.ts +9 -20
  352. package/src/__tests__/volume-optics-oracle.unit.test.ts +4 -2
  353. package/src/__tests__/volumetric-fog-budget-recovery.integration.test.ts +30 -20
  354. package/src/__tests__/volumetric-fog-errors.unit.test.ts +4 -3
  355. package/src/__tests__/volumetric-fog-multiple.unit.test.ts +55 -0
  356. package/src/__tests__/volumetric-fog-spot-frame-optics.integration.test.ts +1 -1
  357. package/src/__tests__/volumetric-fog-stage-readback.dawn.test.ts +113 -9
  358. package/src/__tests__/volumetric-fog-topology.unit.test.ts +5 -3
  359. package/src/assembly/backend-contract.ts +30 -0
  360. package/src/assembly/barrel-distortion-inspection.ts +22 -0
  361. package/src/assembly/canvas-draw-guard.ts +11 -0
  362. package/src/assembly/cloud-shadow-entry.ts +22 -0
  363. package/src/assembly/dynamic-geometry-host.ts +65 -37
  364. package/src/assembly/dynamic-geometry-runtime.ts +7 -1
  365. package/src/assembly/factory.ts +2 -30
  366. package/src/assembly/host-contract.ts +3 -3
  367. package/src/assembly/material/assembly.ts +25 -13
  368. package/src/assembly/material/pipeline-helpers.ts +53 -12
  369. package/src/assembly/material-shader-policy.ts +55 -0
  370. package/src/assembly/material-shader-prewarm.ts +21 -10
  371. package/src/assembly/recovery/device-loss-fanout.ts +13 -0
  372. package/src/assembly/recovery/renderer-recover.ts +41 -18
  373. package/src/assembly/render-feature-post-processes.ts +54 -0
  374. package/src/assembly/renderer-facade.ts +4 -1
  375. package/src/assembly/renderer-feature-inspection.ts +8 -2
  376. package/src/assembly/renderer-frame-transaction.ts +23 -0
  377. package/src/assembly/renderer-inspection.ts +28 -0
  378. package/src/assembly/skin-palette-owner.ts +1 -1
  379. package/src/assembly/temporal-post-process-prewarm.ts +3 -3
  380. package/src/assembly/webgpu-pbr-ready.ts +9 -1
  381. package/src/assembly/webgpu-ready-per-pass.ts +104 -0
  382. package/src/assembly/webgpu-ready.ts +115 -61
  383. package/src/assembly/webgpu-renderer-bootstrap.ts +0 -12
  384. package/src/assembly/webgpu-renderer-observation-owner.ts +222 -0
  385. package/src/assembly/webgpu-renderer.ts +214 -252
  386. package/src/assembly/webgpu-vertex-layouts.ts +1 -1
  387. package/src/barrel-distortion.ts +247 -0
  388. package/src/cloud/__tests__/cloud-density-parity.dawn.test.ts +173 -0
  389. package/src/cloud/__tests__/cloud-layer-framebuffer-y.dawn.test.ts +265 -0
  390. package/src/cloud/__tests__/cloud-layer.browser.test.ts +432 -0
  391. package/src/cloud/__tests__/cloud-layer.unit.test.ts +634 -0
  392. package/src/cloud/density.ts +600 -0
  393. package/src/cloud/extract.ts +110 -0
  394. package/src/cloud/feature.ts +1810 -0
  395. package/src/cloud/frame-context.ts +42 -0
  396. package/src/cloud/inspection.ts +130 -0
  397. package/src/cloud/optics.ts +285 -0
  398. package/src/cloud/parameters.ts +255 -0
  399. package/src/cloud/resources.ts +122 -0
  400. package/src/cloud/shadow.ts +167 -0
  401. package/src/cloud/temporal.ts +226 -0
  402. package/src/components/barrel-distortion.ts +46 -0
  403. package/src/components/cloud-layer.ts +47 -0
  404. package/src/components/index.ts +2 -0
  405. package/src/components/instances.ts +18 -45
  406. package/src/components/sprite-instances.ts +1 -1
  407. package/src/construct-renderer.ts +1 -1
  408. package/src/dynamic-geometry.ts +12 -1
  409. package/src/errors/cloud.ts +103 -0
  410. package/src/errors/render.ts +44 -7
  411. package/src/examples/single-layer-medium-surface.ts +59 -0
  412. package/src/extract/camera.ts +15 -1
  413. package/src/extract/contracts.ts +5 -0
  414. package/src/features/barrel-distortion.ts +172 -0
  415. package/src/features/error-reporting.ts +26 -6
  416. package/src/features/host.ts +115 -14
  417. package/src/features/plan.ts +8 -0
  418. package/src/features/render-graph-contribution.ts +9 -0
  419. package/src/features/render-graph-raster.ts +45 -3
  420. package/src/features/targets.ts +66 -0
  421. package/src/features/types.ts +47 -0
  422. package/src/fullscreen-post-process-pass.ts +41 -9
  423. package/src/gpu-dirty-ranges.ts +48 -0
  424. package/src/gpu-driven/batch-topology.ts +53 -0
  425. package/src/gpu-driven/material-artifacts.ts +33 -25
  426. package/src/gpu-driven/prepared-draw.ts +12 -4
  427. package/src/gpu-driven/production-raster-material.ts +1894 -0
  428. package/src/gpu-driven/production-raster.ts +825 -784
  429. package/src/gpu-driven/resource-allocation.ts +142 -0
  430. package/src/gpu-driven/shadow-ownership.ts +71 -0
  431. package/src/gpu-driven/view-gpu.ts +164 -10
  432. package/src/gpu-scene.ts +75 -84
  433. package/src/hdrp-buffers.ts +4 -3
  434. package/src/ibl/skylight-bind-group.ts +49 -7
  435. package/src/index.ts +196 -9
  436. package/src/inspection-types.ts +162 -0
  437. package/src/instance-buffer-cache.ts +4 -4
  438. package/src/instances.ts +149 -569
  439. package/src/pbr-pipeline.ts +219 -13
  440. package/src/pipeline/single-layer-medium-passes.ts +267 -0
  441. package/src/pipeline/standard-forward-lane.ts +313 -57
  442. package/src/pipeline/standard-output/graph.ts +8 -2
  443. package/src/pipeline/standard-output/types.ts +12 -1
  444. package/src/pipeline/standard-pipeline.ts +291 -18
  445. package/src/pipeline/standard-post.ts +90 -24
  446. package/src/pipeline-builder.ts +1 -1
  447. package/src/plugin.ts +4 -0
  448. package/src/points-lines/__tests__/points-lines.bench.ts +17 -8
  449. package/src/prepare/prepared-graphics-resolver.ts +2 -0
  450. package/src/record/__tests__/main-pass-geometry.unit.test.ts +30 -0
  451. package/src/record/__tests__/sprite-material-abi.unit.test.ts +1 -1
  452. package/src/record/__tests__/temporal-payload.unit.test.ts +1 -1
  453. package/src/record/__tests__/transparent-group2-selection.unit.test.ts +11 -0
  454. package/src/record/__tests__/typed-frame-graph-plan.unit.test.ts +1 -0
  455. package/src/record/__tests__/view-ubo-layout.unit.test.ts +4 -3
  456. package/src/record/barrel-distortion-frame.ts +110 -0
  457. package/src/record/dynamic-geometry-consumption.ts +39 -9
  458. package/src/record/fold-buckets.ts +852 -0
  459. package/src/record/fold-instance-buffer.ts +51 -0
  460. package/src/record/frame-lighting.ts +36 -2
  461. package/src/record/frame-snapshot.ts +39 -3
  462. package/src/record/frame.ts +217 -1084
  463. package/src/record/gpu-draw-receipts.ts +38 -0
  464. package/src/record/gpu-timing.ts +48 -5
  465. package/src/record/main-pass-geometry.ts +251 -82
  466. package/src/record/main-pass-material.ts +66 -4
  467. package/src/record/main-pass-sprite-draws.ts +7 -65
  468. package/src/record/main-pass.ts +156 -20
  469. package/src/record/motion-blur-receipt.ts +91 -0
  470. package/src/record/probe-blend-buffer.ts +180 -0
  471. package/src/record/recovery-pipeline.ts +35 -3
  472. package/src/record/render-context.ts +39 -3
  473. package/src/record/shadow-pass.ts +30 -1
  474. package/src/record/skybox-post-pass.ts +28 -4
  475. package/src/record/typed-frame-graph.ts +770 -134
  476. package/src/record/view-ubo.ts +26 -3
  477. package/src/record/volume-params.ts +225 -0
  478. package/src/recovery/render-system-candidate.ts +235 -42
  479. package/src/reflection/record-owner.ts +7 -3
  480. package/src/render-contract.ts +48 -4
  481. package/src/render-graph-primitives.ts +7 -1
  482. package/src/render-pipeline.ts +130 -0
  483. package/src/render-system-extract-tail.ts +57 -61
  484. package/src/render-system-extract.ts +74 -76
  485. package/src/render-system-presentation.ts +56 -0
  486. package/src/render-system-producer-roots.ts +96 -0
  487. package/src/render-system-residency.ts +159 -0
  488. package/src/render-system.ts +347 -363
  489. package/src/scene/probe-blend.ts +96 -4
  490. package/src/scene/render-scene.ts +349 -280
  491. package/src/ssao-buffers.ts +95 -2
  492. package/src/surface/__tests__/dynamic-input.unit.test.ts +374 -0
  493. package/src/surface/__tests__/gpu-driven.unit.test.ts +87 -0
  494. package/src/surface/dynamic-input.ts +658 -0
  495. package/src/surface/gpu-driven.ts +147 -0
  496. package/src/surface/submission-observation.ts +517 -0
  497. package/src/systems/skin-palette-allocator.ts +4 -1
  498. package/src/temporal/gpu.ts +101 -17
  499. package/src/temporal/inspection.ts +7 -1
  500. package/src/temporal/standard-scene-data.ts +5 -0
  501. package/src/temporal/target-coverage-attachment.ts +4 -0
  502. package/src/transmission/__tests__/single-layer-medium.unit.test.ts +149 -0
  503. package/src/transmission/__tests__/standard-transmission.dawn.test.ts +12 -11
  504. package/src/transmission/single-layer-medium.ts +322 -0
  505. package/src/typed-render-graph-primitives.ts +70 -2
  506. package/src/volume/component.ts +10 -9
  507. package/src/volume/extract.ts +11 -5
  508. package/src/volume/inspection.ts +3 -0
  509. package/src/volume/passes.ts +87 -4
  510. package/src/volume/resources.ts +2 -1
  511. package/dist/chunk-3RTCJTH4.mjs.map +0 -1
  512. package/dist/chunk-NB2S7ZRX.mjs.map +0 -1
  513. package/dist/chunk-NNQL7CB3.mjs +0 -1713
  514. package/dist/chunk-NNQL7CB3.mjs.map +0 -1
  515. package/dist/chunk-OO3DRYK7.mjs.map +0 -1
  516. package/dist/chunk-PA5DRJNI.mjs.map +0 -1
  517. package/dist/chunk-PLAXOOX5.mjs.map +0 -1
  518. package/dist/chunk-VOZWDM3L.mjs.map +0 -1
@@ -43,11 +43,9 @@ import type { PointsLinesRecordPlan } from '../points-lines/record';
43
43
  import { POINTS_LINES_MATERIAL_SHADER_ID } from '../points-lines/record';
44
44
  import type { RenderRecordPhase } from '../render-contract';
45
45
  import type { DispatchEntry, MaterialSnapshot, RenderableSnapshot } from '../render-system-extract';
46
- import {
47
- PROBE_BLEND_RECORD_BYTE_SIZE,
48
- PROBE_BLEND_RECORD_STRIDE,
49
- probeBlendRecordOffset,
50
- } from '../scene/probe-blend-record';
46
+ import { PROBE_BLEND_RECORD_BYTE_SIZE, probeBlendRecordOffset } from '../scene/probe-blend-record';
47
+ import type { SurfacePassName } from '../surface/submission-observation';
48
+ import { resolveFoldInstanceBuffer } from './fold-instance-buffer';
51
49
  import {
52
50
  getOpaqueResourceIdentity,
53
51
  instanceCollectionCacheKey,
@@ -69,6 +67,7 @@ import {
69
67
  MESH_UBO_FULL_ARRAY_BYTES,
70
68
  packInstanceStorageBuffer,
71
69
  } from './mesh-ssbo';
70
+ import { ensureProbeBlendRecordBuffer } from './probe-blend-buffer';
72
71
  import type { _InternalRenderPipelineContext, MaterialShaderPipelineEntry } from './render-context';
73
72
  import { MATERIAL_PER_ENTITY_STRIDE } from './render-context';
74
73
  import { POINTS_LINES_VIEW_SLOT_STRIDE, writePointsLinesViewUbo } from './view-ubo';
@@ -93,11 +92,19 @@ export function sameOpaqueTemporalDraw(a: DispatchEntry, b: DispatchEntry): bool
93
92
  type GeometryInstanceDraw = {
94
93
  readonly instanceBuffer: Buffer;
95
94
  readonly instanceBindGroup: BindGroup;
95
+ /** Producer-owned Probe buffer paired with probeOffset, when present. */
96
+ readonly probeBuffer?: Buffer;
96
97
  /** -1 means the no-probe layout and therefore no dynamic offset. */
97
98
  readonly probeOffset: number;
99
+ readonly dynamicOffsets?: readonly number[];
98
100
  readonly instanceCount: number;
101
+ readonly firstInstanceOrdinal?: number;
102
+ readonly surfaceFrameBase?: number;
103
+ readonly surfaceMemberIds?: readonly string[];
99
104
  };
100
105
 
106
+ type DirectSurfaceLayoutKind = 'surface-direct-pbr' | 'surface-direct-cluster-pbr';
107
+
101
108
  type InstanceUploadResult =
102
109
  | {
103
110
  readonly ok: true;
@@ -113,6 +120,7 @@ type InstanceUploadResult =
113
120
  type GeometryBindingState = {
114
121
  pipeline: RenderPipeline | null;
115
122
  instancesBuffer: Buffer | null;
123
+ instanceBindGroup: BindGroup | null;
116
124
  probeOffset: number;
117
125
  };
118
126
 
@@ -143,6 +151,7 @@ type MaterialPipelineLookup = {
143
151
  readonly colorFormatOverride: GPUTextureFormat | undefined;
144
152
  readonly additionalColorFormats: readonly GPUTextureFormat[] | undefined;
145
153
  readonly textureMask: number | undefined;
154
+ readonly layoutKind: DirectSurfaceLayoutKind | undefined;
146
155
  readonly handle: MaterialShaderPipelineEntry | null;
147
156
  };
148
157
 
@@ -219,10 +228,11 @@ function isGpuDrivenMainClaimedSubmesh(
219
228
  if (drawItemIndex === undefined || draw === undefined) return false;
220
229
  const material = source.materials[draw.materialSlot] ?? source.material;
221
230
  const sourceDrawItemIndex = gpuDrivenSourceDrawItemIndex(draw, drawItemIndex);
231
+ const stableWorld = c.gpuDrivenWorldKeys?.[source.worldId] ?? source.worldId;
222
232
  return (
223
233
  c.gpuDrivenDrawKeys?.has(
224
234
  gpuDrivenDrawKey(
225
- worldEntityKey(source.worldId, source.entityKey),
235
+ worldEntityKey(stableWorld, source.entityKey),
226
236
  material.materialHandle ?? -1,
227
237
  sourceDrawItemIndex,
228
238
  ),
@@ -365,6 +375,22 @@ export function geometryRenderStateForPass(
365
375
  };
366
376
  }
367
377
 
378
+ /**
379
+ * Transparent depth is an authored medium policy. A transparent pass with no
380
+ * explicit depth-write bit remains read-only, which keeps alpha smoke and
381
+ * ordinary blending from becoming an opaque occluder; water or a cutout-like
382
+ * medium can opt in by setting the bit on its own pass state.
383
+ */
384
+ export function authoredTransparentDepthWrite(
385
+ transparent: boolean | undefined,
386
+ renderState: MaterialSnapshot['renderState'],
387
+ ): boolean {
388
+ return (
389
+ (transparent === true || renderState?.blend !== undefined) &&
390
+ renderState?.depthWriteEnabled === true
391
+ );
392
+ }
393
+
368
394
  function geometryRecordPhase(
369
395
  passKind: PassKind,
370
396
  segment: GeometryRecordProfileSegment,
@@ -394,7 +420,7 @@ function submitSubmeshDraws(
394
420
  indexCount: number,
395
421
  vertexCount: number,
396
422
  indexOffset: number,
397
- onDraw?: () => void,
423
+ onDraw?: (draw: GeometryInstanceDraw, command: 'draw' | 'draw-indexed') => void,
398
424
  ): void {
399
425
  if (state.pipeline !== pipeline) {
400
426
  pass.setPipeline(pipeline);
@@ -403,14 +429,18 @@ function submitSubmeshDraws(
403
429
  for (const instanceDraw of instanceDraws) {
404
430
  if (
405
431
  instanceDraw.instanceBuffer !== state.instancesBuffer ||
432
+ instanceDraw.instanceBindGroup !== state.instanceBindGroup ||
406
433
  instanceDraw.probeOffset !== state.probeOffset
407
434
  ) {
408
- if (instanceDraw.probeOffset < 0) {
435
+ if (instanceDraw.dynamicOffsets !== undefined) {
436
+ pass.setBindGroup(3, instanceDraw.instanceBindGroup, instanceDraw.dynamicOffsets);
437
+ } else if (instanceDraw.probeOffset < 0) {
409
438
  pass.setBindGroup(3, instanceDraw.instanceBindGroup);
410
439
  } else {
411
440
  pass.setBindGroup(3, instanceDraw.instanceBindGroup, [instanceDraw.probeOffset]);
412
441
  }
413
442
  state.instancesBuffer = instanceDraw.instanceBuffer;
443
+ state.instanceBindGroup = instanceDraw.instanceBindGroup;
414
444
  state.probeOffset = instanceDraw.probeOffset;
415
445
  }
416
446
  if (indexed) {
@@ -418,7 +448,7 @@ function submitSubmeshDraws(
418
448
  } else {
419
449
  pass.draw(vertexCount, instanceDraw.instanceCount, 0, 0);
420
450
  }
421
- onDraw?.();
451
+ onDraw?.(instanceDraw, indexed ? 'draw-indexed' : 'draw');
422
452
  }
423
453
  }
424
454
 
@@ -472,6 +502,9 @@ export function recordGeometryDraws(
472
502
  selectedDispatch?: readonly DispatchEntry[],
473
503
  colorFormats: readonly GPUTextureFormat[] = [],
474
504
  coverageOnly = false,
505
+ fragmentEntryPoint?: string,
506
+ surfacePass?: SurfacePassName,
507
+ transparentDepthWrite = false,
475
508
  ): void {
476
509
  const {
477
510
  runtime,
@@ -520,6 +553,7 @@ export function recordGeometryDraws(
520
553
  const bindingState: GeometryBindingState = {
521
554
  pipeline: null,
522
555
  instancesBuffer: null,
556
+ instanceBindGroup: null,
523
557
  probeOffset: -1,
524
558
  };
525
559
  const identityInstanceBuffer = pipelineState.identityInstanceBuffer;
@@ -563,6 +597,7 @@ export function recordGeometryDraws(
563
597
  vertexEntry?: string,
564
598
  fragmentEntry?: string,
565
599
  textureMask?: number,
600
+ layoutKind?: DirectSurfaceLayoutKind,
566
601
  ): MaterialShaderPipelineEntry | null => {
567
602
  const pipelineVariantSet = withCoverageVariant(variantSet);
568
603
  // The fallback MRT is an extension of the built-in Standard PBR output
@@ -594,6 +629,7 @@ export function recordGeometryDraws(
594
629
  cached.vertexEntry === vertexEntry &&
595
630
  cached.fragmentEntry === fragmentEntry &&
596
631
  cached.textureMask === textureMask &&
632
+ cached.layoutKind === layoutKind &&
597
633
  cached.passKind === passKind &&
598
634
  cached.layoutProjection.digest === layoutProjection.digest &&
599
635
  cached.sampleCount === sampleCount &&
@@ -604,8 +640,13 @@ export function recordGeometryDraws(
604
640
  }
605
641
  }
606
642
  }
643
+ // Published Surface artifacts carry both direct and scene-index modules.
644
+ // The boot artifact may be the scene-index specialization selected by the
645
+ // retained producer, so a direct slot-3 layout must still resolve the
646
+ // explicit capability key. This keeps the module source, entry point and
647
+ // pipeline layout on the same GPU_DRIVEN_SCENE_INDEX_AVAILABLE=false ABI.
607
648
  const resolvedVariantSetResult =
608
- runtime.getMaterialArtifact?.(materialShaderId) !== undefined
649
+ runtime.getMaterialArtifact?.(materialShaderId) !== undefined && layoutKind === undefined
609
650
  ? ({ ok: true, value: undefined } as const)
610
651
  : pipelineVariantSet === undefined &&
611
652
  (materialShaderId === 'forgeax::sprite' || materialShaderId === 'forgeax::sprite-lit')
@@ -639,7 +680,7 @@ export function recordGeometryDraws(
639
680
  undefined,
640
681
  layoutProjection,
641
682
  undefined,
642
- undefined,
683
+ layoutKind,
643
684
  undefined,
644
685
  reflectionFallbackFormats,
645
686
  vertexEntry,
@@ -674,6 +715,7 @@ export function recordGeometryDraws(
674
715
  colorFormatOverride: colorFormat,
675
716
  additionalColorFormats: reflectionFallbackFormats,
676
717
  textureMask,
718
+ layoutKind,
677
719
  handle,
678
720
  };
679
721
  if (shaderLookupCache === undefined) {
@@ -693,6 +735,9 @@ export function recordGeometryDraws(
693
735
  for (let i = 0; i < validatedOrdered.length; i++) {
694
736
  const entry = validatedOrdered[i];
695
737
  if (entry === undefined) continue;
738
+ // The typed transparent pass uses this common draw owner. Consume the
739
+ // same fold plan as the legacy sprite pass, including coverage/depth draws.
740
+ if (c.foldDispatchPlan?.skipIndices.has(i) === true) continue;
696
741
  // Points/Lines share the Standard geometry pass. Their retained source
697
742
  // is prepared once by the renderer owner, while this loop remains the
698
743
  // sole pass/draw submission owner and preserves the authored topology.
@@ -822,8 +867,22 @@ export function recordGeometryDraws(
822
867
  // length instead.
823
868
  if (pipelineTag === 'unlit') dispatchCounts.unlit += 1;
824
869
 
825
- const instanceDraws = resolveGeometryInstanceBuffer(c, entry, identityInstanceDraws, false);
826
- if (instanceDraws === null) continue;
870
+ const fold = c.foldDispatchPlan?.headBuckets.get(i);
871
+ const foldBuffer = fold === undefined ? null : resolveFoldInstanceBuffer(c, fold, i);
872
+ const baseInstanceDraws =
873
+ fold === undefined
874
+ ? resolveGeometryInstanceBuffer(c, entry, identityInstanceDraws, false)
875
+ : foldBuffer === null
876
+ ? null
877
+ : [
878
+ {
879
+ instanceBuffer: foldBuffer,
880
+ instanceBindGroup: resolveGeometryInstancesBindGroup(c, foldBuffer, undefined),
881
+ probeOffset: -1,
882
+ instanceCount: fold.bucketSize,
883
+ },
884
+ ];
885
+ if (baseInstanceDraws === null) continue;
827
886
 
828
887
  // feat-20260611 R2 / M8 / w28 (IS-14): skin entries need a 3-binding
829
888
  // group(2) BG matching `pbr-skin-pl` (binding 0 mesh-array UBO +
@@ -1114,16 +1173,22 @@ export function recordGeometryDraws(
1114
1173
  ) {
1115
1174
  continue;
1116
1175
  }
1176
+ const selectedMaterialPasses = materialPasses
1177
+ .get(entry.renderableIndex)
1178
+ ?.get(submeshMaterial.materialHandle ?? 0);
1117
1179
  const draws: readonly (DispatchEntry | undefined)[] =
1118
- selectedDispatch === undefined
1180
+ selectedDispatch === undefined ||
1181
+ (selectedMaterialPasses === undefined &&
1182
+ submeshMaterial.surfaceModel === 'single-layer-medium' &&
1183
+ matchedMaterials?.get(entry.renderableIndex)?.has(submeshMaterial.materialHandle ?? 0))
1119
1184
  ? [undefined]
1120
- : (materialPasses.get(entry.renderableIndex)?.get(submeshMaterial.materialHandle ?? 0) ??
1121
- []);
1185
+ : (selectedMaterialPasses ?? []);
1122
1186
  for (const selectedPass of draws) {
1123
1187
  // Temporal projects the selected material's alpha/motion contract,
1124
1188
  // not its authored Forward entry points or color outputs.
1125
1189
  const vertexEntry = passKind === 'temporal' ? undefined : selectedPass?.vertexEntry;
1126
- const fragmentEntry = passKind === 'temporal' ? undefined : selectedPass?.fragmentEntry;
1190
+ const fragmentEntry =
1191
+ passKind === 'temporal' ? undefined : (fragmentEntryPoint ?? selectedPass?.fragmentEntry);
1127
1192
  const selectedShaderId =
1128
1193
  selectedPass === undefined
1129
1194
  ? submeshMaterial.materialShaderId
@@ -1228,7 +1293,9 @@ export function recordGeometryDraws(
1228
1293
  : SKIN_MATERIAL_SHADER_ID
1229
1294
  : submeshMaterial.materialShaderId;
1230
1295
  const probeBlendAvailable =
1231
- probeBlendRecordAvailable && isStandardPbrMaterialShader(smMaterialShaderId);
1296
+ probeBlendRecordAvailable &&
1297
+ (isStandardPbrMaterialShader(smMaterialShaderId) ||
1298
+ submeshMaterial.surfaceModel === 'single-layer-medium');
1232
1299
  const isSpriteShader =
1233
1300
  smMaterialShaderId === 'forgeax::sprite' || smMaterialShaderId === 'forgeax::sprite-lit';
1234
1301
  // Preserve the dedicated sprite-pass state when the linear-LDR graph
@@ -1243,11 +1310,25 @@ export function recordGeometryDraws(
1243
1310
  blend: selectedRenderState?.blend ?? SPRITE_PREMULTIPLIED_ALPHA_BLEND,
1244
1311
  }
1245
1312
  : geometryRenderStateForTopology(smTopology, selectedRenderState);
1246
- const pipelineRenderState = geometryRenderStateForPass(
1313
+ let pipelineRenderState = geometryRenderStateForPass(
1247
1314
  basePipelineRenderState,
1248
1315
  passKind,
1249
1316
  coverageOnly,
1250
1317
  );
1318
+ if (
1319
+ transparentDepthWrite &&
1320
+ passKind === 'forward' &&
1321
+ (submeshMaterial.transparent === true || selectedRenderState?.blend !== undefined)
1322
+ ) {
1323
+ pipelineRenderState = {
1324
+ ...pipelineRenderState,
1325
+ depthWriteEnabled: authoredTransparentDepthWrite(
1326
+ submeshMaterial.transparent,
1327
+ selectedRenderState,
1328
+ ),
1329
+ depthCompare: 'less-equal',
1330
+ };
1331
+ }
1251
1332
  let smPipelineHandle: typeof pipelineState.unlitPipeline;
1252
1333
  let materialGroup2Contract: 'mesh' | 'skin' | 'cluster' | 'skin-cluster' | undefined;
1253
1334
  let materialPipelineEntry: MaterialShaderPipelineEntry | null = null;
@@ -1319,15 +1400,17 @@ export function recordGeometryDraws(
1319
1400
  transmissionAvailable && !capabilityVariantSet.includes('TRANSMISSION_AVAILABLE=')
1320
1401
  ? `${capabilityVariantSet}+TRANSMISSION_AVAILABLE=true`
1321
1402
  : capabilityVariantSet;
1322
- // Sprite's base request must retain the boot-selected artifact. Only
1323
- // SpriteInstances uses the explicit empty key for the
1324
- // PER_INSTANCE_REGION=true variant; synthesizing the generic PBR
1325
- // capability axes for a base sprite would invent a lazy module label
1326
- // that has no boot seed and skip the first HDR draw.
1403
+ // Regular sprite keeps the boot-selected artifact; SpriteInstances
1404
+ // uses the explicit empty key for PER_INSTANCE_REGION=true. Sprite-lit
1405
+ // is different: the typed Standard transparent lane records it here,
1406
+ // so its shader must follow the frame-owned cluster topology or local
1407
+ // lights disappear while the ordinary sprite path remains direct.
1327
1408
  const variantSet = isSpriteShader
1328
- ? smMaterialShaderId === 'forgeax::sprite' && entry.source.spriteInstances !== undefined
1329
- ? ''
1330
- : undefined
1409
+ ? smMaterialShaderId === 'forgeax::sprite-lit'
1410
+ ? materialCapabilityVariantSet
1411
+ : entry.source.spriteInstances !== undefined
1412
+ ? ''
1413
+ : undefined
1331
1414
  : entry.variantSet === undefined
1332
1415
  ? materialCapabilityVariantSet
1333
1416
  : `${materialCapabilityVariantSet}+${entry.variantSet}`;
@@ -1342,6 +1425,11 @@ export function recordGeometryDraws(
1342
1425
  vertexEntry,
1343
1426
  fragmentEntry,
1344
1427
  submeshMaterial.standardTextureMask,
1428
+ submeshMaterial.surfaceModel === 'single-layer-medium' && passKind === 'forward'
1429
+ ? capabilityVariantSet.includes('CLUSTER_FORWARD_AVAILABLE=true')
1430
+ ? 'surface-direct-cluster-pbr'
1431
+ : 'surface-direct-pbr'
1432
+ : undefined,
1345
1433
  );
1346
1434
  // feat-20260615-pipeline-spec-ssot M6-T1: cache miss resolves to
1347
1435
  // null uniformly across URP / HDRP / skin shaders. Charter P3
@@ -1380,12 +1468,28 @@ export function recordGeometryDraws(
1380
1468
  // renderable, but unlit/custom shaders still use the one-binding
1381
1469
  // instances BGL and must never receive the probe bind group. Resolve
1382
1470
  // this per submesh so mixed-material meshes cannot cross the layouts.
1383
- const instanceDraws = resolveGeometryInstanceBuffer(
1384
- c,
1385
- entry,
1386
- identityInstanceDraws,
1387
- probeBlendAvailable,
1388
- );
1471
+ const resolvedInstanceDraws = probeBlendAvailable
1472
+ ? resolveGeometryInstanceBuffer(c, entry, identityInstanceDraws, true)
1473
+ : baseInstanceDraws;
1474
+ if (resolvedInstanceDraws === null) continue;
1475
+ const compactDrawIndex = gpuDrivenDrawIndices.get(smIdx);
1476
+ const compactDraw =
1477
+ compactDrawIndex === undefined
1478
+ ? undefined
1479
+ : entry.source.gpuDrivenDraws?.[compactDrawIndex];
1480
+ const sourceDrawItemIndex =
1481
+ compactDrawIndex === undefined || compactDraw === undefined
1482
+ ? smIdx
1483
+ : gpuDrivenSourceDrawItemIndex(compactDraw, compactDrawIndex);
1484
+ const instanceDraws =
1485
+ submeshMaterial.surfaceModel === 'single-layer-medium' && passKind === 'forward'
1486
+ ? resolveSurfaceDirectInstanceDraws(
1487
+ c,
1488
+ entry,
1489
+ sourceDrawItemIndex,
1490
+ resolvedInstanceDraws,
1491
+ )
1492
+ : resolvedInstanceDraws;
1389
1493
  if (instanceDraws === null) continue;
1390
1494
  // Standard clustered PBR variants declare the unified cluster/SSAO
1391
1495
  // group(2) layout. Unlit and other URP-layout materials must bind the
@@ -1441,7 +1545,26 @@ export function recordGeometryDraws(
1441
1545
  sm.indexCount,
1442
1546
  sm.vertexCount,
1443
1547
  sm.indexOffset,
1444
- () => c.onRenderableDraw?.(entry),
1548
+ (draw, command) => {
1549
+ c.onRenderableDraw?.(entry, smIdx);
1550
+ if (surfacePass === undefined || draw.surfaceFrameBase === undefined) return;
1551
+ c.frameState.surfaceSubmissionObservation?.record(surfacePass, {
1552
+ kind: command,
1553
+ count: entry.mesh.indexed ? sm.indexCount : sm.vertexCount,
1554
+ first: entry.mesh.indexed ? sm.indexOffset : 0,
1555
+ instanceCount: draw.instanceCount,
1556
+ firstInstance: 0,
1557
+ surfaceFrameBase: draw.surfaceFrameBase,
1558
+ memberIds: draw.surfaceMemberIds ?? [],
1559
+ pipelineIdentity: getOpaqueResourceIdentity(smPipelineHandle as object),
1560
+ ...(materialPipelineEntry?.receipt === undefined
1561
+ ? {}
1562
+ : {
1563
+ receiptIdentity: materialPipelineEntry.receipt.identity,
1564
+ receiptGeneration: materialPipelineEntry.receipt.generation,
1565
+ }),
1566
+ });
1567
+ },
1445
1568
  ),
1446
1569
  );
1447
1570
  } else {
@@ -1456,7 +1579,26 @@ export function recordGeometryDraws(
1456
1579
  sm.indexCount,
1457
1580
  sm.vertexCount,
1458
1581
  sm.indexOffset,
1459
- () => c.onRenderableDraw?.(entry),
1582
+ (draw, command) => {
1583
+ c.onRenderableDraw?.(entry, smIdx);
1584
+ if (surfacePass === undefined || draw.surfaceFrameBase === undefined) return;
1585
+ c.frameState.surfaceSubmissionObservation?.record(surfacePass, {
1586
+ kind: command,
1587
+ count: entry.mesh.indexed ? sm.indexCount : sm.vertexCount,
1588
+ first: entry.mesh.indexed ? sm.indexOffset : 0,
1589
+ instanceCount: draw.instanceCount,
1590
+ firstInstance: 0,
1591
+ surfaceFrameBase: draw.surfaceFrameBase,
1592
+ memberIds: draw.surfaceMemberIds ?? [],
1593
+ pipelineIdentity: getOpaqueResourceIdentity(smPipelineHandle as object),
1594
+ ...(materialPipelineEntry?.receipt === undefined
1595
+ ? {}
1596
+ : {
1597
+ receiptIdentity: materialPipelineEntry.receipt.identity,
1598
+ receiptGeneration: materialPipelineEntry.receipt.generation,
1599
+ }),
1600
+ });
1601
+ },
1460
1602
  ),
1461
1603
  ),
1462
1604
  );
@@ -1475,7 +1617,7 @@ export function recordGeometryDraws(
1475
1617
  * @internal
1476
1618
  */
1477
1619
  function uploadInstanceRanges(
1478
- c: _InternalRenderPipelineContext,
1620
+ c: InstanceBufferContext,
1479
1621
  inst: NonNullable<RenderableSnapshot['instances']>,
1480
1622
  buffer: Buffer,
1481
1623
  ranges: readonly { readonly start: number; readonly end: number }[],
@@ -1532,7 +1674,7 @@ function uploadInstanceRanges(
1532
1674
  }
1533
1675
 
1534
1676
  export function reportInstanceResidency(
1535
- c: _InternalRenderPipelineContext,
1677
+ c: InstanceBufferContext,
1536
1678
  inst: NonNullable<RenderableSnapshot['instances']>,
1537
1679
  input: {
1538
1680
  readonly lane: 'direct-storage' | 'chunked-storage' | 'direct-uniform' | 'chunked-uniform';
@@ -1557,7 +1699,7 @@ export function reportInstanceResidency(
1557
1699
  }
1558
1700
 
1559
1701
  function reportInstanceFailure(
1560
- c: _InternalRenderPipelineContext,
1702
+ c: InstanceBufferContext,
1561
1703
  inst: NonNullable<RenderableSnapshot['instances']>,
1562
1704
  error: {
1563
1705
  readonly code: InstanceCollectionFailureCode;
@@ -1584,7 +1726,7 @@ function reportInstanceFailure(
1584
1726
  });
1585
1727
  }
1586
1728
 
1587
- function clearInstanceChunksForOwner(c: _InternalRenderPipelineContext, ownerKey: number): void {
1729
+ function clearInstanceChunksForOwner(c: InstanceBufferContext, ownerKey: number): void {
1588
1730
  const chunks = c.frameState.instanceBufferChunks;
1589
1731
  if (chunks === undefined) return;
1590
1732
  const prefix = `${ownerKey}:`;
@@ -1599,7 +1741,7 @@ function clearInstanceChunksForOwner(c: _InternalRenderPipelineContext, ownerKey
1599
1741
  }
1600
1742
 
1601
1743
  export function resolveStorageInstanceChunks(
1602
- c: _InternalRenderPipelineContext,
1744
+ c: InstanceBufferContext,
1603
1745
  entry: _InternalRenderPipelineContext['validatedOrdered'][number],
1604
1746
  inst: NonNullable<RenderableSnapshot['instances']>,
1605
1747
  cap: number,
@@ -1734,8 +1876,10 @@ export function resolveStorageInstanceChunks(
1734
1876
  activeBuffer.buffer.handle,
1735
1877
  probeBuffer,
1736
1878
  ),
1879
+ ...(probeBuffer === undefined ? {} : { probeBuffer }),
1737
1880
  probeOffset,
1738
1881
  instanceCount: count,
1882
+ firstInstanceOrdinal: start,
1739
1883
  });
1740
1884
  }
1741
1885
  if (chunks !== undefined) {
@@ -1759,8 +1903,13 @@ export function resolveStorageInstanceChunks(
1759
1903
  return draws;
1760
1904
  }
1761
1905
 
1762
- function resolveGeometryInstanceBuffer(
1763
- c: _InternalRenderPipelineContext,
1906
+ type InstanceBufferContext = Pick<
1907
+ _InternalRenderPipelineContext,
1908
+ 'runtime' | 'pipelineState' | 'frameState' | 'bindGroupCounts'
1909
+ >;
1910
+
1911
+ export function resolveGeometryInstanceBuffer(
1912
+ c: InstanceBufferContext,
1764
1913
  entry: _InternalRenderPipelineContext['validatedOrdered'][number],
1765
1914
  identityInstanceDraws: readonly GeometryInstanceDraw[],
1766
1915
  useProbeBlend: boolean,
@@ -1788,6 +1937,7 @@ function resolveGeometryInstanceBuffer(
1788
1937
  pipelineState.identityInstanceBuffer,
1789
1938
  probeBinding?.buffer,
1790
1939
  ),
1940
+ ...(probeBinding?.buffer === undefined ? {} : { probeBuffer: probeBinding.buffer }),
1791
1941
  probeOffset: probeBinding?.offset ?? -1,
1792
1942
  },
1793
1943
  ];
@@ -1918,8 +2068,10 @@ function resolveGeometryInstanceBuffer(
1918
2068
  active.buffer.handle,
1919
2069
  probeBinding?.buffer,
1920
2070
  ),
2071
+ ...(probeBinding?.buffer === undefined ? {} : { probeBuffer: probeBinding.buffer }),
1921
2072
  probeOffset: probeBinding?.offset ?? -1,
1922
2073
  instanceCount: count,
2074
+ firstInstanceOrdinal: start,
1923
2075
  });
1924
2076
  }
1925
2077
  if (chunks !== undefined) {
@@ -1988,6 +2140,7 @@ function resolveGeometryInstanceBuffer(
1988
2140
  if (!bufRes.ok) {
1989
2141
  runtime.errorRegistry.fire(bufRes.error);
1990
2142
  reportInstanceFailure(c, inst, bufRes.error, requestedBytes, cap);
2143
+ return null;
1991
2144
  } else {
1992
2145
  // feat-20260619 M4 / F12: destroy the old cached buffer
1993
2146
  // before replacing it with the new one (D-6).
@@ -2078,62 +2231,78 @@ function resolveGeometryInstanceBuffer(
2078
2231
  {
2079
2232
  instanceBuffer,
2080
2233
  instanceBindGroup: resolveGeometryInstancesBindGroup(c, instanceBuffer, probeBinding?.buffer),
2234
+ ...(probeBinding?.buffer === undefined ? {} : { probeBuffer: probeBinding.buffer }),
2081
2235
  probeOffset: probeBinding?.offset ?? -1,
2082
2236
  instanceCount,
2083
2237
  },
2084
2238
  ];
2085
2239
  }
2086
2240
 
2087
- export function resolveProbeBlendBuffer(
2241
+ function resolveSurfaceDirectInstanceDraws(
2088
2242
  c: _InternalRenderPipelineContext,
2243
+ entry: _InternalRenderPipelineContext['validatedOrdered'][number],
2244
+ drawItemIndex: number,
2245
+ draws: readonly GeometryInstanceDraw[],
2246
+ ): readonly GeometryInstanceDraw[] | null {
2247
+ const resolve = c.gpuDrivenStandardPbrFrameResources?.surfaceDirectInstances;
2248
+ if (resolve === undefined) {
2249
+ c.runtime.errorRegistry.fire(
2250
+ new RhiError({
2251
+ code: 'rhi-not-available',
2252
+ expected: 'the prepared Surface producer publishes the direct slot-3 resource closure',
2253
+ hint: 'prepare the retained Surface frame before recording direct medium draws',
2254
+ }),
2255
+ );
2256
+ return null;
2257
+ }
2258
+ const resolved: GeometryInstanceDraw[] = [];
2259
+ for (const draw of draws) {
2260
+ const direct = resolve({
2261
+ worldId: entry.source.worldId,
2262
+ entityKey: entry.source.entityKey,
2263
+ drawItemIndex,
2264
+ instanceCount: draw.instanceCount,
2265
+ firstInstanceOrdinal: draw.firstInstanceOrdinal ?? 0,
2266
+ instanceBuffer: draw.instanceBuffer,
2267
+ ...(draw.probeBuffer === undefined ? {} : { probeBuffer: draw.probeBuffer }),
2268
+ ...(draw.probeOffset < 0
2269
+ ? {}
2270
+ : {
2271
+ probeOffset: draw.probeOffset,
2272
+ }),
2273
+ });
2274
+ if (!direct.ok) {
2275
+ c.runtime.errorRegistry.fire(direct.error);
2276
+ return null;
2277
+ }
2278
+ resolved.push({
2279
+ ...draw,
2280
+ instanceBindGroup: direct.value.bindGroup,
2281
+ dynamicOffsets: direct.value.dynamicOffsets,
2282
+ surfaceFrameBase: direct.value.frameBase,
2283
+ surfaceMemberIds: direct.value.memberIds,
2284
+ });
2285
+ }
2286
+ return resolved;
2287
+ }
2288
+
2289
+ export function resolveProbeBlendBuffer(
2290
+ c: InstanceBufferContext,
2089
2291
  record: import('../scene/probe-blend-record').ProbeBlendRecord | undefined,
2090
2292
  entityKey?: number,
2091
2293
  ): { readonly buffer: Buffer; readonly offset: number } {
2092
2294
  const { runtime, frameState } = c;
2093
- const usage = runtime.device.caps.storageBuffer
2094
- ? GPU_BUFFER_USAGE_STORAGE | GPU_BUFFER_USAGE_COPY_DST
2095
- : GPU_BUFFER_USAGE_UNIFORM | GPU_BUFFER_USAGE_COPY_DST;
2096
2295
  if (record === undefined) throw new Error('probe blend record is required for probe allocation');
2097
2296
  if (entityKey === undefined) throw new Error('probe blend record requires an entity key');
2098
- const offset = probeBlendRecordOffset(record.objectKey);
2099
- const requiredCapacity = record.objectKey + 2;
2100
- let buffer = frameState.probeBlendRecordBuffer;
2101
- if (buffer === undefined || frameState.probeBlendRecordBufferCapacity < requiredCapacity) {
2102
- const created = runtime.device.createBuffer({
2103
- label: 'probe-blend-records',
2104
- size: requiredCapacity * PROBE_BLEND_RECORD_STRIDE,
2105
- usage,
2106
- mappedAtCreation: false,
2107
- });
2108
- if (!created.ok) throw created.error;
2109
- buffer = new GpuBuffer(runtime.device, created.value);
2110
- frameState.probeBlendRecordBuffer = buffer;
2111
- frameState.probeBlendRecordBufferCapacity = requiredCapacity;
2112
- // The cache is tied to the previous backing allocation. A new buffer has
2113
- // no valid record contents, so every later object must upload its full
2114
- // 160B payload even when generation/bytes match the old allocation.
2115
- frameState.probeBlendBuffers.clear();
2116
- }
2117
- const cached = frameState.probeBlendBuffers.get(entityKey);
2118
- const unchanged =
2119
- cached !== undefined &&
2120
- cached.generation === record.generation &&
2121
- cached.bytes.length === record.bytes.length &&
2122
- cached.bytes.every((value, index) => value === record.bytes[index]);
2123
- if (!unchanged) {
2124
- const uploaded = runtime.device.queue.writeBuffer(buffer.handle, offset, record.bytes);
2125
- if (!uploaded.ok) throw uploaded.error;
2126
- // Publish the generation only after the complete 160B queue write succeeds.
2127
- frameState.probeBlendBuffers.set(entityKey, {
2128
- generation: record.generation,
2129
- bytes: new Uint8Array(record.bytes),
2130
- });
2131
- }
2132
- return { buffer: buffer.handle, offset };
2297
+ const buffer = ensureProbeBlendRecordBuffer(runtime.device, frameState, [
2298
+ { cacheKey: entityKey, record },
2299
+ ]);
2300
+ if (buffer === undefined) throw new Error('probe blend record buffer allocation failed');
2301
+ return { buffer, offset: probeBlendRecordOffset(record.objectKey) };
2133
2302
  }
2134
2303
 
2135
2304
  export function resolveGeometryInstancesBindGroup(
2136
- c: _InternalRenderPipelineContext,
2305
+ c: InstanceBufferContext,
2137
2306
  instanceBuffer: Buffer,
2138
2307
  probeBuffer?: Buffer,
2139
2308
  ): BindGroup {