@forgeax/engine-render 0.1.29 → 0.1.31

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 (350) hide show
  1. package/README.md +248 -21
  2. package/dist/assembly/atmosphere-shader-prewarm.d.ts +1 -1
  3. package/dist/assembly/atmosphere-shader-prewarm.d.ts.map +1 -1
  4. package/dist/assembly/device-feature-admission.d.ts +4 -3
  5. package/dist/assembly/device-feature-admission.d.ts.map +1 -1
  6. package/dist/assembly/dynamic-geometry-host.d.ts +6 -0
  7. package/dist/assembly/dynamic-geometry-host.d.ts.map +1 -1
  8. package/dist/assembly/host-contract.d.ts +6 -0
  9. package/dist/assembly/host-contract.d.ts.map +1 -1
  10. package/dist/assembly/material/assembly.d.ts +26 -3
  11. package/dist/assembly/material/assembly.d.ts.map +1 -1
  12. package/dist/assembly/material/pipeline-helpers.d.ts +24 -0
  13. package/dist/assembly/material/pipeline-helpers.d.ts.map +1 -0
  14. package/dist/assembly/material-shader-policy.d.ts.map +1 -1
  15. package/dist/assembly/recovery/device-loss-fanout.d.ts.map +1 -1
  16. package/dist/assembly/recovery/recovery-attempt.d.ts +1 -6
  17. package/dist/assembly/recovery/recovery-attempt.d.ts.map +1 -1
  18. package/dist/assembly/recovery/renderer-recover.d.ts +1 -0
  19. package/dist/assembly/recovery/renderer-recover.d.ts.map +1 -1
  20. package/dist/assembly/renderer-facade.d.ts.map +1 -1
  21. package/dist/assembly/shader-prewarm-policy.d.ts +1 -1
  22. package/dist/assembly/shader-prewarm-policy.d.ts.map +1 -1
  23. package/dist/assembly/webgpu-ready.d.ts +1 -1
  24. package/dist/assembly/webgpu-ready.d.ts.map +1 -1
  25. package/dist/assembly/webgpu-renderer.d.ts.map +1 -1
  26. package/dist/capture/scene-projection.d.ts +41 -0
  27. package/dist/capture/scene-projection.d.ts.map +1 -0
  28. package/dist/{chunk-BQVQOQJH.mjs → chunk-7MQ3XBSP.mjs} +20 -14
  29. package/dist/chunk-7MQ3XBSP.mjs.map +1 -0
  30. package/dist/{chunk-S4DNKQYQ.mjs → chunk-C3DDSXYK.mjs} +86 -33
  31. package/dist/chunk-C3DDSXYK.mjs.map +1 -0
  32. package/dist/{chunk-BTWH7BP4.mjs → chunk-FUUO4UND.mjs} +73 -29
  33. package/dist/chunk-FUUO4UND.mjs.map +1 -0
  34. package/dist/{chunk-NRNXBLIJ.mjs → chunk-JRBDO2KB.mjs} +46 -6
  35. package/dist/chunk-JRBDO2KB.mjs.map +1 -0
  36. package/dist/{chunk-NICXSHAT.mjs → chunk-MDQJPY3T.mjs} +8 -6
  37. package/dist/chunk-MDQJPY3T.mjs.map +1 -0
  38. package/dist/{chunk-JQTSEI3Z.mjs → chunk-NO4WZCAH.mjs} +3 -3
  39. package/dist/chunk-NO4WZCAH.mjs.map +1 -0
  40. package/dist/{chunk-FUODTTIA.mjs → chunk-PSEQ6QPH.mjs} +621 -108
  41. package/dist/chunk-PSEQ6QPH.mjs.map +1 -0
  42. package/dist/{chunk-33XZFTQU.mjs → chunk-S5UE2T5P.mjs} +48 -6
  43. package/dist/chunk-S5UE2T5P.mjs.map +1 -0
  44. package/dist/components/directional-light.d.ts +2 -2
  45. package/dist/components/dynamic-resolution.d.ts +15 -0
  46. package/dist/components/dynamic-resolution.d.ts.map +1 -0
  47. package/dist/components/index.d.ts +1 -0
  48. package/dist/components/index.d.ts.map +1 -1
  49. package/dist/components/light-helpers.d.ts.map +1 -1
  50. package/dist/components/reflection-probe.d.ts +1 -0
  51. package/dist/components/reflection-probe.d.ts.map +1 -1
  52. package/dist/components/skylight.d.ts +4 -1
  53. package/dist/components/skylight.d.ts.map +1 -1
  54. package/dist/construct-renderer.mjs +2172 -796
  55. package/dist/construct-renderer.mjs.map +1 -1
  56. package/dist/device/device-scope.d.ts +2 -0
  57. package/dist/device/device-scope.d.ts.map +1 -1
  58. package/dist/device/gpu-residency.d.ts +2 -2
  59. package/dist/device/gpu-residency.d.ts.map +1 -1
  60. package/dist/dynamic-geometry.d.ts.map +1 -1
  61. package/dist/environment/background.d.ts +3 -2
  62. package/dist/environment/background.d.ts.map +1 -1
  63. package/dist/environment/ibl.d.ts +11 -0
  64. package/dist/environment/ibl.d.ts.map +1 -0
  65. package/dist/environment/storage.d.ts +14 -0
  66. package/dist/environment/storage.d.ts.map +1 -0
  67. package/dist/errors/gpu-driven.d.ts +2 -2
  68. package/dist/errors/gpu-driven.d.ts.map +1 -1
  69. package/dist/errors/render.d.ts +35 -1
  70. package/dist/errors/render.d.ts.map +1 -1
  71. package/dist/extract/camera.d.ts.map +1 -1
  72. package/dist/extract/contracts.d.ts +7 -0
  73. package/dist/extract/contracts.d.ts.map +1 -1
  74. package/dist/extract/gpu-driven.d.ts +18 -1
  75. package/dist/extract/gpu-driven.d.ts.map +1 -1
  76. package/dist/gpu-driven/batch-topology.d.ts.map +1 -1
  77. package/dist/gpu-driven/material-artifacts.d.ts +24 -0
  78. package/dist/gpu-driven/material-artifacts.d.ts.map +1 -0
  79. package/dist/gpu-driven/material-bindings.d.ts +7 -0
  80. package/dist/gpu-driven/material-bindings.d.ts.map +1 -0
  81. package/dist/gpu-driven/prepared-draw.d.ts +2 -0
  82. package/dist/gpu-driven/prepared-draw.d.ts.map +1 -1
  83. package/dist/gpu-driven/production-raster.d.ts +27 -6
  84. package/dist/gpu-driven/production-raster.d.ts.map +1 -1
  85. package/dist/gpu-resource.d.ts +5 -2
  86. package/dist/gpu-resource.d.ts.map +1 -1
  87. package/dist/gpu-scene-schema.d.ts.map +1 -1
  88. package/dist/gpu-scene.d.ts.map +1 -1
  89. package/dist/hdrp-buffers.d.ts +3 -0
  90. package/dist/hdrp-buffers.d.ts.map +1 -1
  91. package/dist/ibl/IblPipelineCache.d.ts +2 -0
  92. package/dist/ibl/IblPipelineCache.d.ts.map +1 -1
  93. package/dist/ibl/skylight-bind-group.d.ts +3 -1
  94. package/dist/ibl/skylight-bind-group.d.ts.map +1 -1
  95. package/dist/index.d.ts +83 -81
  96. package/dist/index.d.ts.map +1 -1
  97. package/dist/index.mjs +7 -5
  98. package/dist/index.mjs.map +1 -1
  99. package/dist/inspection-types.d.ts +16 -1
  100. package/dist/inspection-types.d.ts.map +1 -1
  101. package/dist/internal.mjs +6 -6
  102. package/dist/material-row.d.ts +10 -0
  103. package/dist/material-row.d.ts.map +1 -1
  104. package/dist/pbr-pipeline.d.ts +3 -1
  105. package/dist/pbr-pipeline.d.ts.map +1 -1
  106. package/dist/pipeline/render-extent.d.ts +51 -0
  107. package/dist/pipeline/render-extent.d.ts.map +1 -0
  108. package/dist/pipeline/standard-build-context.d.ts +7 -0
  109. package/dist/pipeline/standard-build-context.d.ts.map +1 -0
  110. package/dist/pipeline/standard-forward-lane.d.ts +3 -2
  111. package/dist/pipeline/standard-forward-lane.d.ts.map +1 -1
  112. package/dist/pipeline/standard-pipeline.d.ts.map +1 -1
  113. package/dist/pipeline/standard-post.d.ts +1 -1
  114. package/dist/pipeline/standard-post.d.ts.map +1 -1
  115. package/dist/pipeline/standard-profile.d.ts +2 -1
  116. package/dist/pipeline/standard-profile.d.ts.map +1 -1
  117. package/dist/pipeline-builder.d.ts +3 -1
  118. package/dist/pipeline-builder.d.ts.map +1 -1
  119. package/dist/plugin.d.ts.map +1 -1
  120. package/dist/post-process-errors.d.ts +9 -2
  121. package/dist/post-process-errors.d.ts.map +1 -1
  122. package/dist/prepare/extended-lighting/resources.d.ts +3 -3
  123. package/dist/record/frame-lighting.d.ts.map +1 -1
  124. package/dist/record/frame-snapshot.d.ts +3 -8
  125. package/dist/record/frame-snapshot.d.ts.map +1 -1
  126. package/dist/record/frame.d.ts +3 -2
  127. package/dist/record/frame.d.ts.map +1 -1
  128. package/dist/record/main-pass-geometry.d.ts +7 -2
  129. package/dist/record/main-pass-geometry.d.ts.map +1 -1
  130. package/dist/record/main-pass-material.d.ts +6 -3
  131. package/dist/record/main-pass-material.d.ts.map +1 -1
  132. package/dist/record/main-pass.d.ts +2 -0
  133. package/dist/record/main-pass.d.ts.map +1 -1
  134. package/dist/record/prepared-material-bindings.d.ts.map +1 -1
  135. package/dist/record/recovery-pipeline.d.ts +9 -1
  136. package/dist/record/recovery-pipeline.d.ts.map +1 -1
  137. package/dist/record/render-context.d.ts +34 -3
  138. package/dist/record/render-context.d.ts.map +1 -1
  139. package/dist/record/shadow-pass.d.ts +2 -2
  140. package/dist/record/shadow-pass.d.ts.map +1 -1
  141. package/dist/record/typed-frame-graph.d.ts +5 -2
  142. package/dist/record/typed-frame-graph.d.ts.map +1 -1
  143. package/dist/recovery/render-system-candidate.d.ts.map +1 -1
  144. package/dist/reflection/background.d.ts +14 -0
  145. package/dist/reflection/background.d.ts.map +1 -0
  146. package/dist/reflection/filter.d.ts.map +1 -1
  147. package/dist/reflection/projection.d.ts +1 -0
  148. package/dist/reflection/projection.d.ts.map +1 -1
  149. package/dist/reflection/record-owner.d.ts +4 -2
  150. package/dist/reflection/record-owner.d.ts.map +1 -1
  151. package/dist/render-contract.d.ts +47 -32
  152. package/dist/render-contract.d.ts.map +1 -1
  153. package/dist/render-graph-primitives.d.ts.map +1 -1
  154. package/dist/render-pipeline.d.ts +17 -1
  155. package/dist/render-pipeline.d.ts.map +1 -1
  156. package/dist/render-system-extract-tail.d.ts +9 -2
  157. package/dist/render-system-extract-tail.d.ts.map +1 -1
  158. package/dist/render-system-extract.d.ts +29 -2
  159. package/dist/render-system-extract.d.ts.map +1 -1
  160. package/dist/render-system.d.ts.map +1 -1
  161. package/dist/scene/render-scene.d.ts +2 -0
  162. package/dist/scene/render-scene.d.ts.map +1 -1
  163. package/dist/ssao-config.d.ts +8 -6
  164. package/dist/ssao-config.d.ts.map +1 -1
  165. package/dist/ssr/graph.d.ts.map +1 -1
  166. package/dist/temporal/gpu.d.ts.map +1 -1
  167. package/dist/temporal/index.mjs +5 -5
  168. package/dist/temporal/standard-scene-data.d.ts +2 -1
  169. package/dist/temporal/standard-scene-data.d.ts.map +1 -1
  170. package/dist/temporal/target-coverage-attachment.d.ts +15 -0
  171. package/dist/temporal/target-coverage-attachment.d.ts.map +1 -0
  172. package/dist/temporal/temporal-view.d.ts +6 -2
  173. package/dist/temporal/temporal-view.d.ts.map +1 -1
  174. package/dist/temporal/view.d.ts +6 -0
  175. package/dist/temporal/view.d.ts.map +1 -1
  176. package/dist/typed-render-graph-primitives.d.ts +6 -0
  177. package/dist/typed-render-graph-primitives.d.ts.map +1 -1
  178. package/dist/volume/component.d.ts +1 -0
  179. package/dist/volume/component.d.ts.map +1 -1
  180. package/package.json +21 -21
  181. package/src/__tests__/capture-scene-projection.unit.test.ts +24 -0
  182. package/src/__tests__/device-feature-admission.unit.test.ts +15 -24
  183. package/src/__tests__/device-loss-fanout.unit.test.ts +43 -0
  184. package/src/__tests__/dynamic-geometry-batch.unit.test.ts +157 -0
  185. package/src/__tests__/dynamic-geometry.unit.test.ts +36 -0
  186. package/src/__tests__/dynamic-resolution-plugin.integration.test.ts +81 -0
  187. package/src/__tests__/factory-contract.integration.test.ts +164 -1
  188. package/src/__tests__/frame-observation.contract.test.ts +21 -0
  189. package/src/__tests__/gpu-driven-baseline.characterization.test.ts +1 -1
  190. package/src/__tests__/gpu-driven-batch-topology-pbr.unit.test.ts +20 -1
  191. package/src/__tests__/gpu-driven-lod-cache.unit.test.ts +0 -3
  192. package/src/__tests__/gpu-driven-mesh-world-identity.unit.test.ts +0 -3
  193. package/src/__tests__/gpu-driven-pbr.dawn.test.ts +11 -6
  194. package/src/__tests__/gpu-driven-production.integration.test.ts +13 -25
  195. package/src/__tests__/gpu-driven-view.unit.test.ts +1 -0
  196. package/src/__tests__/gpu-pass-timing-browser-runner.ts +15 -0
  197. package/src/__tests__/gpu-pass-timing.browser.test.ts +14 -1
  198. package/src/__tests__/gpu-resource-scope.unit.test.ts +71 -0
  199. package/src/__tests__/gpu-scene.unit.test.ts +55 -1
  200. package/src/__tests__/materials-standard-contract.unit.test.ts +5 -1
  201. package/src/__tests__/mesh-submission-lifetime.unit.test.ts +8 -0
  202. package/src/__tests__/morph-neutral-admission.unit.test.ts +19 -0
  203. package/src/__tests__/physical-clearcoat.integration.test.ts +6 -1
  204. package/src/__tests__/post-process-error-policy-owner.unit.test.ts +6 -5
  205. package/src/__tests__/prepared-gpu-driven-pbr.integration.test.ts +216 -5
  206. package/src/__tests__/reflection-fallback-async-publication.unit.test.ts +68 -1
  207. package/src/__tests__/reflection-probe-authoring.unit.test.ts +12 -10
  208. package/src/__tests__/reflection-probe-box.dawn.test.ts +71 -0
  209. package/src/__tests__/reflection-probe-filter.unit.test.ts +9 -0
  210. package/src/__tests__/reflection-probe-orientation.dawn.test.ts +294 -0
  211. package/src/__tests__/reflection-probe-record-owner.characterization.unit.test.ts +5 -15
  212. package/src/__tests__/reflection-probe-updates.unit.test.ts +129 -0
  213. package/src/__tests__/render-error-code-owner.test-d.ts +3 -0
  214. package/src/__tests__/render-error-detail-ssot.test-d.ts +5 -1
  215. package/src/__tests__/render-extent.unit.test.ts +63 -0
  216. package/src/__tests__/render-scene-projection.unit.test.ts +3 -2
  217. package/src/__tests__/renderer-factory-material-contract.unit.test.ts +173 -9
  218. package/src/__tests__/shader-manifest-fixture.ts +6 -0
  219. package/src/__tests__/skinned-shadow-caster.test.ts +8 -1
  220. package/src/__tests__/specular-environment-scale.dawn.test.ts +4 -2
  221. package/src/__tests__/ssao-config.unit.test.ts +7 -0
  222. package/src/__tests__/ssao-surface.dawn.test.ts +252 -0
  223. package/src/__tests__/ssr-cube-silhouette.dawn.test.ts +270 -0
  224. package/src/__tests__/ssr-gpu-dispatch.browser.test.ts +51 -43
  225. package/src/__tests__/ssr-gpu-dispatch.dawn.test.ts +4 -0
  226. package/src/__tests__/ssr-gpu-dispatch.ts +10 -5
  227. package/src/__tests__/ssr-graph-topology.unit.test.ts +2 -2
  228. package/src/__tests__/ssr-hiz.browser.test.ts +1 -1
  229. package/src/__tests__/ssr-hiz.dawn.test.ts +1 -1
  230. package/src/__tests__/ssr-spatial.integration.test.ts +1 -1
  231. package/src/__tests__/standard-cluster-variant-resolution.unit.test.ts +40 -0
  232. package/src/__tests__/standard-pbr-artifact-assembly.unit.test.ts +238 -1
  233. package/src/__tests__/standard-profile-oracle.unit.test.ts +27 -0
  234. package/src/__tests__/taa-coverage-edge.dawn.test.ts +6 -0
  235. package/src/__tests__/taa-neighborhood-equivalence.dawn.test.ts +5 -1
  236. package/src/__tests__/taa-stability-feedback.ts +1 -0
  237. package/src/__tests__/temporal-reset-matrix.unit.test.ts +2 -2
  238. package/src/__tests__/temporal-view.unit.test.ts +17 -0
  239. package/src/__tests__/transmission-prewarm.unit.test.ts +57 -0
  240. package/src/__tests__/volumetric-fog-stage-readback.dawn.test.ts +62 -13
  241. package/src/__tests__/volumetric-fog-topology.unit.test.ts +7 -7
  242. package/src/assembly/atmosphere-shader-prewarm.ts +3 -2
  243. package/src/assembly/device-feature-admission.ts +9 -4
  244. package/src/assembly/dynamic-geometry-host.ts +236 -163
  245. package/src/assembly/host-contract.ts +9 -0
  246. package/src/assembly/material/assembly.ts +350 -6
  247. package/src/assembly/material/pipeline-helpers.ts +100 -0
  248. package/src/assembly/material-shader-policy.ts +39 -18
  249. package/src/assembly/recovery/device-loss-fanout.ts +5 -0
  250. package/src/assembly/recovery/recovery-attempt.ts +2 -29
  251. package/src/assembly/recovery/renderer-recover.ts +6 -9
  252. package/src/assembly/renderer-facade.ts +22 -1
  253. package/src/assembly/shader-prewarm-policy.ts +14 -1
  254. package/src/assembly/webgpu-ready.ts +28 -19
  255. package/src/assembly/webgpu-renderer.ts +95 -95
  256. package/src/capture/scene-projection.ts +37 -0
  257. package/src/components/__tests__/dynamic-resolution-schema.unit.test.ts +65 -0
  258. package/src/components/__tests__/light-radius.integration.test.ts +59 -0
  259. package/src/components/directional-light.ts +3 -3
  260. package/src/components/dynamic-resolution.ts +67 -0
  261. package/src/components/index.ts +1 -0
  262. package/src/components/light-helpers.ts +6 -1
  263. package/src/components/reflection-probe.ts +1 -0
  264. package/src/components/skylight.ts +4 -1
  265. package/src/device/device-scope.ts +13 -7
  266. package/src/device/gpu-residency.ts +11 -11
  267. package/src/dynamic-geometry.ts +13 -8
  268. package/src/environment/background.ts +30 -12
  269. package/src/environment/ibl.ts +211 -0
  270. package/src/environment/storage.ts +63 -0
  271. package/src/errors/gpu-driven.ts +10 -3
  272. package/src/errors/render.ts +64 -0
  273. package/src/extract/camera.ts +12 -1
  274. package/src/extract/contracts.ts +10 -0
  275. package/src/extract/gpu-driven.ts +72 -17
  276. package/src/gpu-driven/batch-topology.ts +33 -11
  277. package/src/gpu-driven/material-artifacts.ts +179 -0
  278. package/src/gpu-driven/material-bindings.ts +41 -0
  279. package/src/gpu-driven/prepared-draw.ts +13 -2
  280. package/src/gpu-driven/production-raster.ts +681 -164
  281. package/src/gpu-resource.ts +21 -2
  282. package/src/gpu-scene-schema.ts +11 -2
  283. package/src/gpu-scene.ts +14 -3
  284. package/src/hdrp-buffers.ts +69 -0
  285. package/src/ibl/IblPipelineCache.ts +5 -0
  286. package/src/ibl/skylight-bind-group.ts +27 -17
  287. package/src/index.ts +92 -81
  288. package/src/inspection-types.ts +16 -1
  289. package/src/material-row.ts +60 -11
  290. package/src/pbr-pipeline.ts +13 -2
  291. package/src/pipeline/render-extent.ts +111 -0
  292. package/src/pipeline/standard-build-context.ts +7 -0
  293. package/src/pipeline/standard-forward-lane.ts +41 -24
  294. package/src/pipeline/standard-pipeline.ts +47 -18
  295. package/src/pipeline/standard-post.ts +4 -0
  296. package/src/pipeline/standard-profile.ts +2 -1
  297. package/src/pipeline-builder.ts +12 -3
  298. package/src/plugin.ts +4 -0
  299. package/src/post-process-errors.ts +26 -18
  300. package/src/prepare/__tests__/extended-lighting-capability.unit.test.ts +2 -2
  301. package/src/prepare/extended-lighting/resources.ts +3 -3
  302. package/src/record/__tests__/main-pass-geometry.unit.test.ts +68 -0
  303. package/src/record/__tests__/material-bg-cache.unit.test.ts +45 -0
  304. package/src/record/__tests__/material-slot-plan.unit.test.ts +9 -0
  305. package/src/record/__tests__/recovery-pipeline.unit.test.ts +47 -1
  306. package/src/record/__tests__/sprite-material-abi.unit.test.ts +7 -3
  307. package/src/record/__tests__/temporal-payload.unit.test.ts +2 -0
  308. package/src/record/frame-lighting.ts +3 -1
  309. package/src/record/frame-snapshot.ts +13 -11
  310. package/src/record/frame.ts +150 -74
  311. package/src/record/main-pass-geometry.ts +60 -9
  312. package/src/record/main-pass-material.ts +47 -19
  313. package/src/record/main-pass.ts +63 -4
  314. package/src/record/prepared-material-bindings.ts +4 -0
  315. package/src/record/recovery-pipeline.ts +56 -0
  316. package/src/record/render-context.ts +34 -3
  317. package/src/record/shadow-pass.ts +187 -50
  318. package/src/record/typed-frame-graph.ts +60 -3
  319. package/src/record/view-ubo.ts +1 -1
  320. package/src/recovery/render-system-candidate.ts +54 -11
  321. package/src/reflection/background.ts +151 -0
  322. package/src/reflection/filter.ts +3 -0
  323. package/src/reflection/projection.ts +16 -6
  324. package/src/reflection/record-owner.ts +282 -86
  325. package/src/render-contract.ts +50 -32
  326. package/src/render-graph-primitives.ts +28 -3
  327. package/src/render-pipeline.ts +20 -1
  328. package/src/render-system-extract-tail.ts +23 -3
  329. package/src/render-system-extract.ts +127 -42
  330. package/src/render-system.ts +35 -7
  331. package/src/scene/render-scene.ts +8 -0
  332. package/src/ssao-config.ts +25 -8
  333. package/src/ssr/graph.ts +78 -58
  334. package/src/temporal/gpu.ts +5 -0
  335. package/src/temporal/standard-scene-data.ts +7 -1
  336. package/src/temporal/target-coverage-attachment.ts +72 -0
  337. package/src/temporal/temporal-view.ts +10 -4
  338. package/src/temporal/view.ts +12 -2
  339. package/src/transmission/__tests__/standard-transmission.dawn.test.ts +24 -9
  340. package/src/typed-render-graph-primitives.ts +38 -0
  341. package/src/volume/component.ts +1 -0
  342. package/src/volume/passes.ts +3 -3
  343. package/dist/chunk-33XZFTQU.mjs.map +0 -1
  344. package/dist/chunk-BQVQOQJH.mjs.map +0 -1
  345. package/dist/chunk-BTWH7BP4.mjs.map +0 -1
  346. package/dist/chunk-FUODTTIA.mjs.map +0 -1
  347. package/dist/chunk-JQTSEI3Z.mjs.map +0 -1
  348. package/dist/chunk-NICXSHAT.mjs.map +0 -1
  349. package/dist/chunk-NRNXBLIJ.mjs.map +0 -1
  350. package/dist/chunk-S4DNKQYQ.mjs.map +0 -1
