@forgeax/engine-render 0.1.21 → 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.
- package/README.md +281 -38
- package/dist/assembly/backend-contract.d.ts +13 -0
- package/dist/assembly/backend-contract.d.ts.map +1 -1
- package/dist/assembly/bundler-contract.d.ts +9 -0
- package/dist/assembly/bundler-contract.d.ts.map +1 -0
- package/dist/assembly/device-feature-admission.d.ts +8 -0
- package/dist/assembly/device-feature-admission.d.ts.map +1 -1
- package/dist/assembly/extended-lighting-fallback.d.ts +13 -0
- package/dist/assembly/extended-lighting-fallback.d.ts.map +1 -0
- package/dist/assembly/factory.d.ts +7 -235
- package/dist/assembly/factory.d.ts.map +1 -1
- package/dist/assembly/host-contract.d.ts +10 -0
- package/dist/assembly/host-contract.d.ts.map +1 -1
- package/dist/assembly/material/assembly.d.ts +3 -2
- package/dist/assembly/material/assembly.d.ts.map +1 -1
- package/dist/assembly/material/standard-layer-projection.d.ts +10 -0
- package/dist/assembly/material/standard-layer-projection.d.ts.map +1 -0
- package/dist/assembly/material-shader-policy.d.ts +168 -0
- package/dist/assembly/material-shader-policy.d.ts.map +1 -0
- package/dist/assembly/material-shader-prewarm.d.ts +21 -0
- package/dist/assembly/material-shader-prewarm.d.ts.map +1 -0
- package/dist/assembly/mesh-ssbo-grow.d.ts +88 -0
- package/dist/assembly/mesh-ssbo-grow.d.ts.map +1 -0
- package/dist/assembly/recovery/device-loss-fanout.d.ts +14 -0
- package/dist/assembly/recovery/device-loss-fanout.d.ts.map +1 -0
- package/dist/assembly/recovery/generation.d.ts +46 -0
- package/dist/assembly/recovery/generation.d.ts.map +1 -0
- package/dist/assembly/recovery/recovery-attempt.d.ts +63 -0
- package/dist/assembly/recovery/recovery-attempt.d.ts.map +1 -0
- package/dist/assembly/recovery/renderer-recover.d.ts +115 -0
- package/dist/assembly/recovery/renderer-recover.d.ts.map +1 -0
- package/dist/assembly/renderer-facade.d.ts +10 -0
- package/dist/assembly/renderer-facade.d.ts.map +1 -0
- package/dist/assembly/renderer-frame-transaction.d.ts +17 -0
- package/dist/assembly/renderer-frame-transaction.d.ts.map +1 -1
- package/dist/assembly/renderer-helpers.d.ts +19 -0
- package/dist/assembly/renderer-helpers.d.ts.map +1 -0
- package/dist/assembly/renderer-lifecycle.d.ts +34 -0
- package/dist/assembly/renderer-lifecycle.d.ts.map +1 -1
- package/dist/assembly/shader-prewarm-policy.d.ts +15 -0
- package/dist/assembly/shader-prewarm-policy.d.ts.map +1 -0
- package/dist/assembly/webgpu-ready-contract.d.ts +9 -0
- package/dist/assembly/webgpu-ready-contract.d.ts.map +1 -0
- package/dist/assembly/webgpu-ready.d.ts +55 -0
- package/dist/assembly/webgpu-ready.d.ts.map +1 -0
- package/dist/assembly/webgpu-renderer.d.ts +152 -0
- package/dist/assembly/webgpu-renderer.d.ts.map +1 -0
- package/dist/authoring.mjs +1 -1
- package/dist/{chunk-PCHBPYML.mjs → chunk-GE3SDD72.mjs} +37 -5
- package/dist/chunk-GE3SDD72.mjs.map +1 -0
- package/dist/chunk-KZFTK6DO.mjs +1191 -0
- package/dist/chunk-KZFTK6DO.mjs.map +1 -0
- package/dist/{chunk-FS2KNUQH.mjs → chunk-Q752SHI5.mjs} +332 -568
- package/dist/chunk-Q752SHI5.mjs.map +1 -0
- package/dist/{chunk-6OPXDQ2E.mjs → chunk-RR5L4SRS.mjs} +33 -294
- package/dist/chunk-RR5L4SRS.mjs.map +1 -0
- package/dist/chunk-TFH5I7JJ.mjs +296 -0
- package/dist/chunk-TFH5I7JJ.mjs.map +1 -0
- package/dist/chunk-UQYS7FRM.mjs +1003 -0
- package/dist/chunk-UQYS7FRM.mjs.map +1 -0
- package/dist/chunk-YKB5DQV7.mjs +345 -0
- package/dist/chunk-YKB5DQV7.mjs.map +1 -0
- package/dist/{chunk-5YADUCA7.mjs → chunk-YRUYGA4A.mjs} +1189 -1217
- package/dist/chunk-YRUYGA4A.mjs.map +1 -0
- package/dist/chunk-Z3YYH2MB.mjs +5082 -0
- package/dist/chunk-Z3YYH2MB.mjs.map +1 -0
- package/dist/cluster-binner.d.ts +5 -0
- package/dist/cluster-binner.d.ts.map +1 -1
- package/dist/components/index.d.ts +3 -0
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/light-helpers.d.ts +4 -0
- package/dist/components/light-helpers.d.ts.map +1 -1
- package/dist/components/light-probe.d.ts +9 -0
- package/dist/components/light-probe.d.ts.map +1 -0
- package/dist/components/rect-area-light.d.ts +12 -0
- package/dist/components/rect-area-light.d.ts.map +1 -0
- package/dist/components/scene-instance.d.ts +4 -0
- package/dist/components/scene-instance.d.ts.map +1 -1
- package/dist/components/spot-light.d.ts +3 -0
- package/dist/components/spot-light.d.ts.map +1 -1
- package/dist/construct-renderer.mjs +27276 -23232
- package/dist/construct-renderer.mjs.map +1 -1
- package/dist/device/device-scope.d.ts +2 -0
- package/dist/device/device-scope.d.ts.map +1 -1
- package/dist/device/gpu-residency.d.ts +32 -5
- package/dist/device/gpu-residency.d.ts.map +1 -1
- package/dist/device/lifecycle-transaction.d.ts +2 -0
- package/dist/device/lifecycle-transaction.d.ts.map +1 -0
- package/dist/environment/frame.d.ts +5 -0
- package/dist/environment/frame.d.ts.map +1 -1
- package/dist/environment/inspection.d.ts +7 -0
- package/dist/environment/inspection.d.ts.map +1 -1
- package/dist/environment/lifecycle.d.ts +20 -2
- package/dist/environment/lifecycle.d.ts.map +1 -1
- package/dist/errors/gpu-driven.d.ts +26 -0
- package/dist/errors/gpu-driven.d.ts.map +1 -0
- package/dist/errors/index.d.ts +1 -0
- package/dist/errors/index.d.ts.map +1 -1
- package/dist/errors/recover.d.ts +67 -3
- package/dist/errors/recover.d.ts.map +1 -1
- package/dist/errors/render.d.ts +39 -1
- package/dist/errors/render.d.ts.map +1 -1
- package/dist/extract/contracts.d.ts +899 -0
- package/dist/extract/contracts.d.ts.map +1 -0
- package/dist/extract/gpu-driven.d.ts +50 -0
- package/dist/extract/gpu-driven.d.ts.map +1 -0
- package/dist/extract/visibility.d.ts.map +1 -1
- package/dist/features/host.d.ts +2 -0
- package/dist/features/host.d.ts.map +1 -1
- package/dist/features/prepared-gpu-work.d.ts +3 -0
- package/dist/features/prepared-gpu-work.d.ts.map +1 -1
- package/dist/features/prepared-graphics-store.d.ts +2 -0
- package/dist/features/prepared-graphics-store.d.ts.map +1 -1
- package/dist/gpu-driven/batch-topology.d.ts +34 -0
- package/dist/gpu-driven/batch-topology.d.ts.map +1 -1
- package/dist/gpu-driven/prepared-draw.d.ts +63 -0
- package/dist/gpu-driven/prepared-draw.d.ts.map +1 -0
- package/dist/gpu-driven/production-raster.d.ts +126 -2
- package/dist/gpu-driven/production-raster.d.ts.map +1 -1
- package/dist/gpu-driven/view-gpu.d.ts +64 -1
- package/dist/gpu-driven/view-gpu.d.ts.map +1 -1
- package/dist/gpu-scene-schema.d.ts +14 -0
- package/dist/gpu-scene-schema.d.ts.map +1 -1
- package/dist/gpu-scene.d.ts +9 -1
- package/dist/gpu-scene.d.ts.map +1 -1
- package/dist/gpu-usage.d.ts +0 -1
- package/dist/gpu-usage.d.ts.map +1 -1
- package/dist/hdrp-buffers.d.ts +3 -3
- package/dist/hdrp-buffers.d.ts.map +1 -1
- package/dist/ibl/IblPipelineCache.d.ts +7 -6
- package/dist/ibl/IblPipelineCache.d.ts.map +1 -1
- package/dist/ibl/skylight-bind-group.d.ts +7 -1
- package/dist/ibl/skylight-bind-group.d.ts.map +1 -1
- package/dist/index.d.ts +13 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.mjs +90 -5
- package/dist/index.mjs.map +1 -1
- package/dist/inspection-types.d.ts +163 -1
- package/dist/inspection-types.d.ts.map +1 -1
- package/dist/internal.d.ts +9 -0
- package/dist/internal.d.ts.map +1 -1
- package/dist/internal.mjs +23 -2
- package/dist/internal.mjs.map +1 -1
- package/dist/light-buffer-layout.d.ts +60 -148
- package/dist/light-buffer-layout.d.ts.map +1 -1
- package/dist/materials.d.ts +34 -10
- package/dist/materials.d.ts.map +1 -1
- package/dist/mesh-material-bindings.d.ts +56 -0
- package/dist/mesh-material-bindings.d.ts.map +1 -1
- package/dist/occlusion-proxy.d.ts +4 -0
- package/dist/occlusion-proxy.d.ts.map +1 -0
- package/dist/pbr-pipeline.d.ts +58 -21
- package/dist/pbr-pipeline.d.ts.map +1 -1
- package/dist/pipeline/standard-forward-lane.d.ts.map +1 -1
- package/dist/pipeline/standard-lighting/graph.d.ts.map +1 -1
- package/dist/pipeline/standard-lighting/light-frame.d.ts +3 -3
- package/dist/pipeline/standard-lighting/light-frame.d.ts.map +1 -1
- package/dist/pipeline/standard-lighting/topology.d.ts +1 -1
- package/dist/pipeline/standard-lighting/topology.d.ts.map +1 -1
- package/dist/pipeline/standard-lighting/transport.d.ts.map +1 -1
- package/dist/pipeline/standard-pipeline.d.ts.map +1 -1
- package/dist/pipeline-builder.d.ts +2 -0
- package/dist/pipeline-builder.d.ts.map +1 -1
- package/dist/pipeline-spec.d.ts +1 -1
- package/dist/pipeline-spec.d.ts.map +1 -1
- package/dist/plugin.d.ts.map +1 -1
- package/dist/points-lines/prepare.d.ts +3 -0
- package/dist/points-lines/prepare.d.ts.map +1 -1
- package/dist/points-lines/standard-owner.d.ts +33 -0
- package/dist/points-lines/standard-owner.d.ts.map +1 -0
- package/dist/prepare/extended-lighting/ltc-resources.d.ts +31 -0
- package/dist/prepare/extended-lighting/ltc-resources.d.ts.map +1 -0
- package/dist/prepare/extended-lighting/resources.d.ts +72 -0
- package/dist/prepare/extended-lighting/resources.d.ts.map +1 -0
- package/dist/prepare/extended-lighting/spot-modifiers.d.ts +42 -0
- package/dist/prepare/extended-lighting/spot-modifiers.d.ts.map +1 -0
- package/dist/prepare/extended-lighting/state.d.ts +24 -0
- package/dist/prepare/extended-lighting/state.d.ts.map +1 -0
- package/dist/record/frame-lighting.d.ts +8 -6
- package/dist/record/frame-lighting.d.ts.map +1 -1
- package/dist/record/frame-snapshot.d.ts +55 -10
- package/dist/record/frame-snapshot.d.ts.map +1 -1
- package/dist/record/frame-targets.d.ts.map +1 -1
- package/dist/record/frame.d.ts +21 -5
- package/dist/record/frame.d.ts.map +1 -1
- package/dist/record/gpu-timing.d.ts +19 -7
- package/dist/record/gpu-timing.d.ts.map +1 -1
- package/dist/record/helpers.d.ts +0 -20
- package/dist/record/helpers.d.ts.map +1 -1
- package/dist/record/main-pass-geometry.d.ts +20 -2
- package/dist/record/main-pass-geometry.d.ts.map +1 -1
- package/dist/record/main-pass-material.d.ts +10 -18
- package/dist/record/main-pass-material.d.ts.map +1 -1
- package/dist/record/main-pass-sprite-draws.d.ts.map +1 -1
- package/dist/record/main-pass.d.ts.map +1 -1
- package/dist/record/mesh-ssbo.d.ts +11 -3
- package/dist/record/mesh-ssbo.d.ts.map +1 -1
- package/dist/record/recovery-pipeline.d.ts +30 -0
- package/dist/record/recovery-pipeline.d.ts.map +1 -0
- package/dist/record/render-context.d.ts +82 -9
- package/dist/record/render-context.d.ts.map +1 -1
- package/dist/record/shadow-pass.d.ts.map +1 -1
- package/dist/record/typed-frame-graph.d.ts +49 -2
- package/dist/record/typed-frame-graph.d.ts.map +1 -1
- package/dist/record/view-ubo.d.ts +1 -2
- package/dist/record/view-ubo.d.ts.map +1 -1
- package/dist/recovery/render-system-candidate.d.ts +65 -0
- package/dist/recovery/render-system-candidate.d.ts.map +1 -0
- package/dist/reflection/inspection.d.ts +10 -0
- package/dist/reflection/inspection.d.ts.map +1 -0
- package/dist/reflection/projection.d.ts +49 -0
- package/dist/reflection/projection.d.ts.map +1 -1
- package/dist/reflection/record-owner.d.ts +60 -0
- package/dist/reflection/record-owner.d.ts.map +1 -0
- package/dist/render-contract.d.ts +78 -15
- package/dist/render-contract.d.ts.map +1 -1
- package/dist/render-pipeline.d.ts +7 -0
- package/dist/render-pipeline.d.ts.map +1 -1
- package/dist/render-system-extract-tail.d.ts +12 -0
- package/dist/render-system-extract-tail.d.ts.map +1 -0
- package/dist/render-system-extract.d.ts +252 -30
- package/dist/render-system-extract.d.ts.map +1 -1
- package/dist/render-system.d.ts +140 -5
- package/dist/render-system.d.ts.map +1 -1
- package/dist/scene/probe-blend-record.d.ts +22 -0
- package/dist/scene/probe-blend-record.d.ts.map +1 -0
- package/dist/scene/probe-blend.d.ts +142 -0
- package/dist/scene/probe-blend.d.ts.map +1 -0
- package/dist/scene/render-scene-types.d.ts +0 -6
- package/dist/scene/render-scene-types.d.ts.map +1 -1
- package/dist/scene/render-scene.d.ts +122 -9
- package/dist/scene/render-scene.d.ts.map +1 -1
- package/dist/scene/visibility/bounds.d.ts +20 -0
- package/dist/scene/visibility/bounds.d.ts.map +1 -0
- package/dist/scene/visibility/budget.d.ts +16 -0
- package/dist/scene/visibility/budget.d.ts.map +1 -0
- package/dist/scene/visibility/facet.d.ts +73 -0
- package/dist/scene/visibility/facet.d.ts.map +1 -0
- package/dist/scene/visibility/gpu-frame-timing.d.ts +41 -0
- package/dist/scene/visibility/gpu-frame-timing.d.ts.map +1 -0
- package/dist/scene/visibility/gpu-lod.d.ts +46 -0
- package/dist/scene/visibility/gpu-lod.d.ts.map +1 -0
- package/dist/scene/visibility/inspection.d.ts +132 -0
- package/dist/scene/visibility/inspection.d.ts.map +1 -0
- package/dist/scene/visibility/lod-selector.d.ts +25 -0
- package/dist/scene/visibility/lod-selector.d.ts.map +1 -0
- package/dist/scene/visibility/occlusion-confidence.d.ts +81 -0
- package/dist/scene/visibility/occlusion-confidence.d.ts.map +1 -0
- package/dist/scene/visibility/occlusion-pass.d.ts +57 -0
- package/dist/scene/visibility/occlusion-pass.d.ts.map +1 -0
- package/dist/scene/visibility/occlusion-query-pool.d.ts +57 -0
- package/dist/scene/visibility/occlusion-query-pool.d.ts.map +1 -0
- package/dist/scene/visibility/occlusion-runtime.d.ts +96 -0
- package/dist/scene/visibility/occlusion-runtime.d.ts.map +1 -0
- package/dist/scene/visibility/types.d.ts +34 -0
- package/dist/scene/visibility/types.d.ts.map +1 -0
- package/dist/ssr/admission.d.ts +122 -0
- package/dist/ssr/admission.d.ts.map +1 -0
- package/dist/ssr/composition.d.ts +32 -0
- package/dist/ssr/composition.d.ts.map +1 -0
- package/dist/ssr/errors.d.ts +39 -0
- package/dist/ssr/errors.d.ts.map +1 -0
- package/dist/ssr/identity.d.ts +13 -0
- package/dist/ssr/identity.d.ts.map +1 -0
- package/dist/systems/skin-palette-allocator.d.ts +1 -1
- package/dist/temporal/frame-coordinator.d.ts +13 -0
- package/dist/temporal/frame-coordinator.d.ts.map +1 -1
- package/dist/temporal/frame.d.ts +2 -0
- package/dist/temporal/frame.d.ts.map +1 -1
- package/dist/temporal/index.mjs +6 -5
- package/dist/temporal/taa-history-store.d.ts +15 -1
- package/dist/temporal/taa-history-store.d.ts.map +1 -1
- package/dist/temporal/transaction.d.ts +5 -0
- package/dist/temporal/transaction.d.ts.map +1 -1
- package/dist/temporal/view.d.ts +7 -0
- package/dist/temporal/view.d.ts.map +1 -1
- package/dist/tilemap-chunk-extract-system.d.ts +1 -1
- package/dist/typed-render-graph-primitives.d.ts +4 -0
- package/dist/typed-render-graph-primitives.d.ts.map +1 -1
- package/dist/volume/passes.d.ts +8 -4
- package/dist/volume/passes.d.ts.map +1 -1
- package/package.json +20 -20
- package/src/__tests__/cluster-grid-default-surface.unit.test.ts +5 -0
- package/src/__tests__/detached-inspection.integration.test.ts +6 -0
- package/src/__tests__/device-feature-admission.unit.test.ts +19 -1
- package/src/__tests__/device-loss-fanout.unit.test.ts +107 -0
- package/src/__tests__/device-scope-lifecycle.unit.test.ts +21 -0
- package/src/__tests__/direct-light-snapshot.unit.test.ts +59 -3
- package/src/__tests__/environment-generation.integration.test.ts +39 -0
- package/src/__tests__/evidence-identity.ts +13 -0
- package/src/__tests__/evidence-identity.unit.test.ts +24 -0
- package/src/__tests__/expose-renderer-errors.unit.test.ts +34 -0
- package/src/__tests__/extended-lighting-recovery.browser.test.ts +14 -0
- package/src/__tests__/extended-lighting-recovery.dawn.test.ts +14 -0
- package/src/__tests__/extended-lighting-recovery.integration.test.ts +81 -0
- package/src/__tests__/extended-lighting-resources.unit.test.ts +51 -0
- package/src/__tests__/extended-lighting-zero-feature.integration.test.ts +52 -0
- package/src/__tests__/factory-contract.integration.test.ts +154 -6
- package/src/__tests__/fallback-row-stride-surface.unit.test.ts +4 -1
- package/src/__tests__/frame-observation.contract.test.ts +15 -0
- package/src/__tests__/gpu-driven-batch-topology-pbr.unit.test.ts +146 -0
- package/src/__tests__/gpu-driven-indirect-raster-evidence.ts +1 -0
- package/src/__tests__/gpu-driven-indirect-raster.dawn.test.ts +1 -0
- package/src/__tests__/gpu-driven-production.integration.test.ts +572 -9
- package/src/__tests__/gpu-driven-scaling.unit.test.ts +66 -2
- package/src/__tests__/gpu-driven-view-gpu-evidence.ts +26 -1
- package/src/__tests__/gpu-driven-view-graph.integration.test.ts +89 -2
- package/src/__tests__/gpu-driven-view.browser.test.ts +3 -3
- package/src/__tests__/gpu-driven-view.dawn.test.ts +3 -3
- package/src/__tests__/gpu-driven-view.unit.test.ts +50 -0
- package/src/__tests__/gpu-lod-evidence.ts +188 -0
- package/src/__tests__/gpu-lod-fallback.integration.test.ts +10 -0
- package/src/__tests__/gpu-lod-indirect.integration.test.ts +40 -0
- package/src/__tests__/gpu-lod-parity.dawn.test.ts +29 -0
- package/src/__tests__/gpu-lod-readiness.integration.test.ts +52 -0
- package/src/__tests__/gpu-lod-schema.unit.test.ts +66 -0
- package/src/__tests__/gpu-lod-selector.unit.test.ts +28 -0
- package/src/__tests__/gpu-lod-silhouette.browser.test.ts +13 -0
- package/src/__tests__/gpu-resource-store-stride.unit.test.ts +66 -1
- package/src/__tests__/gpu-scene.dawn.test.ts +8 -1
- package/src/__tests__/gpu-scene.unit.test.ts +49 -3
- package/src/__tests__/ibl/face-uniforms.unit.test.ts +2 -0
- package/src/__tests__/ibl-residency-publication.unit.test.ts +113 -0
- package/src/__tests__/light-buffer-layout.unit.test.ts +113 -3
- package/src/__tests__/light-inspection.unit.test.ts +55 -0
- package/src/__tests__/light-resource-error.unit.test.ts +43 -0
- package/src/__tests__/lighting-scene-roundtrip.integration.test.ts +109 -0
- package/src/__tests__/lod-bounds.unit.test.ts +42 -0
- package/src/__tests__/lod-cpu-lane.integration.test.ts +55 -0
- package/src/__tests__/lod-cpu-no-change.perf.test.ts +19 -0
- package/src/__tests__/lod-gpu-frame-timing.unit.test.ts +49 -0
- package/src/__tests__/lod-multi-view.integration.test.ts +63 -0
- package/src/__tests__/lod-occlusion-device-loss.integration.test.ts +27 -0
- package/src/__tests__/lod-occlusion-final-decision.integration.test.ts +47 -0
- package/src/__tests__/lod-occlusion-inspection.integration.test.ts +217 -0
- package/src/__tests__/lod-occlusion-inspection.schema.test-d.ts +14 -0
- package/src/__tests__/lod-occlusion-inspection.unit.test.ts +72 -0
- package/src/__tests__/lod-occlusion-visual-evidence.ts +91 -0
- package/src/__tests__/lod-occlusion.browser.test.ts +15 -0
- package/src/__tests__/lod-occlusion.dawn.test.ts +20 -0
- package/src/__tests__/lod-selector.profile.test.ts +35 -0
- package/src/__tests__/lod-selector.unit.test.ts +68 -0
- package/src/__tests__/lod-visibility-identity.unit.test.ts +198 -0
- package/src/__tests__/lod-visibility-lifecycle.integration.test.ts +132 -0
- package/src/__tests__/ltc-resources.unit.test.ts +32 -0
- package/src/__tests__/material-contract-inventory.unit.test.ts +41 -9
- package/src/__tests__/material-cooked-projection.unit.test.ts +19 -1
- package/src/__tests__/material-static-dynamic-route.unit.test.ts +29 -0
- package/src/__tests__/material-stride-surface.unit.test.ts +7 -3
- package/src/__tests__/materials-standard-contract.unit.test.ts +104 -0
- package/src/__tests__/mesh-buffer-usage-surface.unit.test.ts +1 -1
- package/src/__tests__/occlusion-confidence.unit.test.ts +168 -0
- package/src/__tests__/occlusion-invalidation.integration.test.ts +37 -0
- package/src/__tests__/occlusion-pass-routing.unit.test.ts +16 -0
- package/src/__tests__/occlusion-pass.dawn.test.ts +20 -0
- package/src/__tests__/occlusion-pass.integration.test.ts +43 -0
- package/src/__tests__/occlusion-pass.rhi-null.test.ts +22 -0
- package/src/__tests__/occlusion-query-pool.rhi-null.test.ts +21 -0
- package/src/__tests__/occlusion-query-pool.unit.test.ts +95 -0
- package/src/__tests__/occlusion-query-ticket.integration.test.ts +47 -0
- package/src/__tests__/occlusion-query.dawn.test.ts +16 -0
- package/src/__tests__/occlusion-query.evidence.ts +178 -0
- package/src/__tests__/occlusion-query.rhi-null.test.ts +31 -0
- package/src/__tests__/occlusion-runtime.unit.test.ts +120 -0
- package/src/__tests__/physical-clearcoat.integration.test.ts +89 -0
- package/src/__tests__/prepared-gpu-driven-pbr.integration.test.ts +196 -0
- package/src/__tests__/prepared-graphics-pipeline-warmup.unit.test.ts +1 -1
- package/src/__tests__/probe-bindings.unit.test.ts +200 -0
- package/src/__tests__/probe-blend-numeric.unit.test.ts +67 -0
- package/src/__tests__/probe-blend-oracle.unit.test.ts +136 -0
- package/src/__tests__/probe-capacity.integration.test.ts +97 -0
- package/src/__tests__/probe-recovery.integration.test.ts +104 -0
- package/src/__tests__/probe-scene-dirty.integration.test.ts +211 -0
- package/src/__tests__/profiler-phase-catalog.test.ts +4 -1
- package/src/__tests__/profiler-phase-token.test.ts +1 -0
- package/src/__tests__/recover-error-policy-owner.unit.test.ts +6 -3
- package/src/__tests__/recovery-candidate-prepare.contract.test.ts +140 -0
- package/src/__tests__/rect-area-boundary.unit.test.ts +24 -0
- package/src/__tests__/reflection-fallback-graph.unit.test.ts +67 -0
- package/src/__tests__/reflection-fallback-inspection.unit.test.ts +77 -0
- package/src/__tests__/reflection-fallback-lifecycle.integration.test.ts +21 -0
- package/src/__tests__/reflection-fallback-projection.unit.test.ts +90 -0
- package/src/__tests__/reflection-fallback-source.unit.test.ts +32 -0
- package/src/__tests__/reflection-probe-owner-placement.unit.test.ts +39 -0
- package/src/__tests__/reflection-probe-record-owner.characterization.unit.test.ts +120 -0
- package/src/__tests__/render-error-code-owner.test-d.ts +1 -0
- package/src/__tests__/render-feature-docs.unit.test.ts +12 -7
- package/src/__tests__/render-graph-fallback.integration.test.ts +24 -0
- package/src/__tests__/render-perf/extended-lighting.bench.test.ts +66 -0
- package/src/__tests__/render-scene-projection.unit.test.ts +447 -18
- package/src/__tests__/renderer-factory-material-contract.unit.test.ts +160 -17
- package/src/__tests__/renderer-frame-generation-fence.integration.test.ts +47 -0
- package/src/__tests__/renderer-generation-assembly.unit.test.ts +77 -0
- package/src/__tests__/renderer-generation-failure.unit.test.ts +108 -0
- package/src/__tests__/renderer-producer-root-matrix.integration.test.ts +33 -0
- package/src/__tests__/renderer-recovery-capability-matrix.unit.test.ts +59 -0
- package/src/__tests__/renderer-recovery-contract.unit.test.ts +73 -0
- package/src/__tests__/renderer-recovery-lifecycle.unit.test.ts +216 -0
- package/src/__tests__/renderer-target-history-recovery.integration.test.ts +80 -0
- package/src/__tests__/shader-manifest-fixture.ts +13 -16
- package/src/__tests__/shader-stage-surface.unit.test.ts +1 -1
- package/src/__tests__/skin-motion-regression.unit.test.ts +22 -0
- package/src/__tests__/skinned-shadow-caster.test.ts +2 -2
- package/src/__tests__/spot-modifier-projection.unit.test.ts +70 -0
- package/src/__tests__/ssr-admission-matrix.integration.test.ts +206 -0
- package/src/__tests__/ssr-composition.unit.test.ts +46 -0
- package/src/__tests__/ssr-fallback-zero-work.bench.test.ts +94 -0
- package/src/__tests__/ssr-recovery-errors.unit.test.ts +58 -0
- package/src/__tests__/standard-cluster-variant-resolution.unit.test.ts +67 -0
- package/src/__tests__/standard-clustered-pipeline.unit.test.ts +7 -0
- package/src/__tests__/standard-layer-projection.unit.test.ts +23 -0
- package/src/__tests__/standard-lighting-inspection.integration.test.ts +1 -1
- package/src/__tests__/standard-lighting-write.unit.test.ts +66 -2
- package/src/__tests__/temporal-fallback-generation.integration.test.ts +16 -0
- package/src/__tests__/temporal-view.unit.test.ts +3 -3
- package/src/__tests__/transmission-prewarm.unit.test.ts +111 -32
- package/src/__tests__/visibility-budget.integration.test.ts +140 -0
- package/src/__tests__/visibility-budget.unit.test.ts +70 -0
- package/src/__tests__/visibility-extract.integration.test.ts +11 -6
- package/src/__tests__/volumetric-fog-point-spot-accumulation.integration.test.ts +6 -3
- package/src/__tests__/volumetric-fog-stage-readback.dawn.test.ts +31 -28
- package/src/__tests__/volumetric-fog-topology.unit.test.ts +3 -1
- package/src/assembly/backend-contract.ts +13 -0
- package/src/assembly/bundler-contract.ts +9 -0
- package/src/assembly/device-feature-admission.ts +26 -9
- package/src/assembly/extended-lighting-fallback.ts +216 -0
- package/src/assembly/factory.ts +81 -9634
- package/src/assembly/host-contract.ts +10 -0
- package/src/assembly/material/assembly.ts +18 -2
- package/src/assembly/material/standard-layer-projection.ts +16 -0
- package/src/assembly/material-shader-policy.ts +854 -0
- package/src/assembly/material-shader-prewarm.ts +88 -0
- package/src/assembly/mesh-ssbo-grow.ts +270 -0
- package/src/assembly/recovery/device-loss-fanout.ts +89 -0
- package/src/assembly/recovery/generation.ts +141 -0
- package/src/assembly/recovery/recovery-attempt.ts +800 -0
- package/src/assembly/recovery/renderer-recover.ts +906 -0
- package/src/assembly/renderer-facade.ts +342 -0
- package/src/assembly/renderer-frame-transaction.ts +45 -0
- package/src/assembly/renderer-helpers.ts +99 -0
- package/src/assembly/renderer-lifecycle.ts +159 -0
- package/src/assembly/shader-prewarm-policy.ts +157 -0
- package/src/assembly/webgpu-ready-contract.ts +14 -0
- package/src/assembly/webgpu-ready.ts +4079 -0
- package/src/assembly/webgpu-renderer.ts +4095 -0
- package/src/cluster-binner.ts +31 -0
- package/src/components/__tests__/lighting-authoring.unit.test.ts +39 -0
- package/src/components/__tests__/rect-area-light.unit.test.ts +33 -0
- package/src/components/camera.ts +1 -1
- package/src/components/index.ts +3 -0
- package/src/components/light-helpers.ts +52 -1
- package/src/components/light-probe.ts +13 -0
- package/src/components/rect-area-light.ts +15 -0
- package/src/components/scene-instance.ts +6 -0
- package/src/components/spot-light.ts +3 -0
- package/src/debug-draw-glue.ts +1 -1
- package/src/device/__tests__/extended-lighting-recovery.unit.test.ts +24 -0
- package/src/device/device-scope.ts +35 -6
- package/src/device/gpu-residency.ts +334 -35
- package/src/device/lifecycle-transaction.ts +12 -0
- package/src/environment/frame.ts +6 -0
- package/src/environment/inspection.ts +10 -0
- package/src/environment/lifecycle.ts +122 -9
- package/src/errors/gpu-driven.ts +92 -0
- package/src/errors/index.ts +1 -0
- package/src/errors/recover.ts +108 -5
- package/src/errors/render.ts +72 -1
- package/src/extract/camera.ts +3 -3
- package/src/extract/contracts.ts +974 -0
- package/src/extract/gpu-driven.ts +108 -0
- package/src/extract/visibility.ts +0 -23
- package/src/features/host.ts +16 -0
- package/src/features/prepared-gpu-work.ts +20 -2
- package/src/features/prepared-graphics-store.ts +17 -0
- package/src/gpu-driven/batch-topology.ts +206 -28
- package/src/gpu-driven/prepared-draw.ts +208 -0
- package/src/gpu-driven/production-raster.ts +1046 -39
- package/src/gpu-driven/view-gpu.ts +411 -29
- package/src/gpu-scene-schema.ts +13 -0
- package/src/gpu-scene.ts +137 -67
- package/src/gpu-usage.ts +0 -1
- package/src/hdrp-buffers.ts +6 -6
- package/src/ibl/IblPipelineCache.ts +134 -50
- package/src/ibl/skylight-bind-group.ts +26 -0
- package/src/index.ts +83 -1
- package/src/inspection-types.ts +220 -1
- package/src/internal.ts +38 -0
- package/src/light-buffer-layout.ts +157 -324
- package/src/materials.ts +278 -47
- package/src/mesh-material-bindings.ts +59 -0
- package/src/occlusion-proxy.ts +64 -0
- package/src/pbr-pipeline.ts +290 -60
- package/src/pipeline/standard-forward-lane.ts +47 -0
- package/src/pipeline/standard-lighting/graph.ts +2 -1
- package/src/pipeline/standard-lighting/light-frame.ts +3 -2
- package/src/pipeline/standard-lighting/topology.ts +1 -1
- package/src/pipeline/standard-lighting/transport.ts +2 -1
- package/src/pipeline/standard-pipeline.ts +2 -0
- package/src/pipeline-builder.ts +5 -2
- package/src/pipeline-spec.ts +12 -1
- package/src/plugin.ts +4 -0
- package/src/points-lines/__tests__/cache-recovery.unit.test.ts +22 -0
- package/src/points-lines/prepare.ts +9 -0
- package/src/points-lines/standard-owner.ts +403 -0
- package/src/prepare/__tests__/extended-lighting-capability.unit.test.ts +56 -0
- package/src/prepare/extended-lighting/ltc-resources.ts +136 -0
- package/src/prepare/extended-lighting/resources.ts +389 -0
- package/src/prepare/extended-lighting/spot-modifiers.ts +194 -0
- package/src/prepare/extended-lighting/state.ts +92 -0
- package/src/record/__tests__/frame-targets-recovery.unit.test.ts +60 -0
- package/src/record/__tests__/gpu-timing.unit.test.ts +177 -0
- package/src/record/__tests__/main-pass-geometry.unit.test.ts +26 -1
- package/src/record/__tests__/mesh-ssbo.unit.test.ts +38 -0
- package/src/record/__tests__/recovery-pipeline.unit.test.ts +124 -0
- package/src/record/__tests__/sprite-material-abi.unit.test.ts +28 -13
- package/src/record/__tests__/standard-pbr-ubo-layout.unit.test.ts +47 -4
- package/src/record/__tests__/temporal-payload.unit.test.ts +29 -28
- package/src/record/__tests__/typed-frame-graph-plan.unit.test.ts +21 -2
- package/src/record/frame-lighting.ts +252 -53
- package/src/record/frame-snapshot.ts +72 -12
- package/src/record/frame-targets.ts +11 -1
- package/src/record/frame.ts +416 -95
- package/src/record/gpu-timing.ts +108 -44
- package/src/record/helpers.ts +1 -59
- package/src/record/main-pass-geometry.ts +434 -44
- package/src/record/main-pass-material.ts +324 -210
- package/src/record/main-pass-sprite-draws.ts +58 -92
- package/src/record/main-pass.ts +94 -6
- package/src/record/mesh-ssbo.ts +79 -46
- package/src/record/recovery-pipeline.ts +695 -0
- package/src/record/render-context.ts +99 -7
- package/src/record/shadow-pass.ts +66 -40
- package/src/record/typed-frame-graph.ts +270 -84
- package/src/record/view-ubo.ts +17 -27
- package/src/recovery/render-system-candidate.ts +839 -0
- package/src/reflection/inspection.ts +67 -0
- package/src/reflection/projection.ts +196 -1
- package/src/reflection/record-owner.ts +1283 -0
- package/src/render-contract.ts +82 -12
- package/src/render-pipeline.ts +5 -0
- package/src/render-system-extract-tail.ts +2983 -0
- package/src/render-system-extract.ts +290 -2784
- package/src/render-system.ts +1597 -1192
- package/src/scene/__tests__/changed-block-summary.candidate.test.ts +36 -0
- package/src/scene/probe-blend-record.ts +54 -0
- package/src/scene/probe-blend.ts +813 -0
- package/src/scene/render-scene-types.ts +0 -7
- package/src/scene/render-scene.ts +972 -184
- package/src/scene/visibility/bounds.ts +57 -0
- package/src/scene/visibility/budget.ts +40 -0
- package/src/scene/visibility/facet.ts +400 -0
- package/src/scene/visibility/gpu-frame-timing.ts +101 -0
- package/src/scene/visibility/gpu-lod.ts +119 -0
- package/src/scene/visibility/inspection.ts +313 -0
- package/src/scene/visibility/lod-selector.ts +84 -0
- package/src/scene/visibility/occlusion-confidence.ts +478 -0
- package/src/scene/visibility/occlusion-pass.ts +165 -0
- package/src/scene/visibility/occlusion-query-pool.ts +178 -0
- package/src/scene/visibility/occlusion-runtime.ts +672 -0
- package/src/scene/visibility/types.ts +50 -0
- package/src/ssr/admission.ts +451 -0
- package/src/ssr/composition.ts +73 -0
- package/src/ssr/errors.ts +76 -0
- package/src/ssr/identity.ts +12 -0
- package/src/systems/skin-palette-allocator.ts +1 -1
- package/src/temporal/frame-coordinator.ts +30 -1
- package/src/temporal/frame.ts +14 -1
- package/src/temporal/taa-history-store.ts +46 -2
- package/src/temporal/temporal-view.ts +1 -1
- package/src/temporal/transaction.ts +9 -0
- package/src/temporal/view.ts +11 -0
- package/src/tilemap-chunk-extract-system.ts +5 -5
- package/src/transmission/__tests__/standard-transmission.dawn.test.ts +19 -12
- package/src/typed-render-graph-primitives.ts +48 -0
- package/src/volume/passes.ts +46 -49
- package/dist/.tsbuildinfo +0 -1
- package/dist/chunk-5YADUCA7.mjs.map +0 -1
- package/dist/chunk-6OPXDQ2E.mjs.map +0 -1
- package/dist/chunk-BXBQQKFQ.mjs +0 -67
- package/dist/chunk-BXBQQKFQ.mjs.map +0 -1
- package/dist/chunk-FS2KNUQH.mjs.map +0 -1
- package/dist/chunk-PCHBPYML.mjs.map +0 -1
- package/dist/chunk-VFPLTKCU.mjs +0 -192
- package/dist/chunk-VFPLTKCU.mjs.map +0 -1
|
@@ -0,0 +1,839 @@
|
|
|
1
|
+
import type { MipmapEncoderWork } from '@forgeax/engine-assets-runtime';
|
|
2
|
+
import { resolveAssetHandle } from '@forgeax/engine-assets-runtime';
|
|
3
|
+
import type { World } from '@forgeax/engine-ecs';
|
|
4
|
+
import {
|
|
5
|
+
type CommandBuffer,
|
|
6
|
+
err,
|
|
7
|
+
ok,
|
|
8
|
+
type RenderPipeline,
|
|
9
|
+
type Result,
|
|
10
|
+
RhiError,
|
|
11
|
+
} from '@forgeax/engine-rhi';
|
|
12
|
+
import type { Handle, MeshAsset, SamplerAsset, TextureAsset } from '@forgeax/engine-types';
|
|
13
|
+
import { toShared } from '@forgeax/engine-types';
|
|
14
|
+
import { createClusterBinScratch } from '../cluster-binner';
|
|
15
|
+
import type { EnvironmentLifecycle } from '../environment/lifecycle';
|
|
16
|
+
import {
|
|
17
|
+
getRenderFeaturePlanExecutionProjection,
|
|
18
|
+
type RenderFeatureHost,
|
|
19
|
+
type RenderFeaturePreparedGraphicsResolverInput,
|
|
20
|
+
runRenderFeatureFrame,
|
|
21
|
+
} from '../features/host';
|
|
22
|
+
import type { RenderFeatureGpuWorkOwner } from '../features/prepared-gpu-work';
|
|
23
|
+
import { resolveStandardRenderFeatureTargets } from '../features/targets';
|
|
24
|
+
import {
|
|
25
|
+
buildFullscreenPostProcessPass,
|
|
26
|
+
entryHasDepthRead,
|
|
27
|
+
type PostProcessShaderEntry,
|
|
28
|
+
postProcessShaderEntrySignature,
|
|
29
|
+
} from '../fullscreen-post-process-pass';
|
|
30
|
+
import { GpuDrivenProduction } from '../gpu-driven/production-raster';
|
|
31
|
+
import { inspectStandardLighting } from '../pipeline/standard-lighting/inspection';
|
|
32
|
+
import type { PipelineBuilderShaderModuleFactory } from '../pipeline-builder';
|
|
33
|
+
import { inspectPointShadow } from '../point-shadow-inspection';
|
|
34
|
+
import type { PreparedGraphicsResolver } from '../prepare/prepared-graphics-resolver';
|
|
35
|
+
import { validateRenderables } from '../record/frame';
|
|
36
|
+
import { prepareFrameLighting } from '../record/frame-lighting';
|
|
37
|
+
import type { RenderFrameState, ValidatedRenderable } from '../record/frame-snapshot';
|
|
38
|
+
import { computeSplitLdrSprite } from '../record/main-pass-sprite-draws';
|
|
39
|
+
import {
|
|
40
|
+
prepareRecoveryPipelineReadiness,
|
|
41
|
+
type RecoveryPipelineReadiness,
|
|
42
|
+
} from '../record/recovery-pipeline';
|
|
43
|
+
import type { PointsLinesRecordOwner, RenderSystemInternals } from '../record/render-context';
|
|
44
|
+
import {
|
|
45
|
+
ensureCompiledFrameGraph,
|
|
46
|
+
getRenderFeatureGraphState,
|
|
47
|
+
type RenderFeatureGraphCandidate,
|
|
48
|
+
} from '../record/typed-frame-graph';
|
|
49
|
+
import { STANDARD_OUTPUT_TRANSFORM_FEATURE_ID } from '../render-contract';
|
|
50
|
+
import type {
|
|
51
|
+
RecoveryGraphCandidate,
|
|
52
|
+
RecoveryGraphCandidatePreparation,
|
|
53
|
+
RecoveryGraphCandidateRuntime,
|
|
54
|
+
RecoveryGraphSetupSubmission,
|
|
55
|
+
RecoveryPointsLinesCandidate,
|
|
56
|
+
} from '../render-system';
|
|
57
|
+
import type { ExtractedFrame, MaterialSnapshot } from '../render-system-extract';
|
|
58
|
+
import type { PersistentGpuDrivenCandidate, PersistentRenderScene } from '../scene/render-scene';
|
|
59
|
+
import { SHADOW_ATLAS_DEFAULT_LAYERS } from '../shadow-atlas';
|
|
60
|
+
import { createTemporalFrameTransaction } from '../temporal/frame';
|
|
61
|
+
import {
|
|
62
|
+
getTemporalBindGroupResources,
|
|
63
|
+
getTemporalGpuState,
|
|
64
|
+
getTemporalParamsBuffer,
|
|
65
|
+
} from '../temporal/gpu';
|
|
66
|
+
|
|
67
|
+
export interface PreparedResolverCaches {
|
|
68
|
+
readonly preparedPipelineIds: WeakMap<object, string>;
|
|
69
|
+
readonly preparedMaterialPipelineShaders: WeakMap<object, string>;
|
|
70
|
+
readonly preparedGroup0Pipelines: WeakSet<object>;
|
|
71
|
+
readonly preparedViewOnlyPipelines: WeakSet<object>;
|
|
72
|
+
readonly preparedRenderMaterialPipelines: WeakSet<object>;
|
|
73
|
+
readonly preparedAssetHandles: WeakMap<World, Map<string, number>>;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export interface RecoveryFrameSeed {
|
|
77
|
+
readonly frame: ExtractedFrame;
|
|
78
|
+
readonly worlds: readonly World[];
|
|
79
|
+
readonly cameraOwner: number;
|
|
80
|
+
readonly resourceOwner: number;
|
|
81
|
+
readonly width: number;
|
|
82
|
+
readonly height: number;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export interface RenderSystemRecoveryDependencies {
|
|
86
|
+
readonly frameState: RenderFrameState;
|
|
87
|
+
readonly internals: RenderSystemInternals;
|
|
88
|
+
readonly getEnvironmentLifecycle: () => EnvironmentLifecycle;
|
|
89
|
+
readonly getGpuDrivenProduction: () => GpuDrivenProduction;
|
|
90
|
+
readonly setGpuDrivenProduction: (production: GpuDrivenProduction) => void;
|
|
91
|
+
readonly disposeFeatureGpuWork: () => void;
|
|
92
|
+
readonly setFeatureGpuWork: (owner: RenderFeatureGpuWorkOwner) => void;
|
|
93
|
+
readonly getActiveFeaturePostProcessEntries: () => ReadonlyMap<string, PostProcessShaderEntry>;
|
|
94
|
+
readonly setActiveFeaturePostProcessEntries: (
|
|
95
|
+
entries: ReadonlyMap<string, PostProcessShaderEntry>,
|
|
96
|
+
) => void;
|
|
97
|
+
readonly postProcessPipelineCache: Map<string, RenderPipeline>;
|
|
98
|
+
readonly clearPostProcessPipelineCache: (id: string) => void;
|
|
99
|
+
readonly clearPostProcessPipelineEntry: (id: string, entry: PostProcessShaderEntry) => void;
|
|
100
|
+
readonly invalidatePostProcessModule: (id: string) => void;
|
|
101
|
+
readonly persistentRenderScene: PersistentRenderScene;
|
|
102
|
+
readonly gpuDrivenShaderFactory: PipelineBuilderShaderModuleFactory;
|
|
103
|
+
readonly createFeatureGpuWorkOwner: (runtime: RenderSystemInternals) => RenderFeatureGpuWorkOwner;
|
|
104
|
+
readonly pointsLinesOwner: PointsLinesRecordOwner & {
|
|
105
|
+
prepareRecoveryCandidate: (
|
|
106
|
+
entries: readonly ValidatedRenderable[],
|
|
107
|
+
clustered: boolean,
|
|
108
|
+
runtime: RenderSystemInternals,
|
|
109
|
+
) => RecoveryPointsLinesCandidate | undefined;
|
|
110
|
+
};
|
|
111
|
+
readonly createPreparedResolverFactory: (
|
|
112
|
+
runtime: RenderSystemInternals,
|
|
113
|
+
gpuWork: RenderFeatureGpuWorkOwner,
|
|
114
|
+
worlds: readonly World[],
|
|
115
|
+
caches: PreparedResolverCaches,
|
|
116
|
+
) => (input: RenderFeaturePreparedGraphicsResolverInput) => PreparedGraphicsResolver;
|
|
117
|
+
readonly createPreparedResolverCaches: () => PreparedResolverCaches;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export interface RenderSystemRecoveryOwner {
|
|
121
|
+
setLastSuccessfulFrameSeed(seed: RecoveryFrameSeed): void;
|
|
122
|
+
prepareRecoveryGraphCandidate(
|
|
123
|
+
runtime: RecoveryGraphCandidateRuntime,
|
|
124
|
+
): RecoveryGraphCandidatePreparation;
|
|
125
|
+
submitCandidateSetup(
|
|
126
|
+
candidate: RecoveryGraphCandidate,
|
|
127
|
+
isValid: () => boolean,
|
|
128
|
+
): Result<RecoveryGraphSetupSubmission, RhiError>;
|
|
129
|
+
publishRecoveryGraphCandidate(candidate: RecoveryGraphCandidate): void;
|
|
130
|
+
discardRecoveryGraphCandidate(candidate: RecoveryGraphCandidate): void;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
export function materialTextureHandles(
|
|
134
|
+
material: MaterialSnapshot,
|
|
135
|
+
): readonly Handle<'TextureAsset', 'shared'>[] {
|
|
136
|
+
const handles = new Map<number, Handle<'TextureAsset', 'shared'>>();
|
|
137
|
+
const add = (handle: Handle<'TextureAsset', 'shared'> | undefined): void => {
|
|
138
|
+
if (handle !== undefined) handles.set(Number(handle), handle);
|
|
139
|
+
};
|
|
140
|
+
for (const handle of material.textureHandles?.values() ?? []) add(handle);
|
|
141
|
+
add(material.baseColorTexture);
|
|
142
|
+
add(material.metallicRoughnessTexture);
|
|
143
|
+
add(material.normalTexture);
|
|
144
|
+
add(material.emissiveTexture);
|
|
145
|
+
add(material.occlusionTexture);
|
|
146
|
+
return [...handles.values()];
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
export function materialSamplerHandles(
|
|
150
|
+
material: MaterialSnapshot,
|
|
151
|
+
): readonly Handle<'SamplerAsset', 'shared'>[] {
|
|
152
|
+
const handles = new Map<number, Handle<'SamplerAsset', 'shared'>>();
|
|
153
|
+
for (const handle of material.samplerHandles?.values() ?? []) {
|
|
154
|
+
handles.set(Number(handle), handle);
|
|
155
|
+
}
|
|
156
|
+
return [...handles.values()];
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
export function createRenderSystemRecovery(
|
|
160
|
+
deps: RenderSystemRecoveryDependencies,
|
|
161
|
+
): RenderSystemRecoveryOwner {
|
|
162
|
+
const {
|
|
163
|
+
frameState,
|
|
164
|
+
internals,
|
|
165
|
+
getEnvironmentLifecycle,
|
|
166
|
+
getGpuDrivenProduction,
|
|
167
|
+
setGpuDrivenProduction,
|
|
168
|
+
disposeFeatureGpuWork,
|
|
169
|
+
setFeatureGpuWork,
|
|
170
|
+
getActiveFeaturePostProcessEntries,
|
|
171
|
+
setActiveFeaturePostProcessEntries,
|
|
172
|
+
postProcessPipelineCache,
|
|
173
|
+
clearPostProcessPipelineCache,
|
|
174
|
+
clearPostProcessPipelineEntry,
|
|
175
|
+
invalidatePostProcessModule,
|
|
176
|
+
persistentRenderScene,
|
|
177
|
+
gpuDrivenShaderFactory,
|
|
178
|
+
createFeatureGpuWorkOwner,
|
|
179
|
+
pointsLinesOwner,
|
|
180
|
+
createPreparedResolverFactory,
|
|
181
|
+
createPreparedResolverCaches,
|
|
182
|
+
} = deps;
|
|
183
|
+
|
|
184
|
+
// This is a detached CPU projection, retained only after queue submission.
|
|
185
|
+
// It is not a World/lease cache and it never carries target or scheduler state.
|
|
186
|
+
let lastSuccessfulFrameSeed: RecoveryFrameSeed | undefined;
|
|
187
|
+
|
|
188
|
+
const createRecoveryCandidateFrameState = (): RenderFrameState => {
|
|
189
|
+
const { probeBlendRecordBuffer: discardedProbeBlendRecordBuffer, ...baseFrameState } =
|
|
190
|
+
frameState;
|
|
191
|
+
void discardedProbeBlendRecordBuffer;
|
|
192
|
+
return {
|
|
193
|
+
...baseFrameState,
|
|
194
|
+
successfulTemporalFrameIndex: 0,
|
|
195
|
+
temporalFrameTransaction: createTemporalFrameTransaction({ deviceEpoch: 0 }),
|
|
196
|
+
temporalFrameInput: undefined,
|
|
197
|
+
graphTargetCapture: undefined,
|
|
198
|
+
perFrameGraph: null,
|
|
199
|
+
directionalShadowCache: null,
|
|
200
|
+
directionalShadowCacheRecorded: false,
|
|
201
|
+
compiledFrameGraph: null,
|
|
202
|
+
compiledFrameGraphTopologyKey: null,
|
|
203
|
+
volumetricFogPreviousGraph: null,
|
|
204
|
+
volumetricFogPreviousGraphKey: null,
|
|
205
|
+
volumetricFogCandidateGraph: null,
|
|
206
|
+
volumetricFogParamsBuffers: [null, null],
|
|
207
|
+
volumetricFogParamsPendingSlot: null,
|
|
208
|
+
volumetricFogParamsAcceptedSlot: null,
|
|
209
|
+
volumetricFogAcceptedParams: undefined,
|
|
210
|
+
volumetricFogPendingParams: undefined,
|
|
211
|
+
volumetricFogAccepted: undefined,
|
|
212
|
+
volumetricFogAcceptedContext: undefined,
|
|
213
|
+
volumetricFogHistoryGraph: null,
|
|
214
|
+
volumetricFogHistorySlot: null,
|
|
215
|
+
volumetricFogHistorySignature: null,
|
|
216
|
+
retiredCompiledFrameGraphs: new Set(),
|
|
217
|
+
currentFrameObservationSource: undefined,
|
|
218
|
+
lastSuccessfulCameraAntialias: undefined,
|
|
219
|
+
temporalGpuState: undefined,
|
|
220
|
+
activeTemporalGpuState: undefined,
|
|
221
|
+
retiringTemporalGpuStates: new Set(),
|
|
222
|
+
lastSuccessfulTemporalView: undefined,
|
|
223
|
+
pendingTemporalCommit: { kind: 'none' },
|
|
224
|
+
environmentGeneration: undefined,
|
|
225
|
+
currentDirectionalShadowView: null,
|
|
226
|
+
currentSpotShadowView: null,
|
|
227
|
+
instanceBuffers: new Map(),
|
|
228
|
+
morphBuffers: new Map(),
|
|
229
|
+
hdrpClusterBinScratch: createClusterBinScratch(),
|
|
230
|
+
hdrpClusterGridScratch: null,
|
|
231
|
+
hdrpLightIndexListScratch: null,
|
|
232
|
+
hdrpClusterMembership: null,
|
|
233
|
+
standardLightingGraphSignature: '',
|
|
234
|
+
standardLightingInspection: undefined,
|
|
235
|
+
pointShadowInspection: undefined,
|
|
236
|
+
transientInstanceBuffers: [],
|
|
237
|
+
pointShadowAtlas: null,
|
|
238
|
+
pointShadowSnapshots: [],
|
|
239
|
+
spotShadowSnapshots: [],
|
|
240
|
+
viewBindGroupCache: new WeakMap(),
|
|
241
|
+
meshBindGroupCache: new WeakMap(),
|
|
242
|
+
materialBgPerEntity: new Map(),
|
|
243
|
+
instancesBgPerEntity: new Map(),
|
|
244
|
+
instancesBgShared: new WeakMap(),
|
|
245
|
+
materialBgShared: new Map(),
|
|
246
|
+
materialBgAssemblyCache: new Map(),
|
|
247
|
+
singletonMaterialCache: new Map(),
|
|
248
|
+
postProcessBgCache: new WeakMap(),
|
|
249
|
+
probeBlendBuffers: new Map(),
|
|
250
|
+
probeBlendRecordBufferCapacity: 0,
|
|
251
|
+
standardOncePerFrameFired: new Set(),
|
|
252
|
+
} as RenderFrameState;
|
|
253
|
+
};
|
|
254
|
+
|
|
255
|
+
const publishRecoveryGraphCandidate = (candidate: RecoveryGraphCandidate): void => {
|
|
256
|
+
candidate.recoveryReadiness.assertFirstRecoveryFrame();
|
|
257
|
+
const previousFeatureHost = internals.featureHost;
|
|
258
|
+
// The caller enters this method only after the active generation swap and
|
|
259
|
+
// after resetForRecover() has shed every lost-device owner. Replace the
|
|
260
|
+
// whole device-bound frame projection so no stale cache/map/temporal view
|
|
261
|
+
// survives publication; the candidate was already built from the CPU/LKG
|
|
262
|
+
// facts before this synchronous boundary.
|
|
263
|
+
Object.assign(frameState, candidate.frameState);
|
|
264
|
+
// EnvironmentLifecycle is published by the candidate root bundle. The
|
|
265
|
+
// candidate frame state was created before that owner switch, so bind the
|
|
266
|
+
// freshly selected lifecycle explicitly at the same boundary.
|
|
267
|
+
Object.assign(frameState, {
|
|
268
|
+
environmentLifecycle: getEnvironmentLifecycle(),
|
|
269
|
+
temporalFrame: undefined,
|
|
270
|
+
bloomFrameReceipts: undefined,
|
|
271
|
+
});
|
|
272
|
+
candidate.gpuDrivenScene?.publish();
|
|
273
|
+
if (candidate.gpuDrivenProduction !== undefined) {
|
|
274
|
+
getGpuDrivenProduction().dispose();
|
|
275
|
+
setGpuDrivenProduction(candidate.gpuDrivenProduction);
|
|
276
|
+
}
|
|
277
|
+
if (candidate.featureGpuWork !== undefined) {
|
|
278
|
+
disposeFeatureGpuWork();
|
|
279
|
+
setFeatureGpuWork(candidate.featureGpuWork);
|
|
280
|
+
}
|
|
281
|
+
if (candidate.featureHost !== undefined) {
|
|
282
|
+
const setFeatureHost = internals.setFeatureHost;
|
|
283
|
+
if (setFeatureHost !== undefined) setFeatureHost(candidate.featureHost);
|
|
284
|
+
if (previousFeatureHost !== undefined && previousFeatureHost !== candidate.featureHost) {
|
|
285
|
+
const disposed = previousFeatureHost.dispose();
|
|
286
|
+
if (!disposed.ok) internals.errorRegistry.fire(disposed.error);
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
if (candidate.featureGraphCandidate !== undefined) {
|
|
290
|
+
for (const [id, previous] of getActiveFeaturePostProcessEntries()) {
|
|
291
|
+
const next = candidate.featureGraphCandidate.fullscreenEffects.get(id);
|
|
292
|
+
if (next === undefined) {
|
|
293
|
+
clearPostProcessPipelineCache(id);
|
|
294
|
+
invalidatePostProcessModule(id);
|
|
295
|
+
} else if (
|
|
296
|
+
postProcessShaderEntrySignature(previous) !== postProcessShaderEntrySignature(next)
|
|
297
|
+
) {
|
|
298
|
+
clearPostProcessPipelineEntry(id, previous);
|
|
299
|
+
if (previous.source !== next.source) invalidatePostProcessModule(id);
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
setActiveFeaturePostProcessEntries(candidate.featureGraphCandidate.fullscreenEffects);
|
|
303
|
+
const graphState = getRenderFeatureGraphState(internals);
|
|
304
|
+
graphState.plans = candidate.featureGraphCandidate.plans;
|
|
305
|
+
graphState.fullscreenEffects = candidate.featureGraphCandidate.fullscreenEffects;
|
|
306
|
+
}
|
|
307
|
+
for (const [key, pipeline] of candidate.postProcessPipelines ?? []) {
|
|
308
|
+
postProcessPipelineCache.set(key, pipeline);
|
|
309
|
+
}
|
|
310
|
+
};
|
|
311
|
+
|
|
312
|
+
const discardRecoveryGraphCandidate = (candidate: RecoveryGraphCandidate): void => {
|
|
313
|
+
candidate.release();
|
|
314
|
+
};
|
|
315
|
+
|
|
316
|
+
const prepareRecoveryGraphCandidate = (
|
|
317
|
+
runtime: RecoveryGraphCandidateRuntime,
|
|
318
|
+
): RecoveryGraphCandidatePreparation => {
|
|
319
|
+
const seed = lastSuccessfulFrameSeed;
|
|
320
|
+
if (seed === undefined) return { kind: 'no-seed' };
|
|
321
|
+
const camera = seed.frame.cameras[0];
|
|
322
|
+
// A successful clear-only draw can have no display camera. There is no
|
|
323
|
+
// frame graph to rehydrate in that case, but the device generation is
|
|
324
|
+
// still recoverable; the next camera-bearing draw will build its graph
|
|
325
|
+
// from the current World composition.
|
|
326
|
+
if (camera === undefined) return { kind: 'no-seed' };
|
|
327
|
+
|
|
328
|
+
const candidateFrameState = createRecoveryCandidateFrameState();
|
|
329
|
+
Object.assign(candidateFrameState, {
|
|
330
|
+
temporalFrame: undefined,
|
|
331
|
+
bloomFrameReceipts: undefined,
|
|
332
|
+
});
|
|
333
|
+
const setupWorks: MipmapEncoderWork[] = [];
|
|
334
|
+
const candidateGpuStore = runtime.internals.gpuStore;
|
|
335
|
+
let candidateGpuDrivenScene: PersistentGpuDrivenCandidate | undefined;
|
|
336
|
+
let candidateGpuDrivenProduction: GpuDrivenProduction | undefined;
|
|
337
|
+
let candidateFeatureHost: RenderFeatureHost | undefined;
|
|
338
|
+
let candidateFeatureGpuWork: RenderFeatureGpuWorkOwner | undefined;
|
|
339
|
+
let candidatePointsLines: RecoveryPointsLinesCandidate | undefined;
|
|
340
|
+
let candidateFeatureGraph: RenderFeatureGraphCandidate = {
|
|
341
|
+
plans: Object.freeze([]),
|
|
342
|
+
fullscreenEffects: new Map(),
|
|
343
|
+
};
|
|
344
|
+
let candidateValidated: ValidatedRenderable[] = [];
|
|
345
|
+
let recoveryReadiness: RecoveryPipelineReadiness | undefined;
|
|
346
|
+
let preparedGpuDriven:
|
|
347
|
+
| import('../gpu-driven/production-raster').PreparedGpuDrivenFrame
|
|
348
|
+
| undefined;
|
|
349
|
+
let recoveryGraphFailure: unknown;
|
|
350
|
+
let candidatePublished = false;
|
|
351
|
+
let candidateReleased = false;
|
|
352
|
+
const releaseCandidate = (): void => {
|
|
353
|
+
if (candidateReleased || candidatePublished) return;
|
|
354
|
+
candidateReleased = true;
|
|
355
|
+
for (const work of setupWorks) work.discard();
|
|
356
|
+
setupWorks.length = 0;
|
|
357
|
+
const graph = candidateFrameState.compiledFrameGraph;
|
|
358
|
+
candidateFrameState.compiledFrameGraph = null;
|
|
359
|
+
candidateFrameState.perFrameGraph = null;
|
|
360
|
+
try {
|
|
361
|
+
graph?.retire().catch(() => undefined);
|
|
362
|
+
} catch {
|
|
363
|
+
// Candidate cleanup continues through every independent owner.
|
|
364
|
+
}
|
|
365
|
+
try {
|
|
366
|
+
candidateFrameState.pointShadowAtlas?.dispose();
|
|
367
|
+
} catch {
|
|
368
|
+
// Candidate cleanup continues through every independent owner.
|
|
369
|
+
}
|
|
370
|
+
candidateFrameState.pointShadowAtlas = null;
|
|
371
|
+
candidateFeatureGraph.onAbandoned?.();
|
|
372
|
+
const featureHost = candidateFeatureHost;
|
|
373
|
+
candidateFeatureHost = undefined;
|
|
374
|
+
if (featureHost !== undefined) {
|
|
375
|
+
featureHost.dispose();
|
|
376
|
+
}
|
|
377
|
+
candidateFeatureGpuWork?.dispose();
|
|
378
|
+
candidateFeatureGpuWork = undefined;
|
|
379
|
+
candidateGpuDrivenProduction?.dispose();
|
|
380
|
+
candidateGpuDrivenProduction = undefined;
|
|
381
|
+
candidateGpuDrivenScene?.release();
|
|
382
|
+
candidateGpuDrivenScene = undefined;
|
|
383
|
+
candidatePointsLines?.release();
|
|
384
|
+
candidatePointsLines = undefined;
|
|
385
|
+
candidateGpuStore.destroyAll();
|
|
386
|
+
};
|
|
387
|
+
const markPublished = (): void => {
|
|
388
|
+
candidatePointsLines?.publish();
|
|
389
|
+
candidatePublished = true;
|
|
390
|
+
};
|
|
391
|
+
const failed = (
|
|
392
|
+
reason: string,
|
|
393
|
+
cause: unknown = recoveryGraphFailure,
|
|
394
|
+
): RecoveryGraphCandidatePreparation => {
|
|
395
|
+
releaseCandidate();
|
|
396
|
+
return cause === undefined ? { kind: 'failed', reason } : { kind: 'failed', reason, cause };
|
|
397
|
+
};
|
|
398
|
+
|
|
399
|
+
try {
|
|
400
|
+
const gpuScene = persistentRenderScene.prepareRecoveryGpuDrivenCandidate(
|
|
401
|
+
runtime.internals.device,
|
|
402
|
+
);
|
|
403
|
+
if (!gpuScene.ok) return failed('candidate GPU scene preparation failed', gpuScene.error);
|
|
404
|
+
candidateGpuDrivenScene = gpuScene.value;
|
|
405
|
+
if (candidateGpuDrivenScene.state !== undefined) {
|
|
406
|
+
candidateGpuDrivenProduction = GpuDrivenProduction.forDevice(
|
|
407
|
+
runtime.internals.device,
|
|
408
|
+
gpuDrivenShaderFactory,
|
|
409
|
+
);
|
|
410
|
+
const prepared = candidateGpuDrivenProduction.prepare({
|
|
411
|
+
scene: candidateGpuDrivenScene.state,
|
|
412
|
+
camera,
|
|
413
|
+
meshes: runtime.pipelineState.meshes,
|
|
414
|
+
viewBindGroupLayout: runtime.pipelineState.viewBindGroupLayout,
|
|
415
|
+
meshResidencyEpoch: runtime.internals.gpuStore.meshResidencyEpoch,
|
|
416
|
+
hdrp: false,
|
|
417
|
+
});
|
|
418
|
+
if (!prepared.ok) return failed('candidate GPU-driven preparation failed', prepared.error);
|
|
419
|
+
preparedGpuDriven = prepared.value;
|
|
420
|
+
}
|
|
421
|
+
candidateFeatureHost = runtime.internals.featureHost;
|
|
422
|
+
if (candidateFeatureHost !== undefined && candidateFeatureHost.size > 0) {
|
|
423
|
+
candidateFeatureGpuWork = createFeatureGpuWorkOwner(runtime.internals);
|
|
424
|
+
const featureTargets = resolveStandardRenderFeatureTargets({
|
|
425
|
+
tonemap: camera.tonemap,
|
|
426
|
+
antialias: camera.antialias,
|
|
427
|
+
colorAttachmentFormat: runtime.pipelineState.colorAttachmentFormat,
|
|
428
|
+
storageBuffer: runtime.internals.device.caps.storageBuffer,
|
|
429
|
+
multisample: runtime.internals.device.caps.backendKind !== 'wgpu-webgl2',
|
|
430
|
+
});
|
|
431
|
+
const featureFrame = runRenderFeatureFrame(candidateFeatureHost, {
|
|
432
|
+
worlds: seed.worlds,
|
|
433
|
+
owner: seed.resourceOwner,
|
|
434
|
+
frameNumber: candidateFrameState.frameNumber,
|
|
435
|
+
visibilitySnapshots: seed.frame.featureVisibilitySnapshots,
|
|
436
|
+
hiddenEntityReports: seed.frame.hiddenEntityReports,
|
|
437
|
+
targets: featureTargets,
|
|
438
|
+
generation: runtime.internals.deviceScope.generation,
|
|
439
|
+
caps: runtime.internals.device.caps,
|
|
440
|
+
...(runtime.internals.getMaterialShaderBindingContract === undefined
|
|
441
|
+
? {}
|
|
442
|
+
: {
|
|
443
|
+
materialShaderBindingContract: runtime.internals.getMaterialShaderBindingContract,
|
|
444
|
+
}),
|
|
445
|
+
createPreparedGraphicsResolver: createPreparedResolverFactory(
|
|
446
|
+
runtime.internals,
|
|
447
|
+
candidateFeatureGpuWork,
|
|
448
|
+
seed.worlds,
|
|
449
|
+
createPreparedResolverCaches(),
|
|
450
|
+
),
|
|
451
|
+
gpuWork: candidateFeatureGpuWork,
|
|
452
|
+
});
|
|
453
|
+
if (featureFrame.errors.length > 0) {
|
|
454
|
+
return failed('candidate render-feature preparation failed');
|
|
455
|
+
}
|
|
456
|
+
const featurePreparationIncomplete = featureFrame.plans.some((planned) => {
|
|
457
|
+
const execution = getRenderFeaturePlanExecutionProjection(planned);
|
|
458
|
+
return (
|
|
459
|
+
execution === undefined ||
|
|
460
|
+
execution.passes.some(
|
|
461
|
+
(pass) =>
|
|
462
|
+
(pass.graphics !== undefined && pass.resolvedGraphics === undefined) ||
|
|
463
|
+
(pass.gpuCompute !== undefined && pass.resolvedGpuCompute === undefined),
|
|
464
|
+
)
|
|
465
|
+
);
|
|
466
|
+
});
|
|
467
|
+
if (featurePreparationIncomplete) {
|
|
468
|
+
return failed('candidate render-feature resources are not fully prepared');
|
|
469
|
+
}
|
|
470
|
+
const batches = Object.freeze([...featureFrame.preparedResourceBatches]);
|
|
471
|
+
let batchesReleased = false;
|
|
472
|
+
const releaseBatches = (): void => {
|
|
473
|
+
if (batchesReleased) return;
|
|
474
|
+
batchesReleased = true;
|
|
475
|
+
for (const batch of batches) {
|
|
476
|
+
const released = batch.release();
|
|
477
|
+
if (!released.ok) runtime.internals.errorRegistry.fire(released.error);
|
|
478
|
+
}
|
|
479
|
+
};
|
|
480
|
+
candidateFeatureGraph = {
|
|
481
|
+
plans: featureFrame.plans,
|
|
482
|
+
fullscreenEffects: featureFrame.fullscreenEffects,
|
|
483
|
+
...(batches.length === 0
|
|
484
|
+
? {}
|
|
485
|
+
: { preparedResourceKey: `recovery-${runtime.internals.deviceScope.generation}` }),
|
|
486
|
+
onRejected: releaseBatches,
|
|
487
|
+
onAbandoned: releaseBatches,
|
|
488
|
+
};
|
|
489
|
+
}
|
|
490
|
+
for (const renderable of seed.frame.renderables) {
|
|
491
|
+
const world = seed.worlds[renderable.worldId];
|
|
492
|
+
if (world === undefined) return failed(`world ${renderable.worldId} is unavailable`);
|
|
493
|
+
if (!runtime.pipelineState.meshes.has(renderable.assetHandle)) {
|
|
494
|
+
const mesh = resolveAssetHandle<MeshAsset>(
|
|
495
|
+
world,
|
|
496
|
+
toShared<'MeshAsset'>(renderable.assetHandle),
|
|
497
|
+
);
|
|
498
|
+
if (!mesh.ok) return failed(`mesh ${renderable.assetHandle} resolution failed`);
|
|
499
|
+
const preparedMesh = runtime.internals.gpuStore.prepareResidentForRecovery(
|
|
500
|
+
toShared<'MeshAsset'>(renderable.assetHandle),
|
|
501
|
+
mesh.value,
|
|
502
|
+
world,
|
|
503
|
+
);
|
|
504
|
+
if (!preparedMesh.ok) return failed(`mesh ${renderable.assetHandle} residency failed`);
|
|
505
|
+
if (preparedMesh.value.mipmapWork !== undefined) {
|
|
506
|
+
setupWorks.push(preparedMesh.value.mipmapWork);
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
for (const material of renderable.materials) {
|
|
510
|
+
for (const textureHandle of materialTextureHandles(material)) {
|
|
511
|
+
const texture = resolveAssetHandle<TextureAsset>(world, textureHandle);
|
|
512
|
+
if (!texture.ok) return failed(`texture ${textureHandle} resolution failed`);
|
|
513
|
+
const preparedTexture = runtime.internals.gpuStore.prepareResidentForRecovery(
|
|
514
|
+
textureHandle,
|
|
515
|
+
texture.value,
|
|
516
|
+
world,
|
|
517
|
+
);
|
|
518
|
+
if (!preparedTexture.ok) return failed(`texture ${textureHandle} residency failed`);
|
|
519
|
+
if (preparedTexture.value.mipmapWork !== undefined) {
|
|
520
|
+
setupWorks.push(preparedTexture.value.mipmapWork);
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
for (const samplerHandle of materialSamplerHandles(material)) {
|
|
524
|
+
const sampler = resolveAssetHandle<SamplerAsset>(world, samplerHandle);
|
|
525
|
+
if (!sampler.ok) return failed(`sampler ${samplerHandle} resolution failed`);
|
|
526
|
+
const preparedSampler = runtime.internals.gpuStore.ensureSamplerResident(
|
|
527
|
+
samplerHandle,
|
|
528
|
+
sampler.value,
|
|
529
|
+
world,
|
|
530
|
+
);
|
|
531
|
+
if (!preparedSampler.ok) return failed(`sampler ${samplerHandle} residency failed`);
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
const resourceWorld = seed.worlds[seed.resourceOwner] ?? seed.worlds[0];
|
|
536
|
+
if (resourceWorld === undefined)
|
|
537
|
+
return failed('recovery resource-owner world is unavailable');
|
|
538
|
+
const volumetricFog = seed.frame.volumetricFog;
|
|
539
|
+
if (volumetricFog?.status === 'available') {
|
|
540
|
+
const volumeWorld =
|
|
541
|
+
seed.worlds[volumetricFog.worldId ?? seed.resourceOwner] ?? resourceWorld;
|
|
542
|
+
if (volumetricFog.densityHandle === undefined || volumetricFog.densityAsset === undefined) {
|
|
543
|
+
return failed('recovery volumetric density source is unavailable');
|
|
544
|
+
}
|
|
545
|
+
const preparedDensity = candidateGpuStore.prepareResidentForRecovery(
|
|
546
|
+
volumetricFog.densityHandle,
|
|
547
|
+
volumetricFog.densityAsset,
|
|
548
|
+
volumeWorld,
|
|
549
|
+
);
|
|
550
|
+
if (!preparedDensity.ok) return failed('volumetric density residency failed');
|
|
551
|
+
if (preparedDensity.value.mipmapWork !== undefined) {
|
|
552
|
+
setupWorks.push(preparedDensity.value.mipmapWork);
|
|
553
|
+
}
|
|
554
|
+
if (
|
|
555
|
+
volumetricFog.projectorHandle !== undefined &&
|
|
556
|
+
volumetricFog.projectorAsset !== undefined
|
|
557
|
+
) {
|
|
558
|
+
const preparedProjector = candidateGpuStore.prepareResidentForRecovery(
|
|
559
|
+
volumetricFog.projectorHandle,
|
|
560
|
+
volumetricFog.projectorAsset,
|
|
561
|
+
volumeWorld,
|
|
562
|
+
);
|
|
563
|
+
if (!preparedProjector.ok) return failed('volumetric projector residency failed');
|
|
564
|
+
if (preparedProjector.value.mipmapWork !== undefined) {
|
|
565
|
+
setupWorks.push(preparedProjector.value.mipmapWork);
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
candidateValidated = validateRenderables(
|
|
570
|
+
runtime.internals,
|
|
571
|
+
resourceWorld,
|
|
572
|
+
seed.worlds,
|
|
573
|
+
runtime.pipelineState,
|
|
574
|
+
candidateFrameState,
|
|
575
|
+
seed.frame.renderables,
|
|
576
|
+
seed.frame.dispatch,
|
|
577
|
+
);
|
|
578
|
+
if (candidateValidated.length !== seed.frame.renderables.length) {
|
|
579
|
+
return failed('candidate validation did not retain every LKG-visible renderable');
|
|
580
|
+
}
|
|
581
|
+
const lighting = prepareFrameLighting(
|
|
582
|
+
runtime.internals,
|
|
583
|
+
candidateFrameState,
|
|
584
|
+
seed.frame.lights,
|
|
585
|
+
camera,
|
|
586
|
+
runtime.pipelineState,
|
|
587
|
+
);
|
|
588
|
+
if (!lighting.ok) return failed('candidate lighting preparation failed');
|
|
589
|
+
candidatePointsLines = pointsLinesOwner.prepareRecoveryCandidate(
|
|
590
|
+
candidateValidated,
|
|
591
|
+
lighting.value.standard?.kind === 'clustered',
|
|
592
|
+
runtime.internals,
|
|
593
|
+
);
|
|
594
|
+
recoveryReadiness = prepareRecoveryPipelineReadiness({
|
|
595
|
+
internals: runtime.internals,
|
|
596
|
+
pipelineState: runtime.pipelineState,
|
|
597
|
+
camera,
|
|
598
|
+
standardLighting: lighting.value.standard,
|
|
599
|
+
validated: candidateValidated,
|
|
600
|
+
dispatch: seed.frame.dispatch,
|
|
601
|
+
shadowCastersActive:
|
|
602
|
+
seed.frame.lights.pointShadow.length > 0 ||
|
|
603
|
+
seed.frame.lights.spot.some((spot) => spot.castShadow === true) ||
|
|
604
|
+
(seed.frame.lights.lightViewProj?.length ?? 0) > 0,
|
|
605
|
+
splitLdrSprite: computeSplitLdrSprite(candidateValidated, camera.tonemap !== 'none'),
|
|
606
|
+
reflectionFallbackAvailable: candidateFrameState.reflectionFallbackDemand === true,
|
|
607
|
+
});
|
|
608
|
+
const candidatePostProcessIds = new Set<string>([
|
|
609
|
+
...(candidateFrameState.installedPipelineConfig?.postEffects ?? []),
|
|
610
|
+
...candidateFeatureGraph.fullscreenEffects.keys(),
|
|
611
|
+
]);
|
|
612
|
+
const configuredPostEffects = candidateFrameState.installedPipelineConfig?.postEffects ?? [];
|
|
613
|
+
const postProcessPipeline = runtime.internals.getPostProcessPipeline;
|
|
614
|
+
const postProcessLookup = runtime.internals.lookupPostProcess;
|
|
615
|
+
if (postProcessPipeline === undefined || postProcessLookup === undefined) {
|
|
616
|
+
return failed('candidate post-process pipeline owner is unavailable');
|
|
617
|
+
}
|
|
618
|
+
const depthMultisampled =
|
|
619
|
+
camera.antialias === 'msaa' && runtime.internals.device.caps.backendKind !== 'wgpu-webgl2';
|
|
620
|
+
const warmPostProcessPipeline = (
|
|
621
|
+
id: string,
|
|
622
|
+
colorFormat: GPUTextureFormat,
|
|
623
|
+
entryOverride?: PostProcessShaderEntry,
|
|
624
|
+
): void => {
|
|
625
|
+
const entry =
|
|
626
|
+
entryOverride ?? candidateFeatureGraph.fullscreenEffects.get(id) ?? postProcessLookup(id);
|
|
627
|
+
if (entry === undefined) {
|
|
628
|
+
throw new Error(`recovery post-process declaration is unavailable: ${id}`);
|
|
629
|
+
}
|
|
630
|
+
const built = buildFullscreenPostProcessPass(
|
|
631
|
+
{ device: runtime.internals.device, errorRegistry: runtime.internals.errorRegistry },
|
|
632
|
+
entry,
|
|
633
|
+
depthMultisampled,
|
|
634
|
+
);
|
|
635
|
+
if (
|
|
636
|
+
built === null ||
|
|
637
|
+
built.sampler === null ||
|
|
638
|
+
(entryHasDepthRead(entry) && built.depthSampler === null)
|
|
639
|
+
) {
|
|
640
|
+
throw new Error(`recovery post-process bindings are unavailable: ${id}`);
|
|
641
|
+
}
|
|
642
|
+
const pipeline = postProcessPipeline(id, built.bindGroupLayout, colorFormat, entry);
|
|
643
|
+
if (pipeline === null) {
|
|
644
|
+
throw new Error(`recovery post-process pipeline is unavailable: ${id}`);
|
|
645
|
+
}
|
|
646
|
+
};
|
|
647
|
+
const rawOnlyPostInput =
|
|
648
|
+
runtime.pipelineState.surfaceProfile === 'raw-only' &&
|
|
649
|
+
runtime.internals.device.caps.storageBuffer &&
|
|
650
|
+
configuredPostEffects.length > 0;
|
|
651
|
+
const outputFormat =
|
|
652
|
+
camera.antialias === 'fxaa' || rawOnlyPostInput
|
|
653
|
+
? ('rgba16float' as GPUTextureFormat)
|
|
654
|
+
: (runtime.pipelineState.format as GPUTextureFormat);
|
|
655
|
+
// Standard's output transform is a graph pass even when no authored
|
|
656
|
+
// effect is installed. Warm its exact target format before publication;
|
|
657
|
+
// the first recovery frame must only resolve this candidate-owned cache.
|
|
658
|
+
warmPostProcessPipeline(STANDARD_OUTPUT_TRANSFORM_FEATURE_ID, outputFormat);
|
|
659
|
+
if (camera.antialias === 'taa') {
|
|
660
|
+
const temporal = getTemporalGpuState(
|
|
661
|
+
candidateFrameState,
|
|
662
|
+
runtime.internals.device,
|
|
663
|
+
runtime.internals.deviceScope,
|
|
664
|
+
seed.width,
|
|
665
|
+
seed.height,
|
|
666
|
+
);
|
|
667
|
+
getTemporalParamsBuffer(temporal);
|
|
668
|
+
const temporalBindings = getTemporalBindGroupResources(temporal);
|
|
669
|
+
const taaEntry = postProcessLookup('forgeax.taa-resolve');
|
|
670
|
+
if (taaEntry === undefined) {
|
|
671
|
+
throw new Error('recovery TAA post-process declaration is unavailable');
|
|
672
|
+
}
|
|
673
|
+
const taaPipeline = postProcessPipeline(
|
|
674
|
+
'forgeax.taa-resolve',
|
|
675
|
+
temporalBindings.layout,
|
|
676
|
+
'rgba16float',
|
|
677
|
+
taaEntry,
|
|
678
|
+
);
|
|
679
|
+
if (taaPipeline === null) {
|
|
680
|
+
throw new Error('recovery TAA pipeline is unavailable');
|
|
681
|
+
}
|
|
682
|
+
}
|
|
683
|
+
if (camera.motionBlur?.shutterAngle !== undefined && camera.motionBlur.shutterAngle > 0) {
|
|
684
|
+
warmPostProcessPipeline('forgeax.motion-blur', 'rgba16float');
|
|
685
|
+
}
|
|
686
|
+
for (const id of candidatePostProcessIds) {
|
|
687
|
+
warmPostProcessPipeline(id, runtime.pipelineState.format as GPUTextureFormat);
|
|
688
|
+
}
|
|
689
|
+
if (camera.bloom === 'on' && camera.tonemap !== 'none') {
|
|
690
|
+
runtime.pipelineState.perPassResources.ensureBloomResources?.();
|
|
691
|
+
const bloom = runtime.pipelineState.perPassResources.getBloomResources?.();
|
|
692
|
+
if (
|
|
693
|
+
bloom === null ||
|
|
694
|
+
bloom === undefined ||
|
|
695
|
+
bloom.bloomBrightPipeline === null ||
|
|
696
|
+
bloom.bloomBlurHPipeline === null ||
|
|
697
|
+
bloom.bloomBlurVPipeline === null ||
|
|
698
|
+
bloom.bloomCompositePipeline === null ||
|
|
699
|
+
bloom.bloomBrightBindGroupLayout === null ||
|
|
700
|
+
bloom.bloomBlurBindGroupLayout === null ||
|
|
701
|
+
bloom.bloomCompositeBindGroupLayout === null ||
|
|
702
|
+
bloom.bloomSampler === null ||
|
|
703
|
+
bloom.bloomBrightParamsBuffer === null ||
|
|
704
|
+
bloom.bloomBlurHParamsBuffer === null ||
|
|
705
|
+
bloom.bloomBlurVParamsBuffer === null ||
|
|
706
|
+
bloom.bloomCompositeParamsBuffer === null
|
|
707
|
+
) {
|
|
708
|
+
throw new Error('recovery Bloom resources are incomplete');
|
|
709
|
+
}
|
|
710
|
+
}
|
|
711
|
+
const graph = ensureCompiledFrameGraph(
|
|
712
|
+
runtime.internals,
|
|
713
|
+
candidateFrameState,
|
|
714
|
+
runtime.pipelineState,
|
|
715
|
+
camera,
|
|
716
|
+
seed.frame.lights,
|
|
717
|
+
seed.width,
|
|
718
|
+
seed.height,
|
|
719
|
+
undefined,
|
|
720
|
+
preparedGpuDriven,
|
|
721
|
+
candidateFeatureGraph,
|
|
722
|
+
undefined,
|
|
723
|
+
false,
|
|
724
|
+
undefined,
|
|
725
|
+
undefined,
|
|
726
|
+
seed.frame.volumetricFog,
|
|
727
|
+
seed.frame.volumetricFog?.status === 'available',
|
|
728
|
+
lighting.value.standard,
|
|
729
|
+
(error) => {
|
|
730
|
+
recoveryGraphFailure ??= error;
|
|
731
|
+
},
|
|
732
|
+
);
|
|
733
|
+
if (graph === null) return failed('candidate frame graph compilation failed');
|
|
734
|
+
if (recoveryReadiness === undefined)
|
|
735
|
+
return failed('candidate pipeline readiness was not prepared');
|
|
736
|
+
// Keep recovery inspection derived from the exact Standard declaration
|
|
737
|
+
// admitted to the candidate graph. The point-shadow projection is
|
|
738
|
+
// likewise detached from the candidate atlas and never waits for the
|
|
739
|
+
// first post-recovery frame to rediscover the retained budget.
|
|
740
|
+
candidateFrameState.standardLightingInspection = inspectStandardLighting(
|
|
741
|
+
lighting.value.standard,
|
|
742
|
+
);
|
|
743
|
+
candidateFrameState.pointShadowInspection = inspectPointShadow(
|
|
744
|
+
seed.frame.lights.pointShadow,
|
|
745
|
+
SHADOW_ATLAS_DEFAULT_LAYERS,
|
|
746
|
+
);
|
|
747
|
+
return {
|
|
748
|
+
kind: 'ready',
|
|
749
|
+
candidate: {
|
|
750
|
+
frameState: candidateFrameState,
|
|
751
|
+
setupWorks: Object.freeze(setupWorks),
|
|
752
|
+
device: runtime.internals.device,
|
|
753
|
+
generation: runtime.internals.deviceScope.generation,
|
|
754
|
+
...(candidateGpuDrivenProduction === undefined
|
|
755
|
+
? {}
|
|
756
|
+
: { gpuDrivenProduction: candidateGpuDrivenProduction }),
|
|
757
|
+
...(candidateGpuDrivenScene === undefined
|
|
758
|
+
? {}
|
|
759
|
+
: { gpuDrivenScene: candidateGpuDrivenScene }),
|
|
760
|
+
...(candidatePointsLines === undefined ? {} : { pointsLines: candidatePointsLines }),
|
|
761
|
+
...(candidateFeatureHost === undefined ? {} : { featureHost: candidateFeatureHost }),
|
|
762
|
+
...(candidateFeatureGpuWork === undefined
|
|
763
|
+
? {}
|
|
764
|
+
: { featureGpuWork: candidateFeatureGpuWork }),
|
|
765
|
+
featureGraphCandidate: candidateFeatureGraph,
|
|
766
|
+
postProcessPipelines: new Map(
|
|
767
|
+
runtime.internals.getRecoveryPostProcessPipelines?.() ?? [],
|
|
768
|
+
),
|
|
769
|
+
recoveryReadiness,
|
|
770
|
+
release: releaseCandidate,
|
|
771
|
+
markPublished,
|
|
772
|
+
},
|
|
773
|
+
};
|
|
774
|
+
} catch (cause) {
|
|
775
|
+
return failed(`candidate preparation threw: ${String(cause)}`, cause);
|
|
776
|
+
}
|
|
777
|
+
};
|
|
778
|
+
|
|
779
|
+
const submitCandidateSetup = (
|
|
780
|
+
candidate: RecoveryGraphCandidate,
|
|
781
|
+
isValid: () => boolean,
|
|
782
|
+
): Result<RecoveryGraphSetupSubmission, RhiError> => {
|
|
783
|
+
const setupFailure = (hint: string): Result<never, RhiError> =>
|
|
784
|
+
err(
|
|
785
|
+
new RhiError({
|
|
786
|
+
code: 'webgpu-runtime-error',
|
|
787
|
+
expected: 'recovery setup remains candidate-only and valid before publication',
|
|
788
|
+
hint,
|
|
789
|
+
}),
|
|
790
|
+
);
|
|
791
|
+
const discardSetupWorks = (): void => {
|
|
792
|
+
for (const work of candidate.setupWorks) work.discard();
|
|
793
|
+
};
|
|
794
|
+
try {
|
|
795
|
+
if (!isValid()) {
|
|
796
|
+
discardSetupWorks();
|
|
797
|
+
return setupFailure('discard the recovery candidate after its setup deadline or loss');
|
|
798
|
+
}
|
|
799
|
+
const commandBuffers: CommandBuffer[] = [];
|
|
800
|
+
for (const work of candidate.setupWorks) {
|
|
801
|
+
const finished = work.finish();
|
|
802
|
+
if (!finished.ok) {
|
|
803
|
+
discardSetupWorks();
|
|
804
|
+
return err(finished.error);
|
|
805
|
+
}
|
|
806
|
+
if (finished.value !== undefined) commandBuffers.push(finished.value);
|
|
807
|
+
}
|
|
808
|
+
if (!isValid()) {
|
|
809
|
+
discardSetupWorks();
|
|
810
|
+
return setupFailure('discard the recovery candidate after mip setup became stale');
|
|
811
|
+
}
|
|
812
|
+
if (commandBuffers.length === 0) return ok({});
|
|
813
|
+
const submitted = candidate.device.queue.submit(commandBuffers);
|
|
814
|
+
if (!submitted.ok) {
|
|
815
|
+
discardSetupWorks();
|
|
816
|
+
return err(submitted.error);
|
|
817
|
+
}
|
|
818
|
+
if (!isValid()) {
|
|
819
|
+
discardSetupWorks();
|
|
820
|
+
return setupFailure('discard the recovery candidate after setup submission became stale');
|
|
821
|
+
}
|
|
822
|
+
return ok({ completion: candidate.device.queue.onSubmittedWorkDone() });
|
|
823
|
+
} catch (cause) {
|
|
824
|
+
discardSetupWorks();
|
|
825
|
+
if (cause instanceof RhiError) return err(cause);
|
|
826
|
+
return setupFailure(`recovery setup submission raised: ${String(cause)}`);
|
|
827
|
+
}
|
|
828
|
+
};
|
|
829
|
+
|
|
830
|
+
return {
|
|
831
|
+
setLastSuccessfulFrameSeed(seed: RecoveryFrameSeed): void {
|
|
832
|
+
lastSuccessfulFrameSeed = seed;
|
|
833
|
+
},
|
|
834
|
+
prepareRecoveryGraphCandidate,
|
|
835
|
+
submitCandidateSetup,
|
|
836
|
+
publishRecoveryGraphCandidate,
|
|
837
|
+
discardRecoveryGraphCandidate,
|
|
838
|
+
};
|
|
839
|
+
}
|