@forgeax/engine-render 0.1.23 → 0.1.24

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 (271) hide show
  1. package/README.md +131 -9
  2. package/dist/assembly/bundler-contract.d.ts +9 -0
  3. package/dist/assembly/bundler-contract.d.ts.map +1 -0
  4. package/dist/assembly/device-feature-admission.d.ts +8 -0
  5. package/dist/assembly/device-feature-admission.d.ts.map +1 -1
  6. package/dist/assembly/extended-lighting-fallback.d.ts +13 -0
  7. package/dist/assembly/extended-lighting-fallback.d.ts.map +1 -0
  8. package/dist/assembly/factory.d.ts +7 -243
  9. package/dist/assembly/factory.d.ts.map +1 -1
  10. package/dist/assembly/material/assembly.d.ts +3 -2
  11. package/dist/assembly/material/assembly.d.ts.map +1 -1
  12. package/dist/assembly/material/standard-layer-projection.d.ts +10 -0
  13. package/dist/assembly/material/standard-layer-projection.d.ts.map +1 -0
  14. package/dist/assembly/material-shader-policy.d.ts +168 -0
  15. package/dist/assembly/material-shader-policy.d.ts.map +1 -0
  16. package/dist/assembly/material-shader-prewarm.d.ts +21 -0
  17. package/dist/assembly/material-shader-prewarm.d.ts.map +1 -0
  18. package/dist/assembly/mesh-ssbo-grow.d.ts +88 -0
  19. package/dist/assembly/mesh-ssbo-grow.d.ts.map +1 -0
  20. package/dist/assembly/recovery/device-loss-fanout.d.ts +14 -0
  21. package/dist/assembly/recovery/device-loss-fanout.d.ts.map +1 -0
  22. package/dist/assembly/recovery/generation.d.ts +46 -0
  23. package/dist/assembly/recovery/generation.d.ts.map +1 -0
  24. package/dist/assembly/recovery/recovery-attempt.d.ts +63 -0
  25. package/dist/assembly/recovery/recovery-attempt.d.ts.map +1 -0
  26. package/dist/assembly/recovery/renderer-recover.d.ts +115 -0
  27. package/dist/assembly/recovery/renderer-recover.d.ts.map +1 -0
  28. package/dist/assembly/renderer-facade.d.ts +10 -0
  29. package/dist/assembly/renderer-facade.d.ts.map +1 -0
  30. package/dist/assembly/renderer-frame-transaction.d.ts +17 -0
  31. package/dist/assembly/renderer-frame-transaction.d.ts.map +1 -1
  32. package/dist/assembly/renderer-helpers.d.ts +19 -0
  33. package/dist/assembly/renderer-helpers.d.ts.map +1 -0
  34. package/dist/assembly/renderer-lifecycle.d.ts +34 -0
  35. package/dist/assembly/renderer-lifecycle.d.ts.map +1 -1
  36. package/dist/assembly/shader-prewarm-policy.d.ts +15 -0
  37. package/dist/assembly/shader-prewarm-policy.d.ts.map +1 -0
  38. package/dist/assembly/webgpu-ready-contract.d.ts +9 -0
  39. package/dist/assembly/webgpu-ready-contract.d.ts.map +1 -0
  40. package/dist/assembly/webgpu-ready.d.ts +55 -0
  41. package/dist/assembly/webgpu-ready.d.ts.map +1 -0
  42. package/dist/assembly/webgpu-renderer.d.ts +152 -0
  43. package/dist/assembly/webgpu-renderer.d.ts.map +1 -0
  44. package/dist/authoring.mjs +1 -1
  45. package/dist/{chunk-4L3P6DT5.mjs → chunk-GE3SDD72.mjs} +37 -5
  46. package/dist/chunk-GE3SDD72.mjs.map +1 -0
  47. package/dist/{chunk-HZUPSYW7.mjs → chunk-KZFTK6DO.mjs} +102 -15
  48. package/dist/chunk-KZFTK6DO.mjs.map +1 -0
  49. package/dist/{chunk-FF7K3FSO.mjs → chunk-Q752SHI5.mjs} +89 -89
  50. package/dist/{chunk-FF7K3FSO.mjs.map → chunk-Q752SHI5.mjs.map} +1 -1
  51. package/dist/{chunk-QODA5UKU.mjs → chunk-RR5L4SRS.mjs} +2 -2
  52. package/dist/chunk-RR5L4SRS.mjs.map +1 -0
  53. package/dist/{chunk-YALPS44A.mjs → chunk-TFH5I7JJ.mjs} +47 -47
  54. package/dist/chunk-TFH5I7JJ.mjs.map +1 -0
  55. package/dist/{chunk-FBC4R44J.mjs → chunk-UQYS7FRM.mjs} +57 -57
  56. package/dist/chunk-UQYS7FRM.mjs.map +1 -0
  57. package/dist/{chunk-4NPUASZR.mjs → chunk-YKB5DQV7.mjs} +161 -19
  58. package/dist/chunk-YKB5DQV7.mjs.map +1 -0
  59. package/dist/{chunk-ZUWKAZ2I.mjs → chunk-YRUYGA4A.mjs} +615 -237
  60. package/dist/chunk-YRUYGA4A.mjs.map +1 -0
  61. package/dist/{chunk-DIYW3M5D.mjs → chunk-Z3YYH2MB.mjs} +2210 -2213
  62. package/dist/chunk-Z3YYH2MB.mjs.map +1 -0
  63. package/dist/construct-renderer.mjs +19841 -16190
  64. package/dist/construct-renderer.mjs.map +1 -1
  65. package/dist/device/device-scope.d.ts +2 -0
  66. package/dist/device/device-scope.d.ts.map +1 -1
  67. package/dist/device/gpu-residency.d.ts +24 -4
  68. package/dist/device/gpu-residency.d.ts.map +1 -1
  69. package/dist/environment/frame.d.ts +5 -0
  70. package/dist/environment/frame.d.ts.map +1 -1
  71. package/dist/environment/inspection.d.ts +7 -0
  72. package/dist/environment/inspection.d.ts.map +1 -1
  73. package/dist/environment/lifecycle.d.ts +20 -2
  74. package/dist/environment/lifecycle.d.ts.map +1 -1
  75. package/dist/errors/recover.d.ts +58 -2
  76. package/dist/errors/recover.d.ts.map +1 -1
  77. package/dist/errors/render.d.ts +13 -0
  78. package/dist/errors/render.d.ts.map +1 -1
  79. package/dist/extract/contracts.d.ts +899 -0
  80. package/dist/extract/contracts.d.ts.map +1 -0
  81. package/dist/features/host.d.ts +2 -0
  82. package/dist/features/host.d.ts.map +1 -1
  83. package/dist/features/prepared-gpu-work.d.ts +3 -0
  84. package/dist/features/prepared-gpu-work.d.ts.map +1 -1
  85. package/dist/features/prepared-graphics-store.d.ts +2 -0
  86. package/dist/features/prepared-graphics-store.d.ts.map +1 -1
  87. package/dist/gpu-driven/production-raster.d.ts +28 -0
  88. package/dist/gpu-driven/production-raster.d.ts.map +1 -1
  89. package/dist/gpu-scene.d.ts +1 -0
  90. package/dist/gpu-scene.d.ts.map +1 -1
  91. package/dist/ibl/IblPipelineCache.d.ts +7 -6
  92. package/dist/ibl/IblPipelineCache.d.ts.map +1 -1
  93. package/dist/ibl/skylight-bind-group.d.ts +7 -1
  94. package/dist/ibl/skylight-bind-group.d.ts.map +1 -1
  95. package/dist/index.d.ts +1 -1
  96. package/dist/index.d.ts.map +1 -1
  97. package/dist/index.mjs +6 -6
  98. package/dist/internal.mjs +6 -6
  99. package/dist/light-buffer-layout.d.ts +3 -0
  100. package/dist/light-buffer-layout.d.ts.map +1 -1
  101. package/dist/materials.d.ts +34 -10
  102. package/dist/materials.d.ts.map +1 -1
  103. package/dist/mesh-material-bindings.d.ts +56 -0
  104. package/dist/mesh-material-bindings.d.ts.map +1 -1
  105. package/dist/occlusion-proxy.d.ts +4 -0
  106. package/dist/occlusion-proxy.d.ts.map +1 -0
  107. package/dist/pbr-pipeline.d.ts +32 -9
  108. package/dist/pbr-pipeline.d.ts.map +1 -1
  109. package/dist/points-lines/prepare.d.ts +3 -0
  110. package/dist/points-lines/prepare.d.ts.map +1 -1
  111. package/dist/points-lines/standard-owner.d.ts +33 -0
  112. package/dist/points-lines/standard-owner.d.ts.map +1 -0
  113. package/dist/record/frame-snapshot.d.ts +5 -0
  114. package/dist/record/frame-snapshot.d.ts.map +1 -1
  115. package/dist/record/frame-targets.d.ts.map +1 -1
  116. package/dist/record/frame.d.ts +14 -2
  117. package/dist/record/frame.d.ts.map +1 -1
  118. package/dist/record/main-pass-geometry.d.ts +14 -1
  119. package/dist/record/main-pass-geometry.d.ts.map +1 -1
  120. package/dist/record/main-pass-material.d.ts +7 -17
  121. package/dist/record/main-pass-material.d.ts.map +1 -1
  122. package/dist/record/main-pass.d.ts.map +1 -1
  123. package/dist/record/mesh-ssbo.d.ts +11 -3
  124. package/dist/record/mesh-ssbo.d.ts.map +1 -1
  125. package/dist/record/recovery-pipeline.d.ts +30 -0
  126. package/dist/record/recovery-pipeline.d.ts.map +1 -0
  127. package/dist/record/render-context.d.ts +26 -4
  128. package/dist/record/render-context.d.ts.map +1 -1
  129. package/dist/record/typed-frame-graph.d.ts +1 -1
  130. package/dist/record/typed-frame-graph.d.ts.map +1 -1
  131. package/dist/recovery/render-system-candidate.d.ts +65 -0
  132. package/dist/recovery/render-system-candidate.d.ts.map +1 -0
  133. package/dist/render-contract.d.ts +64 -7
  134. package/dist/render-contract.d.ts.map +1 -1
  135. package/dist/render-system-extract-tail.d.ts +12 -0
  136. package/dist/render-system-extract-tail.d.ts.map +1 -0
  137. package/dist/render-system-extract.d.ts +156 -22
  138. package/dist/render-system-extract.d.ts.map +1 -1
  139. package/dist/render-system.d.ts +128 -4
  140. package/dist/render-system.d.ts.map +1 -1
  141. package/dist/scene/render-scene.d.ts +19 -0
  142. package/dist/scene/render-scene.d.ts.map +1 -1
  143. package/dist/temporal/frame-coordinator.d.ts.map +1 -1
  144. package/dist/temporal/index.mjs +6 -6
  145. package/dist/temporal/taa-history-store.d.ts +15 -1
  146. package/dist/temporal/taa-history-store.d.ts.map +1 -1
  147. package/dist/temporal/transaction.d.ts +5 -0
  148. package/dist/temporal/transaction.d.ts.map +1 -1
  149. package/package.json +20 -20
  150. package/src/__tests__/device-feature-admission.unit.test.ts +6 -0
  151. package/src/__tests__/device-loss-fanout.unit.test.ts +107 -0
  152. package/src/__tests__/device-scope-lifecycle.unit.test.ts +21 -0
  153. package/src/__tests__/environment-generation.integration.test.ts +23 -0
  154. package/src/__tests__/expose-renderer-errors.unit.test.ts +34 -0
  155. package/src/__tests__/factory-contract.integration.test.ts +122 -7
  156. package/src/__tests__/fallback-row-stride-surface.unit.test.ts +4 -1
  157. package/src/__tests__/ibl/face-uniforms.unit.test.ts +2 -0
  158. package/src/__tests__/ibl-residency-publication.unit.test.ts +113 -0
  159. package/src/__tests__/material-contract-inventory.unit.test.ts +24 -9
  160. package/src/__tests__/material-cooked-projection.unit.test.ts +19 -1
  161. package/src/__tests__/material-static-dynamic-route.unit.test.ts +29 -0
  162. package/src/__tests__/material-stride-surface.unit.test.ts +7 -3
  163. package/src/__tests__/materials-standard-contract.unit.test.ts +104 -0
  164. package/src/__tests__/mesh-buffer-usage-surface.unit.test.ts +1 -1
  165. package/src/__tests__/physical-clearcoat.integration.test.ts +89 -0
  166. package/src/__tests__/prepared-gpu-driven-pbr.integration.test.ts +1 -1
  167. package/src/__tests__/prepared-graphics-pipeline-warmup.unit.test.ts +1 -1
  168. package/src/__tests__/recover-error-policy-owner.unit.test.ts +6 -3
  169. package/src/__tests__/recovery-candidate-prepare.contract.test.ts +140 -0
  170. package/src/__tests__/renderer-factory-material-contract.unit.test.ts +85 -18
  171. package/src/__tests__/renderer-frame-generation-fence.integration.test.ts +47 -0
  172. package/src/__tests__/renderer-generation-assembly.unit.test.ts +77 -0
  173. package/src/__tests__/renderer-generation-failure.unit.test.ts +108 -0
  174. package/src/__tests__/renderer-producer-root-matrix.integration.test.ts +33 -0
  175. package/src/__tests__/renderer-recovery-capability-matrix.unit.test.ts +59 -0
  176. package/src/__tests__/renderer-recovery-contract.unit.test.ts +73 -0
  177. package/src/__tests__/renderer-recovery-lifecycle.unit.test.ts +216 -0
  178. package/src/__tests__/renderer-target-history-recovery.integration.test.ts +80 -0
  179. package/src/__tests__/shader-manifest-fixture.ts +13 -16
  180. package/src/__tests__/shader-stage-surface.unit.test.ts +1 -1
  181. package/src/__tests__/standard-layer-projection.unit.test.ts +23 -0
  182. package/src/__tests__/transmission-prewarm.unit.test.ts +95 -85
  183. package/src/__tests__/volumetric-fog-topology.unit.test.ts +3 -1
  184. package/src/assembly/bundler-contract.ts +9 -0
  185. package/src/assembly/device-feature-admission.ts +15 -5
  186. package/src/assembly/extended-lighting-fallback.ts +216 -0
  187. package/src/assembly/factory.ts +81 -10088
  188. package/src/assembly/material/assembly.ts +18 -2
  189. package/src/assembly/material/standard-layer-projection.ts +16 -0
  190. package/src/assembly/material-shader-policy.ts +854 -0
  191. package/src/assembly/material-shader-prewarm.ts +88 -0
  192. package/src/assembly/mesh-ssbo-grow.ts +270 -0
  193. package/src/assembly/recovery/device-loss-fanout.ts +89 -0
  194. package/src/assembly/recovery/generation.ts +141 -0
  195. package/src/assembly/recovery/recovery-attempt.ts +800 -0
  196. package/src/assembly/recovery/renderer-recover.ts +906 -0
  197. package/src/assembly/renderer-facade.ts +342 -0
  198. package/src/assembly/renderer-frame-transaction.ts +45 -0
  199. package/src/assembly/renderer-helpers.ts +99 -0
  200. package/src/assembly/renderer-lifecycle.ts +159 -0
  201. package/src/assembly/shader-prewarm-policy.ts +157 -0
  202. package/src/assembly/webgpu-ready-contract.ts +14 -0
  203. package/src/assembly/webgpu-ready.ts +4079 -0
  204. package/src/assembly/webgpu-renderer.ts +4095 -0
  205. package/src/components/camera.ts +1 -1
  206. package/src/debug-draw-glue.ts +1 -1
  207. package/src/device/device-scope.ts +35 -6
  208. package/src/device/gpu-residency.ts +194 -26
  209. package/src/environment/frame.ts +6 -0
  210. package/src/environment/inspection.ts +10 -0
  211. package/src/environment/lifecycle.ts +114 -8
  212. package/src/errors/recover.ts +76 -5
  213. package/src/errors/render.ts +17 -0
  214. package/src/extract/contracts.ts +974 -0
  215. package/src/features/host.ts +16 -0
  216. package/src/features/prepared-gpu-work.ts +20 -2
  217. package/src/features/prepared-graphics-store.ts +17 -0
  218. package/src/gpu-driven/production-raster.ts +97 -2
  219. package/src/gpu-scene.ts +3 -2
  220. package/src/ibl/IblPipelineCache.ts +134 -50
  221. package/src/ibl/skylight-bind-group.ts +26 -0
  222. package/src/index.ts +9 -1
  223. package/src/light-buffer-layout.ts +3 -0
  224. package/src/materials.ts +262 -45
  225. package/src/mesh-material-bindings.ts +59 -0
  226. package/src/occlusion-proxy.ts +64 -0
  227. package/src/pbr-pipeline.ts +139 -15
  228. package/src/points-lines/__tests__/cache-recovery.unit.test.ts +22 -0
  229. package/src/points-lines/prepare.ts +9 -0
  230. package/src/points-lines/standard-owner.ts +403 -0
  231. package/src/record/__tests__/frame-targets-recovery.unit.test.ts +60 -0
  232. package/src/record/__tests__/main-pass-geometry.unit.test.ts +26 -1
  233. package/src/record/__tests__/mesh-ssbo.unit.test.ts +38 -0
  234. package/src/record/__tests__/recovery-pipeline.unit.test.ts +124 -0
  235. package/src/record/__tests__/sprite-material-abi.unit.test.ts +28 -13
  236. package/src/record/__tests__/standard-pbr-ubo-layout.unit.test.ts +47 -4
  237. package/src/record/__tests__/temporal-payload.unit.test.ts +22 -43
  238. package/src/record/__tests__/typed-frame-graph-plan.unit.test.ts +1 -1
  239. package/src/record/frame-snapshot.ts +15 -0
  240. package/src/record/frame-targets.ts +11 -1
  241. package/src/record/frame.ts +6 -2
  242. package/src/record/helpers.ts +1 -1
  243. package/src/record/main-pass-geometry.ts +230 -5
  244. package/src/record/main-pass-material.ts +316 -209
  245. package/src/record/main-pass-sprite-draws.ts +6 -7
  246. package/src/record/main-pass.ts +94 -6
  247. package/src/record/mesh-ssbo.ts +32 -10
  248. package/src/record/recovery-pipeline.ts +695 -0
  249. package/src/record/render-context.ts +35 -4
  250. package/src/record/typed-frame-graph.ts +45 -1
  251. package/src/record/view-ubo.ts +3 -3
  252. package/src/recovery/render-system-candidate.ts +839 -0
  253. package/src/render-contract.ts +65 -7
  254. package/src/render-system-extract-tail.ts +2983 -0
  255. package/src/render-system-extract.ts +124 -2977
  256. package/src/render-system.ts +868 -659
  257. package/src/scene/render-scene.ts +124 -1
  258. package/src/temporal/frame-coordinator.ts +4 -1
  259. package/src/temporal/taa-history-store.ts +46 -2
  260. package/src/temporal/temporal-view.ts +1 -1
  261. package/src/temporal/transaction.ts +9 -0
  262. package/src/tilemap-chunk-extract-system.ts +1 -1
  263. package/src/transmission/__tests__/standard-transmission.dawn.test.ts +19 -12
  264. package/dist/chunk-4L3P6DT5.mjs.map +0 -1
  265. package/dist/chunk-4NPUASZR.mjs.map +0 -1
  266. package/dist/chunk-DIYW3M5D.mjs.map +0 -1
  267. package/dist/chunk-FBC4R44J.mjs.map +0 -1
  268. package/dist/chunk-HZUPSYW7.mjs.map +0 -1
  269. package/dist/chunk-QODA5UKU.mjs.map +0 -1
  270. package/dist/chunk-YALPS44A.mjs.map +0 -1
  271. package/dist/chunk-ZUWKAZ2I.mjs.map +0 -1