@@ -1,3 +1,4 @@
1
+ import { createMeshBuilder } from '@forgeax/engine-geometry';
1
2
  import type { MeshAsset } from '@forgeax/engine-types';
2
3
  import { describe, expect, it } from 'vitest';
3
4
  import { createDynamicGeometryLifecycle } from '../dynamic-geometry';
@@ -15,6 +16,41 @@ const mesh = (): MeshAsset => ({
15
16
  });
16
17
 
17
18
  describe('standard dynamic geometry lifecycle', () => {
19
+ it('accepts a MeshBuilder interleaved color buffer with four vertices', () => {
20
+ const source = createMeshBuilder({
21
+ attributes: {
22
+ position: new Float32Array([0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0]),
23
+ color: new Float32Array(16).fill(1),
24
+ },
25
+ indices: new Uint16Array([0, 1, 2, 0, 2, 3]),
26
+ })
27
+ .build()
28
+ .unwrap();
29
+ expect(source.vertices.length % 3).not.toBe(0);
30
+ const lifecycle = createDynamicGeometryLifecycle();
31
+ expect(lifecycle.prepare({ world: {}, mesh: source, revision: 1 }, 1).ok).toBe(true);
32
+ });
33
+
34
+ it('validates referenced material slots rather than requiring one slot per submesh', () => {
35
+ const source = mesh();
36
+ const shared = { ...source, submeshes: [...source.submeshes, ...source.submeshes] };
37
+ const lifecycle = createDynamicGeometryLifecycle();
38
+ expect(lifecycle.prepare({ world: {}, mesh: shared, revision: 1 }, 1).ok).toBe(true);
39
+ expect(
40
+ lifecycle.prepare(
41
+ {
42
+ world: {},
43
+ mesh: {
44
+ ...source,
45
+ submeshes: source.submeshes.map((submesh) => ({ ...submesh, materialSlot: 2 })),
46
+ },
47
+ revision: 1,
48
+ },
49
+ 1,
50
+ ).ok,
51
+ ).toBe(false);
52
+ });
53
+
18
54
  it('copies a MeshAsset and publishes only after a matching frame generation', () => {
19
55
  const lifecycle = createDynamicGeometryLifecycle();
20
56
  const world = {};
@@ -0,0 +1,81 @@
1
+ import { createWorldContext, World } from '@forgeax/engine-ecs';
2
+ import { scenePlugin, Transform } from '@forgeax/engine-scene';
3
+ import { describe, expect, it } from 'vitest';
4
+ import { extractCameraSnapshots } from '../extract/camera';
5
+ import { ANTIALIAS_NONE, ANTIALIAS_TAA, Camera, DynamicResolution, MotionBlur } from '../index';
6
+ import { renderComponentsPlugin } from '../plugin';
7
+ import { extractFrames } from '../render-system-extract';
8
+
9
+ describe('DynamicResolution render component registration', () => {
10
+ it('uses the existing render plugin for add, remove, and extraction retries', async () => {
11
+ const world = new World();
12
+ const context = await createWorldContext(world, [renderComponentsPlugin(), scenePlugin()]);
13
+ const entries = [...world.components.entries()].map(([name]) => name);
14
+ expect(entries).toContain('DynamicResolution');
15
+
16
+ const entity = world
17
+ .spawn(
18
+ { component: Transform, data: {} },
19
+ { component: Camera, data: { antialias: ANTIALIAS_TAA } },
20
+ { component: DynamicResolution, data: { minScale: 0.5, maxScale: 0.5 } },
21
+ )
22
+ .unwrap();
23
+ world.update(1 / 60).unwrap();
24
+ expect(extractCameraSnapshots(world)[0]?.dynamicResolution).toMatchObject({
25
+ minScale: 0.5,
26
+ maxScale: 0.5,
27
+ });
28
+ expect(extractCameraSnapshots(world)[0]?.dynamicResolution?.targetGpuMs).toBeCloseTo(16.67);
29
+
30
+ world.removeComponent(entity, DynamicResolution).unwrap();
31
+ expect(extractCameraSnapshots(world)[0]?.dynamicResolution).toBeUndefined();
32
+ expect(extractFrames([world], 0).cameras[0]?.dynamicResolution).toBeUndefined();
33
+ world
34
+ .addComponent(entity, {
35
+ component: DynamicResolution,
36
+ data: { minScale: 0.75, maxScale: 0.75 },
37
+ })
38
+ .unwrap();
39
+ expect(extractCameraSnapshots(world)[0]?.dynamicResolution).toMatchObject({
40
+ minScale: 0.75,
41
+ maxScale: 0.75,
42
+ });
43
+ expect(extractCameraSnapshots(world)[0]?.dynamicResolution?.targetGpuMs).toBeCloseTo(16.67);
44
+
45
+ const nonTaa = world.set(entity, Camera, { antialias: ANTIALIAS_NONE });
46
+ expect(nonTaa.ok).toBe(true);
47
+ expect(() => extractCameraSnapshots(world)).toThrowError(
48
+ expect.objectContaining({ code: 'dynamic-resolution-requires-taa' }),
49
+ );
50
+
51
+ await context.fiber.dispose();
52
+ });
53
+
54
+ it('registers MotionBlur for the shared camera extraction query', async () => {
55
+ const world = new World();
56
+ const context = await createWorldContext(world, [renderComponentsPlugin(), scenePlugin()]);
57
+ expect([...world.components.entries()].map(([name]) => name)).toContain('MotionBlur');
58
+
59
+ world
60
+ .spawn(
61
+ { component: Transform, data: {} },
62
+ { component: Camera, data: { antialias: ANTIALIAS_TAA } },
63
+ { component: MotionBlur, data: { shutterAngle: 120, maxRadiusPixels: 12, sampleCount: 6 } },
64
+ )
65
+ .unwrap();
66
+ world.update(1 / 60).unwrap();
67
+
68
+ expect(extractCameraSnapshots(world)[0]?.motionBlur).toEqual({
69
+ shutterAngle: 120,
70
+ maxRadiusPixels: 12,
71
+ sampleCount: 6,
72
+ });
73
+ expect(extractFrames([world], 0).cameras[0]?.motionBlur).toEqual({
74
+ shutterAngle: 120,
75
+ maxRadiusPixels: 12,
76
+ sampleCount: 6,
77
+ });
78
+
79
+ await context.fiber.dispose();
80
+ });
81
+ });
@@ -18,7 +18,15 @@ import { err, ok } from '@forgeax/engine-types';
18
18
  import { describe, expect, it, vi } from 'vitest';
19
19
  import type { RhiBackendPack } from '../assembly/backend-contract';
20
20
  import { createRenderer as constructRenderer } from '../assembly/factory';
21
- import { DirectionalLight, MeshFilter, MeshRenderer, PointLight, SpotLight } from '../components';
21
+ import {
22
+ DirectionalLight,
23
+ DynamicResolution,
24
+ MeshFilter,
25
+ MeshRenderer,
26
+ MotionBlur,
27
+ PointLight,
28
+ SpotLight,
29
+ } from '../components';
22
30
  import {
23
31
  ANTIALIAS_NONE,
24
32
  ANTIALIAS_TAA,
@@ -931,6 +939,161 @@ describe('factory contract', () => {
931
939
  expect((await renderer.dispose()).ok).toBe(true);
932
940
  });
933
941
 
942
+ it('rebuilds the TAA graph when DynamicResolution is removed', async () => {
943
+ const renderer = await constructRenderer(
944
+ { width: 64, height: 64, getContext: () => null },
945
+ { rhi },
946
+ { shaderManifestUrl: renderLifecycleManifestUrl() },
947
+ );
948
+ expect((await renderer.initialization).ok).toBe(true);
949
+ const world = new World();
950
+ const attached = renderer.attach(world);
951
+ expect(attached.ok).toBe(true);
952
+ if (!attached.ok) return;
953
+ registerPropagateTransforms(world);
954
+ const camera = world
955
+ .spawn(
956
+ { component: Transform, data: { pos: [0, 0, 4] } },
957
+ {
958
+ component: LocalCamera,
959
+ data: { fov: 1, aspect: 1, near: 0.1, far: 100, antialias: ANTIALIAS_TAA },
960
+ },
961
+ {
962
+ component: DynamicResolution,
963
+ data: { targetGpuMs: 16.67, minScale: 0.5, maxScale: 0.5 },
964
+ },
965
+ )
966
+ .unwrap();
967
+ const frameInput = () => ({
968
+ leases: [attached.value],
969
+ camera: { lease: attached.value },
970
+ environment: { lease: attached.value },
971
+ });
972
+ expect(world.update().ok).toBe(true);
973
+ expect(renderer.draw(frameInput()).ok).toBe(true);
974
+ const dynamicInspection = renderer.inspect();
975
+ expect(dynamicInspection.perFramePassNames).toContain('standard-scene-coverage');
976
+ expect(dynamicInspection.temporalTarget).toMatchObject({
977
+ descriptor: { width: 32, height: 32 },
978
+ });
979
+ const dynamicGeneration = dynamicInspection.recoveryEvidence.graph.generation;
980
+
981
+ expect(world.removeComponent(camera, DynamicResolution).ok).toBe(true);
982
+ expect(world.update().ok).toBe(true);
983
+ expect(renderer.draw(frameInput()).ok).toBe(true);
984
+ const surfaceInspection = renderer.inspect();
985
+ expect(surfaceInspection.perFramePassNames).not.toContain('standard-scene-coverage');
986
+ expect(surfaceInspection.temporalTarget).toMatchObject({
987
+ descriptor: { width: 64, height: 64 },
988
+ });
989
+ expect(surfaceInspection.recoveryEvidence.graph.generation).toBeGreaterThan(dynamicGeneration);
990
+ await renderer.dispose();
991
+ });
992
+
993
+ it('restores the surface graph after toggling DynamicResolution on and off', async () => {
994
+ const renderer = await constructRenderer(
995
+ { width: 64, height: 64, getContext: () => null },
996
+ { rhi },
997
+ { shaderManifestUrl: renderLifecycleManifestUrl() },
998
+ );
999
+ expect((await renderer.initialization).ok).toBe(true);
1000
+ const world = new World();
1001
+ const attached = renderer.attach(world);
1002
+ expect(attached.ok).toBe(true);
1003
+ if (!attached.ok) return;
1004
+ registerPropagateTransforms(world);
1005
+ const camera = world
1006
+ .spawn(
1007
+ { component: Transform, data: { pos: [0, 0, 4] } },
1008
+ {
1009
+ component: LocalCamera,
1010
+ data: { fov: 1, aspect: 1, near: 0.1, far: 100, antialias: ANTIALIAS_TAA },
1011
+ },
1012
+ )
1013
+ .unwrap();
1014
+ const frameInput = () => ({
1015
+ leases: [attached.value],
1016
+ camera: { lease: attached.value },
1017
+ environment: { lease: attached.value },
1018
+ });
1019
+ expect(world.update().ok).toBe(true);
1020
+ expect(renderer.draw(frameInput()).ok).toBe(true);
1021
+ expect(renderer.inspect().perFramePassNames).not.toContain('standard-scene-coverage');
1022
+
1023
+ expect(
1024
+ world.addComponent(camera, {
1025
+ component: DynamicResolution,
1026
+ data: { targetGpuMs: 16.67, minScale: 0.5, maxScale: 0.5 },
1027
+ }).ok,
1028
+ ).toBe(true);
1029
+ expect(world.update().ok).toBe(true);
1030
+ expect(renderer.draw(frameInput()).ok).toBe(true);
1031
+ const dynamic = renderer.inspect();
1032
+ expect(dynamic.perFramePassNames).toContain('standard-scene-coverage');
1033
+ expect(dynamic.temporalTarget).toMatchObject({ descriptor: { width: 32, height: 32 } });
1034
+
1035
+ expect(world.removeComponent(camera, DynamicResolution).ok).toBe(true);
1036
+ expect(world.update().ok).toBe(true);
1037
+ expect(renderer.draw(frameInput()).ok).toBe(true);
1038
+ const surface = renderer.inspect();
1039
+ expect(surface.perFramePassNames).not.toContain('standard-scene-coverage');
1040
+ expect(surface.temporalTarget).toMatchObject({ descriptor: { width: 64, height: 64 } });
1041
+ await renderer.dispose();
1042
+ });
1043
+
1044
+ it('rebuilds the TAA graph when MotionBlur is added', async () => {
1045
+ const renderer = await constructRenderer(
1046
+ { width: 64, height: 64, getContext: () => null },
1047
+ { rhi },
1048
+ { shaderManifestUrl: renderLifecycleManifestUrl() },
1049
+ );
1050
+ expect((await renderer.initialization).ok).toBe(true);
1051
+ const errors: unknown[] = [];
1052
+ renderer.onError((error) => errors.push(error));
1053
+ const world = new World();
1054
+ const attached = renderer.attach(world);
1055
+ expect(attached.ok).toBe(true);
1056
+ if (!attached.ok) return;
1057
+ registerPropagateTransforms(world);
1058
+ const camera = world
1059
+ .spawn(
1060
+ { component: Transform, data: { pos: [0, 0, 4] } },
1061
+ {
1062
+ component: LocalCamera,
1063
+ data: { fov: 1, aspect: 1, near: 0.1, far: 100, antialias: ANTIALIAS_TAA },
1064
+ },
1065
+ )
1066
+ .unwrap();
1067
+ const frameInput = () => ({
1068
+ leases: [attached.value],
1069
+ camera: { lease: attached.value },
1070
+ environment: { lease: attached.value },
1071
+ });
1072
+ expect(world.update().ok).toBe(true);
1073
+ expect(renderer.draw(frameInput()).ok).toBe(true);
1074
+ expect(renderer.inspect().perFramePassNames).not.toContain('motion-blur');
1075
+
1076
+ expect(
1077
+ world.addComponent(camera, {
1078
+ component: MotionBlur,
1079
+ data: { shutterAngle: 180, maxRadiusPixels: 8, sampleCount: 4 },
1080
+ }).ok,
1081
+ ).toBe(true);
1082
+ expect(world.update().ok).toBe(true);
1083
+ const motionDraw = renderer.draw(frameInput());
1084
+ if (!motionDraw.ok) {
1085
+ throw new Error(JSON.stringify({ error: motionDraw.error, events: errors }));
1086
+ }
1087
+ const inspection = renderer.inspect();
1088
+ expect(inspection.perFramePassNames).toContain('motion-blur');
1089
+ expect(inspection.motionBlur).toMatchObject({
1090
+ enabled: true,
1091
+ status: 'active',
1092
+ temporalDemand: 'scene-data-temporal-v1',
1093
+ });
1094
+ await renderer.dispose();
1095
+ });
1096
+
934
1097
  it('retires factory-owned TAA textures and params on an off submit', async () => {
935
1098
  const created = new Map<object, string>();
936
1099
  const destroyed = new Set<object>();
@@ -124,4 +124,25 @@ describe('render current-frame observation producer contract', () => {
124
124
  }),
125
125
  ).toEqual({ ok: true });
126
126
  });
127
+ it('validates every half-float encoding in both word lanes and an unaligned tail', () => {
128
+ const storage = new Uint8Array(8);
129
+ const bytes = storage.subarray(1, 7);
130
+ const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
131
+ for (let bits = 0; bits <= 0xffff; bits += 1) {
132
+ for (const offset of [0, 2, 4]) {
133
+ bytes.fill(0);
134
+ view.setUint16(offset, bits, true);
135
+ const result = validateGraphTargetCaptureReadback({
136
+ bytes,
137
+ expectedByteLength: bytes.byteLength,
138
+ allowZero: true,
139
+ });
140
+ const finite = (bits & 0x7c00) !== 0x7c00;
141
+ if (result.ok !== finite)
142
+ throw new Error(`half ${bits.toString(16)} at byte ${offset} misclassified`);
143
+ if (!result.ok && result.code !== 'capture-readback-non-finite')
144
+ throw new Error(`half ${bits.toString(16)} returned ${result.code}`);
145
+ }
146
+ }
147
+ });
127
148
  });
@@ -40,7 +40,7 @@ describe('GPU-driven baseline characterization', () => {
40
40
  it('requires the prepared Standard PBR production owner', () => {
41
41
  expect(productionRaster).not.toContain('GPU_DRIVEN_STANDARD_PBR_WGSL');
42
42
  expect(productionRaster).not.toContain('class GpuDrivenPbrRaster');
43
- expect(productionRaster).toContain('StandardPbrRasterAdapter');
43
+ expect(productionRaster).toContain('MaterialAbiRasterAdapter');
44
44
  expect(productionRaster).toContain('preparedPbrCandidateEligible');
45
45
  expect(productionRaster).toContain('deriveVertexBufferLayoutFromProjection');
46
46
  expect(productionRaster).toContain('vertexLayout.arrayStride');
@@ -64,6 +64,7 @@ function prepared(overrides: Partial<PreparedGpuDrivenDraw> = {}): PreparedGpuDr
64
64
  return {
65
65
  identity: { material: 'forgeax::default-standard-pbr', geometry: 'cube', deformation: 'rigid' },
66
66
  receiptGeneration: receipt.generation,
67
+ receiptIdentity: receipt.receiptIdentity,
67
68
  directEntry: receipt.directEntry,
68
69
  sceneIndexEntry: receipt.sceneIndexEntry,
69
70
  materialRow: receipt.materialRow,
@@ -218,11 +219,29 @@ describe('PBR prepared GPU-driven batch topology', () => {
218
219
  expect(plan.candidateCount).toBe(2);
219
220
  expect(plan.batches).toHaveLength(2);
220
221
  expect(plan.batches[0]?.key).toMatchObject({
221
- preparedIdentity: 'forgeax::default-standard-pbr|cube|rigid',
222
+ preparedIdentity: 'forgeax::default-standard-pbr|cube|rigid|standard-pbr/material-row-v3',
222
223
  resourceIdentity: resourceClass,
223
224
  });
224
225
  });
225
226
 
227
+ it('keeps colored and uncolored ABI variants in separate prepared batches', () => {
228
+ const coloredReceipt = createStandardPbrArtifactReceipt(false, true);
229
+ const colored = prepared({
230
+ receiptIdentity: coloredReceipt.receiptIdentity,
231
+ vertexInputs: coloredReceipt.vertexInputs,
232
+ });
233
+ const topology = topologyFor(snapshot(1, prepared()), snapshot(2, colored));
234
+
235
+ expect(topology.plan().candidateCount).toBe(2);
236
+ expect(topology.plan().batches).toHaveLength(2);
237
+ expect(new Set(topology.plan().batches.map((batch) => batch.key.preparedIdentity))).toEqual(
238
+ new Set([
239
+ 'forgeax::default-standard-pbr|cube|rigid|standard-pbr/material-row-v3',
240
+ 'forgeax::default-standard-pbr|cube|rigid|standard-pbr/material-row-v3/vertex-color',
241
+ ]),
242
+ );
243
+ });
244
+
226
245
  it('keeps numeric edits in place and patches only resource identity changes', () => {
227
246
  const projection = new RenderScene();
228
247
  projection.apply([updateSnapshot(snapshot(1, prepared()))]);
@@ -187,7 +187,6 @@ describe('GPU-driven filtered-plan cache', () => {
187
187
  meshBySlot: meshes,
188
188
  viewBindGroupLayout: viewLayout,
189
189
  meshResidencyEpoch: 1,
190
- hdrp: false,
191
190
  })
192
191
  .unwrap();
193
192
  expect(first).toBeDefined();
@@ -212,7 +211,6 @@ describe('GPU-driven filtered-plan cache', () => {
212
211
  meshBySlot: meshes,
213
212
  viewBindGroupLayout: viewLayout,
214
213
  meshResidencyEpoch: 1,
215
- hdrp: false,
216
214
  })
217
215
  .unwrap();
218
216
  expect(moved).toBeDefined();
@@ -243,7 +241,6 @@ describe('GPU-driven filtered-plan cache', () => {
243
241
  meshBySlot: meshes,
244
242
  viewBindGroupLayout: viewLayout,
245
243
  meshResidencyEpoch: 1,
246
- hdrp: false,
247
244
  })
248
245
  .unwrap();
249
246
 
@@ -267,7 +267,6 @@ describe('GPU-driven mesh world identity', () => {
267
267
  meshBySlot: meshes,
268
268
  viewBindGroupLayout: fixture.viewLayout,
269
269
  meshResidencyEpoch: 1,
270
- hdrp: false,
271
270
  })
272
271
  .unwrap();
273
272
  expect(prepared).toBeDefined();
@@ -310,7 +309,6 @@ describe('GPU-driven mesh world identity', () => {
310
309
  ]),
311
310
  viewBindGroupLayout: fixture.viewLayout,
312
311
  meshResidencyEpoch: 1,
313
- hdrp: false,
314
312
  })
315
313
  .unwrap();
316
314
  expect(firstPrepared).toBeDefined();
@@ -337,7 +335,6 @@ describe('GPU-driven mesh world identity', () => {
337
335
  ]),
338
336
  viewBindGroupLayout: fixture.viewLayout,
339
337
  meshResidencyEpoch: 1,
340
- hdrp: false,
341
338
  })
342
339
  .unwrap();
343
340
  expect(secondPrepared).toBeDefined();
@@ -33,6 +33,7 @@ import {
33
33
  buildPbrPipelineLayouts,
34
34
  } from '../pbr-pipeline';
35
35
  import { makeZeroCameraFallbackSnapshot, worldEntityKey } from '../record/frame-snapshot';
36
+ import { MATERIAL_PER_ENTITY_STRIDE } from '../record/render-context';
36
37
  import {
37
38
  type GpuDrivenShadowBatch,
38
39
  type GpuDrivenShadowSubmission,
@@ -86,7 +87,8 @@ const SHADOW_CASTER_GPU_ALPHA_VARIANT = SHADOW_CASTER_PRODUCER?.variants.find(
86
87
  defines.SKINNING_DISABLED === true &&
87
88
  defines.GPU_DRIVEN_SCENE_INDEX_AVAILABLE === true &&
88
89
  defines.GPU_DRIVEN_SCENE_INDEX_EXPLICIT === false &&
89
- defines.ALPHA_MASK === true,
90
+ defines.ALPHA_MASK === true &&
91
+ defines.VERTEX_COLOR_AVAILABLE === false,
90
92
  );
91
93
 
92
94
  // The local/native evidence window remains 300 frames. CI already sets the
@@ -490,13 +492,13 @@ describe('GPU-driven production PBR Dawn regression', () => {
490
492
  device.queue.writeBuffer(spotCascadeUniform, 16, shadowLightMatrix).unwrap();
491
493
  const opaqueMaterialBuffer = device
492
494
  .createBuffer({
493
- size: 512,
495
+ size: MATERIAL_PER_ENTITY_STRIDE,
494
496
  usage: GPU_BUFFER_USAGE_UNIFORM | GPU_BUFFER_USAGE_COPY_DST,
495
497
  })
496
498
  .unwrap();
497
499
  const discardedMaterialBuffer = device
498
500
  .createBuffer({
499
- size: 512,
501
+ size: MATERIAL_PER_ENTITY_STRIDE,
500
502
  usage: GPU_BUFFER_USAGE_UNIFORM | GPU_BUFFER_USAGE_COPY_DST,
501
503
  })
502
504
  .unwrap();
@@ -636,6 +638,7 @@ describe('GPU-driven production PBR Dawn regression', () => {
636
638
  { binding: 15, resource: { kind: 'textureView' as const, value: materialCubeView } },
637
639
  { binding: 16, resource: { kind: 'sampler' as const, value: baseColorSampler } },
638
640
  { binding: 17, resource: { kind: 'textureView' as const, value: materialCubeView } },
641
+ { binding: 47, resource: { kind: 'textureView' as const, value: materialCubeView } },
639
642
  { binding: 18, resource: { kind: 'sampler' as const, value: baseColorSampler } },
640
643
  { binding: 19, resource: { kind: 'textureView' as const, value: baseColorView } },
641
644
  { binding: 20, resource: { kind: 'sampler' as const, value: baseColorSampler } },
@@ -729,7 +732,7 @@ describe('GPU-driven production PBR Dawn regression', () => {
729
732
  meshBySlot: new Map(projection.map((slot) => [slot.slot, gpuMesh])),
730
733
  viewBindGroupLayout: viewLayout,
731
734
  meshResidencyEpoch: 1,
732
- hdrp: false,
735
+
733
736
  standardPbrArtifact: artifact,
734
737
  standardPbrPipelineState: {
735
738
  pbrPipelineLayout: pipelineLayout,
@@ -756,7 +759,9 @@ describe('GPU-driven production PBR Dawn regression', () => {
756
759
  expect(prepared.value.shadowDrawKeys).toEqual(new Set([shadowKey]));
757
760
  expect(prepared.value.standardPbrFrameResources.instancesBindGroup).toBeDefined();
758
761
  expect(prepared.value.standardPbrFrameResources.sceneMaterialBuffer).toBe(scene.materialBuffer);
759
- expect(prepared.value.standardPbrFrameResources.materialStride).toBe(512);
762
+ expect(prepared.value.standardPbrFrameResources.materialStride).toBe(
763
+ MATERIAL_PER_ENTITY_STRIDE,
764
+ );
760
765
  expect(artifact.receipt.alphaMask).toEqual({ cutoff: 'alphaCutoff', source: 'baseColor.a' });
761
766
 
762
767
  const shadowVertexLayout = deriveVertexBufferLayoutFromProjection(gpuMesh.layoutProjection, {
@@ -885,7 +890,7 @@ describe('GPU-driven production PBR Dawn regression', () => {
885
890
  meshBindGroup: projection.meshBindGroup,
886
891
  visibleBindGroup: projection.visibleBindGroup,
887
892
  deformation: projection.deformation,
888
- alphaMaskMaterialGroup: opaqueMaterialBindGroup,
893
+ materialGroup: opaqueMaterialBindGroup,
889
894
  vertexBuffer: projection.mesh.vertexBuffer.handle,
890
895
  ...(indexBuffer === null
891
896
  ? {}
@@ -281,7 +281,7 @@ describe('GPU-driven production projection', () => {
281
281
  ]),
282
282
  viewBindGroupLayout: viewLayout,
283
283
  meshResidencyEpoch: 1,
284
- hdrp: false,
284
+
285
285
  activeEntityKeys: new Set([worldEntityKey(0, 1)]),
286
286
  activeEntityRevision: 1,
287
287
  })
@@ -327,7 +327,7 @@ describe('GPU-driven production projection', () => {
327
327
  ]),
328
328
  viewBindGroupLayout: viewLayout,
329
329
  meshResidencyEpoch: 1,
330
- hdrp: false,
330
+
331
331
  activeEntityKeys: new Set([worldEntityKey(0, 1)]),
332
332
  activeEntityRevision: 1,
333
333
  })
@@ -351,7 +351,7 @@ describe('GPU-driven production projection', () => {
351
351
  ]),
352
352
  viewBindGroupLayout: viewLayout,
353
353
  meshResidencyEpoch: 1,
354
- hdrp: false,
354
+
355
355
  activeEntityKeys: new Set(),
356
356
  activeEntityRevision: 2,
357
357
  })
@@ -377,7 +377,7 @@ describe('GPU-driven production projection', () => {
377
377
  ]),
378
378
  viewBindGroupLayout: viewLayout,
379
379
  meshResidencyEpoch: 1,
380
- hdrp: false,
380
+
381
381
  activeEntityKeys: new Set([worldEntityKey(0, 1)]),
382
382
  activeEntityRevision: 3,
383
383
  })
@@ -433,7 +433,7 @@ describe('GPU-driven production projection', () => {
433
433
  meshBySlot: new Map([[0, mesh(device)]]),
434
434
  viewBindGroupLayout: viewLayout,
435
435
  meshResidencyEpoch: 1,
436
- hdrp: false,
436
+
437
437
  activeEntityKeys: new Set(),
438
438
  activeEntityRevision: 1,
439
439
  })
@@ -491,7 +491,6 @@ describe('GPU-driven production projection', () => {
491
491
  ]),
492
492
  viewBindGroupLayout: viewLayout,
493
493
  meshResidencyEpoch: 1,
494
- hdrp: false,
495
494
  })
496
495
  .unwrap();
497
496
  expect(prepared).toBeDefined();
@@ -586,7 +585,6 @@ describe('GPU-driven production projection', () => {
586
585
  ]),
587
586
  viewBindGroupLayout: viewLayout,
588
587
  meshResidencyEpoch: 1,
589
- hdrp: false,
590
588
  })
591
589
  .unwrap();
592
590
  expect(prepared).toBeDefined();
@@ -744,7 +742,6 @@ describe('GPU-driven production projection', () => {
744
742
  meshBySlot: meshes,
745
743
  viewBindGroupLayout: viewLayout,
746
744
  meshResidencyEpoch: 1,
747
- hdrp: false,
748
745
  })
749
746
  .unwrap();
750
747
  expect(prepared).toBeDefined();
@@ -776,7 +773,6 @@ describe('GPU-driven production projection', () => {
776
773
  meshBySlot: meshes,
777
774
  viewBindGroupLayout: viewLayout,
778
775
  meshResidencyEpoch: 1,
779
- hdrp: false,
780
776
  })
781
777
  .unwrap();
782
778
  expect(stable?.topologySignature).toBe(prepared.topologySignature);
@@ -809,7 +805,6 @@ describe('GPU-driven production projection', () => {
809
805
  meshBySlot: meshes,
810
806
  viewBindGroupLayout: viewLayout,
811
807
  meshResidencyEpoch: 1,
812
- hdrp: false,
813
808
  })
814
809
  .unwrap();
815
810
  expect(moved).toBeDefined();
@@ -892,7 +887,7 @@ describe('GPU-driven production projection', () => {
892
887
  meshBySlot: meshes,
893
888
  viewBindGroupLayout: viewLayout,
894
889
  meshResidencyEpoch: 1,
895
- hdrp: false,
890
+
896
891
  activeEntityKeys: new Set([worldEntityKey(0, 1)]),
897
892
  activeEntityRevision: 1,
898
893
  })
@@ -912,7 +907,7 @@ describe('GPU-driven production projection', () => {
912
907
  meshBySlot: meshes,
913
908
  viewBindGroupLayout: viewLayout,
914
909
  meshResidencyEpoch: 1,
915
- hdrp: false,
910
+
916
911
  activeEntityKeys: new Set([worldEntityKey(1, 2)]),
917
912
  activeEntityRevision: 2,
918
913
  })
@@ -939,7 +934,6 @@ describe('GPU-driven production projection', () => {
939
934
  meshBySlot: meshes,
940
935
  viewBindGroupLayout: viewLayout,
941
936
  meshResidencyEpoch: 1,
942
- hdrp: false,
943
937
  })
944
938
  .unwrap();
945
939
  expect(replacementPrepared?.topologySignature).not.toBe(prepared.topologySignature);
@@ -982,7 +976,6 @@ describe('GPU-driven production projection', () => {
982
976
  },
983
977
  meshBySlot: new Map([[0, mesh(device)]]),
984
978
  viewBindGroupLayout: viewLayout,
985
- hdrp: false,
986
979
  } as const;
987
980
 
988
981
  expect(
@@ -1353,7 +1346,7 @@ describe('GPU-driven production projection', () => {
1353
1346
  meshBySlot: new Map([[0, mesh(device)]]),
1354
1347
  viewBindGroupLayout: viewLayout,
1355
1348
  meshResidencyEpoch: 1,
1356
- hdrp: false,
1349
+
1357
1350
  standardPbrArtifact: artifact,
1358
1351
  standardPbrPipelineState: {
1359
1352
  pbrPipelineLayout,
@@ -1461,7 +1454,7 @@ describe('GPU-driven production projection', () => {
1461
1454
  const gpuKey = gpuDrivenShadowDrawKey(entity, -1, 0, 0);
1462
1455
  const residualKey = gpuDrivenShadowDrawKey(entity, 22, 1, 0);
1463
1456
  const allShadowKeys = new Set([gpuKey, residualKey]);
1464
- const prepareFrame = (hdrp: boolean) =>
1457
+ const prepareFrame = () =>
1465
1458
  production
1466
1459
  .prepare({
1467
1460
  scene: {
@@ -1473,7 +1466,6 @@ describe('GPU-driven production projection', () => {
1473
1466
  meshBySlot: new Map([[0, mesh(device)]]),
1474
1467
  viewBindGroupLayout: viewLayout,
1475
1468
  meshResidencyEpoch: 1,
1476
- hdrp,
1477
1469
  standardPbrArtifact: artifact,
1478
1470
  standardPbrPipelineState: {
1479
1471
  pbrPipelineLayout,
@@ -1487,7 +1479,7 @@ describe('GPU-driven production projection', () => {
1487
1479
  shadowCasterDrawKeys: allShadowKeys,
1488
1480
  })
1489
1481
  .unwrap();
1490
- const prepared = prepareFrame(false);
1482
+ const prepared = prepareFrame();
1491
1483
  expect(prepared).toBeDefined();
1492
1484
  if (prepared === undefined) return;
1493
1485
  const claimed = new Set(prepared.shadowDrawKeys ?? []);
@@ -1521,11 +1513,7 @@ describe('GPU-driven production projection', () => {
1521
1513
  );
1522
1514
  const submission = prepared.shadowViewPool?.submission(identity);
1523
1515
  expect(submission?.plan.candidateCount).toBe(1);
1524
- expect(prepareFrame(true)).toBeUndefined();
1525
- expect(production.inspect().channels.filter((channel) => channel.viewPass !== 'main')).toEqual(
1526
- [],
1527
- );
1528
- const resumed = prepareFrame(false);
1516
+ const resumed = prepareFrame();
1529
1517
  expect(
1530
1518
  resumed?.updateShadowViews?.([
1531
1519
  { identity, planes: new Float32Array(24), cacheToken: 'mixed-candidates' },
@@ -1684,7 +1672,7 @@ describe('GPU-driven production projection', () => {
1684
1672
  meshBySlot: new Map([[0, multiMesh]]),
1685
1673
  viewBindGroupLayout: viewLayout,
1686
1674
  meshResidencyEpoch: 1,
1687
- hdrp: false,
1675
+
1688
1676
  standardPbrArtifact: artifact,
1689
1677
  standardPbrPipelineState: {
1690
1678
  pbrPipelineLayout,
@@ -1906,7 +1894,7 @@ describe('GPU-driven production projection', () => {
1906
1894
  instanceBuffers: new Map(),
1907
1895
  meshBindGroupCache: new Map(),
1908
1896
  instancesBgPerEntity: new Map(),
1909
- singletonMaterialCache: new Map(),
1897
+ shadowMaterialBindGroups: new WeakMap(),
1910
1898
  materialBgShared: new Map(),
1911
1899
  },
1912
1900
  materialBgAssemblyCache: new Map(),