@@ -20,7 +20,11 @@ import type {
20
20
  TextureView,
21
21
  } from '@forgeax/engine-rhi';
22
22
  import { err, ok, RhiError } from '@forgeax/engine-rhi';
23
- import type { MaterialRuntimeArtifact, MaterialShaderArtifact } from '@forgeax/engine-shader';
23
+ import {
24
+ DEFAULT_STANDARD_PBR_PARAM_SCHEMA,
25
+ type MaterialRuntimeArtifact,
26
+ type MaterialShaderArtifact,
27
+ } from '@forgeax/engine-shader';
24
28
  import type {
25
29
  MaterialRenderState,
26
30
  ParamSchemaEntry,
@@ -28,6 +32,7 @@ import type {
28
32
  PrimitiveTopology,
29
33
  VertexAttributeMap,
30
34
  } from '@forgeax/engine-types';
35
+ import { derive } from '@forgeax/engine-types';
31
36
  import type { MaterialRenderProjection } from '../assembly/material/assembly';
32
37
  import type { DeviceScope } from '../device/device-scope';
33
38
  import type { MeshGpuHandles } from '../device/gpu-residency';
@@ -103,6 +108,18 @@ export interface MaterialShaderPipelineEntry {
103
108
  readonly group2Contract: PipelineGroup2Contract;
104
109
  }
105
110
 
111
+ /**
112
+ * Armed only for the first published recovery frame. Candidate preparation
113
+ * must make every pipeline and static residency lookup a cache hit before this
114
+ * guard is armed; a miss is a hard failure before queue submission.
115
+ */
116
+ export interface RecoveryColdWorkGuard {
117
+ arm(): void;
118
+ notePipelineColdWork(): void;
119
+ noteUploadColdWork(): void;
120
+ finish(): void;
121
+ }
122
+
106
123
  import type {
107
124
  RenderDebugOverlay,
108
125
  RenderPipelineContext,
@@ -133,6 +150,8 @@ export interface RenderSystemRuntime {
133
150
  /** Internal backend-fixture hook evaluated at the submit transaction edge. */
134
151
  readonly beforeSubmit?: ((device: RhiDevice) => RhiError | undefined) | undefined;
135
152
  readonly deviceScope: DeviceScope;
153
+ /** Resolve a recorder/backend wrapper before configuring the native surface. */
154
+ readonly resolveSurfaceDevice?: (device: RhiDevice) => Result<RhiDevice, RhiError>;
136
155
  readonly errorRegistry: RhiErrorListenerRegistry;
137
156
  readonly debugOverlay?: RenderDebugOverlay | undefined;
138
157
  readonly healthRegistry: HealthListenerRegistry;
@@ -180,11 +199,17 @@ export interface RenderSystemRuntime {
180
199
  layoutKindOverride?: 'pbr' | 'pbr-skin',
181
200
  additionalColorFormats?: readonly GPUTextureFormat[],
182
201
  ) => MaterialShaderPipelineEntry | null;
202
+ /** Reflection-derived UV count included in the material PipelineSpec cache key. */
203
+ readonly getMaterialShaderUvSetCount?: (materialShaderId: string) => number | undefined;
183
204
  readonly getMaterialShaderBindingContract?: (
184
205
  materialShaderId: string,
185
206
  ) => 'group-0' | 'group-0-resource' | 'view-only' | 'view-and-scene-depth' | 'render-material';
186
207
  readonly getParamSchema?: (materialShaderId: string) => readonly ParamSchemaEntry[] | undefined;
187
- readonly getMaterialBindGroupLayout?: (materialShaderId: string) => BindGroupLayout | undefined;
208
+ readonly getMaterialBindGroupLayout?: (
209
+ materialShaderId: string,
210
+ materialParamSchema?: readonly ParamSchemaEntry[],
211
+ ) => BindGroupLayout | undefined;
212
+ recoveryColdWorkGuard?: RecoveryColdWorkGuard | undefined;
188
213
  readonly metrics: EngineMetrics;
189
214
  readonly lookupPostProcess?: (
190
215
  id: string,
@@ -196,6 +221,8 @@ export interface RenderSystemRuntime {
196
221
  colorFormat: GPUTextureFormat,
197
222
  entry?: import('../fullscreen-post-process-pass').PostProcessShaderEntry,
198
223
  ) => RhiRenderPipeline | null;
224
+ /** Candidate-owned post-process pipelines transferred at publication. */
225
+ readonly getRecoveryPostProcessPipelines?: () => ReadonlyMap<string, RhiRenderPipeline>;
199
226
  readonly clearPostProcessPipelineCache?: (id: string) => void;
200
227
  readonly invalidateShaderModule?: (label: string) => void;
201
228
  readonly dynamicTextureStore?: DynamicTextureStore | undefined;
@@ -356,6 +383,8 @@ export interface PipelineState {
356
383
  readonly skinPaletteAllocator: SkinPaletteAllocator | null;
357
384
  readonly defaultWhiteTextureView: TextureView;
358
385
  readonly defaultNormalTextureView: TextureView;
386
+ /** Missing anisotropy maps encode a neutral direction and unit strength. */
387
+ readonly defaultAnisotropyTextureView?: TextureView;
359
388
  readonly unlitPipelineHdr: RhiRenderPipeline | null;
360
389
  readonly shadowFallbackTextureView: TextureView;
361
390
  readonly shadowAtlasFallbackTextureView: TextureView;
@@ -386,6 +415,8 @@ export interface RenderSystemInternals extends RenderSystemRuntime {
386
415
  readonly standardProfile?: StandardProfile | undefined;
387
416
  readonly standardPipeline: RenderFrameState['activePipeline'];
388
417
  readonly featureHost?: RenderFeatureHost | undefined;
418
+ /** Install a detached feature host only at the recovery publication boundary. */
419
+ readonly setFeatureHost?: ((host: RenderFeatureHost) => void) | undefined;
389
420
  readonly shaderModuleFactory?: PipelineBuilderShaderModuleFactory;
390
421
  readonly createShaderModule?: (
391
422
  device: import('@forgeax/engine-rhi').RhiDevice,
@@ -492,8 +523,8 @@ export type _InternalRenderPipelineContext = RenderPipelineContext & _StandardFo
492
523
 
493
524
  export type RecordProfileRunner = <T>(phase: RenderRecordPhase, action: () => T) => T;
494
525
 
495
- export const STANDARD_PBR_UBO_SIZE = 384;
496
- export const MATERIAL_PER_ENTITY_STRIDE = 512;
526
+ export const STANDARD_PBR_UBO_SIZE = derive(DEFAULT_STANDARD_PBR_PARAM_SCHEMA).uboLayout.totalBytes;
527
+ export const MATERIAL_PER_ENTITY_STRIDE = Math.ceil(STANDARD_PBR_UBO_SIZE / 256) * 256;
497
528
 
498
529
  export type SwapChainFormatPair = {
499
530
  readonly storage: GPUTextureFormat;
@@ -811,6 +811,7 @@ export interface RenderFeatureGraphCandidate {
811
811
  }
812
812
 
813
813
  const featureGraphStates = new WeakMap<RenderSystemInternals, RenderFeatureGraphRuntimeState>();
814
+ const graphDeviceGenerations = new WeakMap<object, number>();
814
815
 
815
816
  interface TimingInstrumentationState {
816
817
  readonly instrumentation: RenderGraphPassInstrumentation<RenderPipelineFrame>;
@@ -1349,6 +1350,7 @@ export function ensureCompiledFrameGraph(
1349
1350
  volumetricFog?: ExtractedVolumetricFog,
1350
1351
  volumeTopologyCandidate = false,
1351
1352
  standardLighting?: StandardTopologyInputValue,
1353
+ onRecoveryError?: (error: unknown) => void,
1352
1354
  ): CompiledRenderGraph<RenderPipelineFrame> | null {
1353
1355
  const requestedStandardLightingSignature = standardLightingTopologySignature(standardLighting);
1354
1356
  const lastKnownGood = (): CompiledRenderGraph<RenderPipelineFrame> | null =>
@@ -1361,6 +1363,7 @@ export function ensureCompiledFrameGraph(
1361
1363
  const featurePlans = featureGraphCandidate?.plans ?? getRenderFeatureGraphState(internals).plans;
1362
1364
  const projectedFeaturePlans = validateRenderFeaturePlans(featurePlans);
1363
1365
  if (!projectedFeaturePlans.ok) {
1366
+ onRecoveryError?.(projectedFeaturePlans.error);
1364
1367
  reportRenderFeatureGraphError(internals, projectedFeaturePlans.error);
1365
1368
  featureGraphCandidate?.onRejected?.();
1366
1369
  return volumeTopologyCandidate ? null : lastKnownGood();
@@ -1383,6 +1386,7 @@ export function ensureCompiledFrameGraph(
1383
1386
  standardLighting,
1384
1387
  );
1385
1388
  if (!topologyResult.ok) {
1389
+ onRecoveryError?.(topologyResult.error);
1386
1390
  internals.errorRegistry.fire(topologyResult.error);
1387
1391
  featureGraphCandidate?.onRejected?.();
1388
1392
  return volumeTopologyCandidate ? null : lastKnownGood();
@@ -1521,6 +1525,7 @@ export function ensureCompiledFrameGraph(
1521
1525
  topology,
1522
1526
  );
1523
1527
  if (!built.ok) {
1528
+ onRecoveryError?.(built.error);
1524
1529
  internals.errorRegistry.fire(built.error);
1525
1530
  featureGraphCandidate?.onRejected?.();
1526
1531
  return volumeTopologyCandidate ? null : lastKnownGood();
@@ -1530,6 +1535,7 @@ export function ensureCompiledFrameGraph(
1530
1535
  surfaceSize: { width: surfaceWidth, height: surfaceHeight },
1531
1536
  });
1532
1537
  if (!compiled.ok) {
1538
+ onRecoveryError?.(compiled.error);
1533
1539
  internals.errorRegistry.fire(compiled.error);
1534
1540
  featureGraphCandidate?.onRejected?.();
1535
1541
  return lastKnownGood();
@@ -1552,6 +1558,10 @@ export function ensureCompiledFrameGraph(
1552
1558
  getColorTargetTexture: (name) => compiledTargets.getColorTargetTexture(name),
1553
1559
  graphGeneration: frameState.graphGeneration,
1554
1560
  };
1561
+ const deviceGeneration = internals.deviceScope?.generation;
1562
+ if (deviceGeneration !== undefined) {
1563
+ graphDeviceGenerations.set(compiled.value, deviceGeneration);
1564
+ }
1555
1565
  gpuDriven?._commitResourceReplacement();
1556
1566
  if (featureGraphCandidate !== undefined && !postProcessAdmission.pending) {
1557
1567
  commitFeatureCandidate(internals, featureGraphCandidate);
@@ -1635,6 +1645,29 @@ export function executeCompiledFrameGraph(
1635
1645
  : legacyTimingInstrumentation;
1636
1646
  type PreparedCommand = { readonly command: CommandBuffer };
1637
1647
  let preparedCommand: PreparedCommand = { command: undefined as never };
1648
+ const deviceScope = internals.deviceScope;
1649
+ const graphDeviceGeneration = graphDeviceGenerations.get(graph);
1650
+ if (
1651
+ graphDeviceGeneration !== undefined &&
1652
+ deviceScope !== undefined &&
1653
+ graphDeviceGeneration !== deviceScope.generation
1654
+ ) {
1655
+ internals.errorRegistry.fire(
1656
+ new RhiError({
1657
+ code: 'webgpu-runtime-error',
1658
+ expected: 'the compiled frame graph belongs to the active device generation',
1659
+ hint: 'discard the stale graph and rebuild it from the retained logical frame plan',
1660
+ detail: {
1661
+ error: {
1662
+ code: 'stale-frame-graph-generation',
1663
+ message: `graph=${graphDeviceGeneration}; current=${deviceScope.generation}`,
1664
+ },
1665
+ },
1666
+ }),
1667
+ );
1668
+ return false;
1669
+ }
1670
+ const capturedGeneration = deviceScope?.generation;
1638
1671
  const transaction = executeRendererFrameTransaction<PreparedCommand>({
1639
1672
  build: () => ({ ok: true, value: { command: undefined as never } }),
1640
1673
  execute: () => {
@@ -1662,7 +1695,7 @@ export function executeCompiledFrameGraph(
1662
1695
  const graphAccess = frameState.perFrameGraph;
1663
1696
  const graphTexture = graphAccess?.getColorTargetTexture(graphCapture.name);
1664
1697
  const descriptor = graphAccess?.getColorTargetDescriptor(graphCapture.name);
1665
- const frameId = frameState.frameNumber - 1;
1698
+ const frameId = frameState.frameNumber;
1666
1699
  const captureFailure = (message: string): void => {
1667
1700
  internals.errorRegistry.fire(
1668
1701
  new RhiError({
@@ -1865,6 +1898,17 @@ export function executeCompiledFrameGraph(
1865
1898
  timingCapture?.markSubmitted();
1866
1899
  return { ok: true, value: undefined };
1867
1900
  },
1901
+ ...(capturedGeneration === undefined || deviceScope === undefined
1902
+ ? {}
1903
+ : {
1904
+ generationFence: {
1905
+ capturedGeneration,
1906
+ // Read the owner at submit time. Recovery publishes a replacement
1907
+ // scope synchronously between finish and submit; retaining the
1908
+ // entry scope here would make that race invisible to the fence.
1909
+ currentGeneration: () => internals.deviceScope?.generation ?? -1,
1910
+ },
1911
+ }),
1868
1912
  commit: () => {
1869
1913
  frameHooks?.onSubmitted?.();
1870
1914
  if (frameState.temporalFrameInput !== undefined) {
@@ -164,9 +164,9 @@ export function writeViewUbo(
164
164
  const VIEW_PAYLOAD_FLOATS = 240;
165
165
  const viewPayload = new Float32Array(VIEW_PAYLOAD_FLOATS);
166
166
  for (let i = 0; i < 16; i++) viewPayload[i] = mainProjection[i] ?? 0;
167
- viewPayload[16] = (light.direction[0] ?? 0) * light.intensity;
168
- viewPayload[17] = (light.direction[1] ?? -1) * light.intensity;
169
- viewPayload[18] = (light.direction[2] ?? 0) * light.intensity;
167
+ viewPayload[16] = light.direction[0] ?? 0;
168
+ viewPayload[17] = light.direction[1] ?? -1;
169
+ viewPayload[18] = light.direction[2] ?? 0;
170
170
  viewPayload[20] = light.color[0] ?? 0;
171
171
  viewPayload[21] = light.color[1] ?? 0;
172
172
  viewPayload[22] = light.color[2] ?? 0;