@forgeax/engine-render 0.1.28 → 0.1.29
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 +627 -124
- package/dist/assembly/atmosphere-shader-prewarm.d.ts +6 -0
- package/dist/assembly/atmosphere-shader-prewarm.d.ts.map +1 -0
- package/dist/assembly/dynamic-geometry-host.d.ts +21 -0
- package/dist/assembly/dynamic-geometry-host.d.ts.map +1 -1
- package/dist/assembly/dynamic-geometry-runtime.d.ts +20 -0
- package/dist/assembly/dynamic-geometry-runtime.d.ts.map +1 -0
- package/dist/assembly/factory.d.ts +3 -1
- package/dist/assembly/factory.d.ts.map +1 -1
- package/dist/assembly/gpu-driven-owner.d.ts +10 -0
- package/dist/assembly/gpu-driven-owner.d.ts.map +1 -0
- package/dist/assembly/host-contract.d.ts +8 -0
- package/dist/assembly/host-contract.d.ts.map +1 -1
- package/dist/assembly/material/assembly.d.ts +7 -0
- package/dist/assembly/material/assembly.d.ts.map +1 -1
- package/dist/assembly/material-shader-policy.d.ts +3 -1
- package/dist/assembly/material-shader-policy.d.ts.map +1 -1
- package/dist/assembly/recovery/failure-location.d.ts +12 -0
- package/dist/assembly/recovery/failure-location.d.ts.map +1 -0
- package/dist/assembly/recovery/renderer-recover.d.ts +6 -4
- package/dist/assembly/recovery/renderer-recover.d.ts.map +1 -1
- package/dist/assembly/renderer-facade.d.ts.map +1 -1
- package/dist/assembly/renderer-feature-inspection.d.ts +5 -0
- package/dist/assembly/renderer-feature-inspection.d.ts.map +1 -0
- package/dist/assembly/renderer-frame-transaction.d.ts +19 -0
- package/dist/assembly/renderer-frame-transaction.d.ts.map +1 -1
- package/dist/assembly/renderer-helpers.d.ts +3 -0
- package/dist/assembly/renderer-helpers.d.ts.map +1 -1
- package/dist/assembly/renderer-inspection.d.ts +4 -0
- package/dist/assembly/renderer-inspection.d.ts.map +1 -1
- package/dist/assembly/shader-prewarm-policy.d.ts +6 -0
- package/dist/assembly/shader-prewarm-policy.d.ts.map +1 -1
- package/dist/assembly/skin-palette-owner.d.ts +8 -0
- package/dist/assembly/skin-palette-owner.d.ts.map +1 -0
- package/dist/assembly/ssr-shader-prewarm.d.ts +6 -0
- package/dist/assembly/ssr-shader-prewarm.d.ts.map +1 -0
- package/dist/assembly/webgpu-device-loss.d.ts +15 -0
- package/dist/assembly/webgpu-device-loss.d.ts.map +1 -0
- package/dist/assembly/webgpu-pbr-ready.d.ts +38 -0
- package/dist/assembly/webgpu-pbr-ready.d.ts.map +1 -0
- package/dist/assembly/webgpu-ready-mipmap.d.ts +11 -0
- package/dist/assembly/webgpu-ready-mipmap.d.ts.map +1 -0
- package/dist/assembly/webgpu-ready.d.ts +7 -3
- package/dist/assembly/webgpu-ready.d.ts.map +1 -1
- package/dist/assembly/webgpu-renderer-bootstrap.d.ts +10 -0
- package/dist/assembly/webgpu-renderer-bootstrap.d.ts.map +1 -0
- package/dist/assembly/webgpu-renderer-contract.d.ts +62 -0
- package/dist/assembly/webgpu-renderer-contract.d.ts.map +1 -0
- package/dist/assembly/webgpu-renderer-guards.d.ts +9 -0
- package/dist/assembly/webgpu-renderer-guards.d.ts.map +1 -0
- package/dist/assembly/webgpu-renderer-observation.d.ts +6 -0
- package/dist/assembly/webgpu-renderer-observation.d.ts.map +1 -0
- package/dist/assembly/webgpu-renderer-recovery-failure.d.ts +12 -0
- package/dist/assembly/webgpu-renderer-recovery-failure.d.ts.map +1 -0
- package/dist/assembly/webgpu-renderer.d.ts +7 -141
- package/dist/assembly/webgpu-renderer.d.ts.map +1 -1
- package/dist/assembly/webgpu-vertex-layouts.d.ts +28 -84
- package/dist/assembly/webgpu-vertex-layouts.d.ts.map +1 -1
- package/dist/authoring.mjs +2 -2
- package/dist/{chunk-JAASCMXA.mjs → chunk-33XZFTQU.mjs} +245 -39
- package/dist/chunk-33XZFTQU.mjs.map +1 -0
- package/dist/{chunk-GF523LHF.mjs → chunk-BLXGONR2.mjs} +30 -12
- package/dist/chunk-BLXGONR2.mjs.map +1 -0
- package/dist/{chunk-J52NMQKR.mjs → chunk-BQVQOQJH.mjs} +1086 -838
- package/dist/chunk-BQVQOQJH.mjs.map +1 -0
- package/dist/{chunk-IQMKJLNU.mjs → chunk-BTWH7BP4.mjs} +386 -17
- package/dist/chunk-BTWH7BP4.mjs.map +1 -0
- package/dist/{chunk-MBU4ZVE7.mjs → chunk-FUODTTIA.mjs} +3921 -671
- package/dist/chunk-FUODTTIA.mjs.map +1 -0
- package/dist/{chunk-MYJ5RPJO.mjs → chunk-JQTSEI3Z.mjs} +3 -3
- package/dist/{chunk-MYJ5RPJO.mjs.map → chunk-JQTSEI3Z.mjs.map} +1 -1
- package/dist/{chunk-GE3SDD72.mjs → chunk-NICXSHAT.mjs} +16 -38
- package/dist/chunk-NICXSHAT.mjs.map +1 -0
- package/dist/{chunk-J6KACNOH.mjs → chunk-NRNXBLIJ.mjs} +577 -7
- package/dist/chunk-NRNXBLIJ.mjs.map +1 -0
- package/dist/{chunk-RBDBZ5R7.mjs → chunk-PA5DRJNI.mjs} +2 -2
- package/dist/chunk-PA5DRJNI.mjs.map +1 -0
- package/dist/{chunk-VSL23LZE.mjs → chunk-S4DNKQYQ.mjs} +1117 -445
- package/dist/chunk-S4DNKQYQ.mjs.map +1 -0
- package/dist/components/camera.d.ts +62 -2
- package/dist/components/camera.d.ts.map +1 -1
- package/dist/components/index.d.ts +1 -0
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/instances.d.ts +6 -20
- package/dist/components/instances.d.ts.map +1 -1
- package/dist/components/scene-instance.d.ts +2 -1
- package/dist/components/scene-instance.d.ts.map +1 -1
- package/dist/components/screen-space-reflection.d.ts +14 -0
- package/dist/components/screen-space-reflection.d.ts.map +1 -0
- package/dist/construct-renderer.mjs +12888 -7025
- package/dist/construct-renderer.mjs.map +1 -1
- package/dist/device/gpu-residency.d.ts +1 -12
- package/dist/device/gpu-residency.d.ts.map +1 -1
- package/dist/environment/background.d.ts +6 -0
- package/dist/environment/background.d.ts.map +1 -0
- package/dist/errors/gpu-driven.d.ts +6 -3
- package/dist/errors/gpu-driven.d.ts.map +1 -1
- package/dist/errors/render.d.ts +7 -4
- package/dist/errors/render.d.ts.map +1 -1
- package/dist/extract/camera.d.ts.map +1 -1
- package/dist/extract/gpu-driven.d.ts +33 -3
- package/dist/extract/gpu-driven.d.ts.map +1 -1
- package/dist/features/host.d.ts +23 -1
- package/dist/features/host.d.ts.map +1 -1
- package/dist/features/noise-texture.d.ts +17 -0
- package/dist/features/noise-texture.d.ts.map +1 -0
- package/dist/features/plan.d.ts +83 -2
- package/dist/features/plan.d.ts.map +1 -1
- package/dist/features/prepared-gpu-work.d.ts +37 -4
- package/dist/features/prepared-gpu-work.d.ts.map +1 -1
- package/dist/features/prepared-graphics-store.d.ts.map +1 -1
- package/dist/features/prepared-graphics.d.ts +5 -0
- package/dist/features/prepared-graphics.d.ts.map +1 -1
- package/dist/features/render-graph-compute.d.ts +5 -3
- package/dist/features/render-graph-compute.d.ts.map +1 -1
- package/dist/features/render-graph-contribution.d.ts +11 -3
- package/dist/features/render-graph-contribution.d.ts.map +1 -1
- package/dist/features/render-graph-raster.d.ts +19 -3
- package/dist/features/render-graph-raster.d.ts.map +1 -1
- package/dist/features/types.d.ts +11 -0
- package/dist/features/types.d.ts.map +1 -1
- package/dist/fullscreen-post-process-pass.d.ts +2 -0
- package/dist/fullscreen-post-process-pass.d.ts.map +1 -1
- package/dist/gpu-driven/batch-topology.d.ts +34 -1
- package/dist/gpu-driven/batch-topology.d.ts.map +1 -1
- package/dist/gpu-driven/pbr-program.d.ts +10 -0
- package/dist/gpu-driven/pbr-program.d.ts.map +1 -0
- package/dist/gpu-driven/prepared-draw.d.ts.map +1 -1
- package/dist/gpu-driven/production-raster.d.ts +144 -23
- package/dist/gpu-driven/production-raster.d.ts.map +1 -1
- package/dist/gpu-driven/shadow-views.d.ts +126 -0
- package/dist/gpu-driven/shadow-views.d.ts.map +1 -0
- package/dist/gpu-driven/view-gpu.d.ts +18 -2
- package/dist/gpu-driven/view-gpu.d.ts.map +1 -1
- package/dist/gpu-scene-schema.d.ts +2 -8
- package/dist/gpu-scene-schema.d.ts.map +1 -1
- package/dist/gpu-scene.d.ts +14 -0
- package/dist/gpu-scene.d.ts.map +1 -1
- package/dist/gpu-texture-usage.d.ts +1 -0
- package/dist/gpu-texture-usage.d.ts.map +1 -1
- package/dist/hdrp-buffers.d.ts +6 -0
- package/dist/hdrp-buffers.d.ts.map +1 -1
- package/dist/ibl/frame-resources.d.ts +8 -0
- package/dist/ibl/frame-resources.d.ts.map +1 -0
- package/dist/ibl/skylight-bind-group.d.ts.map +1 -1
- package/dist/index.d.ts +18 -8
- package/dist/index.d.ts.map +1 -1
- package/dist/index.mjs +8 -8
- package/dist/inspection-types.d.ts +164 -0
- package/dist/inspection-types.d.ts.map +1 -1
- package/dist/instances-derived-bounds.d.ts +11 -0
- package/dist/instances-derived-bounds.d.ts.map +1 -1
- package/dist/instances.d.ts +89 -44
- package/dist/instances.d.ts.map +1 -1
- package/dist/internal.d.ts +3 -0
- package/dist/internal.d.ts.map +1 -1
- package/dist/internal.mjs +117 -9
- package/dist/internal.mjs.map +1 -1
- package/dist/lifecycle.d.ts +2 -1
- package/dist/lifecycle.d.ts.map +1 -1
- package/dist/material-row.d.ts +5 -0
- package/dist/material-row.d.ts.map +1 -0
- package/dist/materials.d.ts +15 -0
- package/dist/materials.d.ts.map +1 -1
- package/dist/pbr-pipeline.d.ts +21 -5
- package/dist/pbr-pipeline.d.ts.map +1 -1
- package/dist/pipeline/standard-forward-lane.d.ts.map +1 -1
- package/dist/pipeline/standard-output/auto-exposure/capability.d.ts +12 -0
- package/dist/pipeline/standard-output/auto-exposure/capability.d.ts.map +1 -0
- package/dist/pipeline/standard-output/auto-exposure/gpu.d.ts +70 -0
- package/dist/pipeline/standard-output/auto-exposure/gpu.d.ts.map +1 -0
- package/dist/pipeline/standard-output/auto-exposure/graph.d.ts +75 -0
- package/dist/pipeline/standard-output/auto-exposure/graph.d.ts.map +1 -0
- package/dist/pipeline/standard-output/auto-exposure/inspection.d.ts +111 -0
- package/dist/pipeline/standard-output/auto-exposure/inspection.d.ts.map +1 -0
- package/dist/pipeline/standard-output/auto-exposure/oracle.d.ts +16 -0
- package/dist/pipeline/standard-output/auto-exposure/oracle.d.ts.map +1 -0
- package/dist/pipeline/standard-output/auto-exposure/preset.d.ts +14 -0
- package/dist/pipeline/standard-output/auto-exposure/preset.d.ts.map +1 -0
- package/dist/pipeline/standard-output/auto-exposure/state.d.ts +46 -0
- package/dist/pipeline/standard-output/auto-exposure/state.d.ts.map +1 -0
- package/dist/pipeline/standard-output/color-transform.d.ts +27 -0
- package/dist/pipeline/standard-output/color-transform.d.ts.map +1 -0
- package/dist/pipeline/standard-output/graph.d.ts +15 -0
- package/dist/pipeline/standard-output/graph.d.ts.map +1 -0
- package/dist/pipeline/standard-output/lut-admission.d.ts +29 -0
- package/dist/pipeline/standard-output/lut-admission.d.ts.map +1 -0
- package/dist/pipeline/standard-output/lut-gpu.d.ts +48 -0
- package/dist/pipeline/standard-output/lut-gpu.d.ts.map +1 -0
- package/dist/pipeline/standard-output/lut-state.d.ts +68 -0
- package/dist/pipeline/standard-output/lut-state.d.ts.map +1 -0
- package/dist/pipeline/standard-output/resources.d.ts +10 -0
- package/dist/pipeline/standard-output/resources.d.ts.map +1 -0
- package/dist/pipeline/standard-output/types.d.ts +39 -0
- package/dist/pipeline/standard-output/types.d.ts.map +1 -0
- package/dist/pipeline/standard-pipeline.d.ts.map +1 -1
- package/dist/pipeline/standard-post.d.ts +2 -2
- package/dist/pipeline/standard-post.d.ts.map +1 -1
- package/dist/pipeline-builder.d.ts +2 -1
- package/dist/pipeline-builder.d.ts.map +1 -1
- package/dist/pipeline-spec-types.d.ts +4 -0
- package/dist/pipeline-spec-types.d.ts.map +1 -1
- package/dist/pipeline-spec.d.ts +1 -9
- package/dist/pipeline-spec.d.ts.map +1 -1
- package/dist/points-lines/standard-owner.d.ts +1 -1
- package/dist/points-lines/standard-owner.d.ts.map +1 -1
- package/dist/prepare/prepared-graphics-resolver.d.ts +6 -1
- package/dist/prepare/prepared-graphics-resolver.d.ts.map +1 -1
- package/dist/record/dynamic-geometry-consumption.d.ts +15 -0
- package/dist/record/dynamic-geometry-consumption.d.ts.map +1 -0
- package/dist/record/frame-lighting.d.ts +3 -3
- package/dist/record/frame-lighting.d.ts.map +1 -1
- package/dist/record/frame-snapshot.d.ts +106 -5
- 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 +39 -4
- package/dist/record/frame.d.ts.map +1 -1
- package/dist/record/main-pass-geometry.d.ts +7 -8
- package/dist/record/main-pass-geometry.d.ts.map +1 -1
- package/dist/record/main-pass-material.d.ts +38 -1
- package/dist/record/main-pass-material.d.ts.map +1 -1
- package/dist/record/main-pass-sprite-draws.d.ts +2 -10
- package/dist/record/main-pass-sprite-draws.d.ts.map +1 -1
- package/dist/record/main-pass.d.ts +12 -2
- package/dist/record/main-pass.d.ts.map +1 -1
- package/dist/record/mesh-ssbo.d.ts +15 -6
- package/dist/record/mesh-ssbo.d.ts.map +1 -1
- package/dist/record/prepared-material-bindings.d.ts +19 -0
- package/dist/record/prepared-material-bindings.d.ts.map +1 -0
- package/dist/record/recovery-pipeline.d.ts +2 -9
- package/dist/record/recovery-pipeline.d.ts.map +1 -1
- package/dist/record/render-context.d.ts +74 -26
- package/dist/record/render-context.d.ts.map +1 -1
- package/dist/record/shadow-pass.d.ts +62 -7
- package/dist/record/shadow-pass.d.ts.map +1 -1
- package/dist/record/skybox-post-pass.d.ts +1 -1
- package/dist/record/skybox-post-pass.d.ts.map +1 -1
- package/dist/record/typed-frame-graph.d.ts +35 -7
- package/dist/record/typed-frame-graph.d.ts.map +1 -1
- package/dist/record/view-ubo.d.ts +1 -0
- package/dist/record/view-ubo.d.ts.map +1 -1
- package/dist/recovery/render-system-candidate.d.ts +10 -2
- package/dist/recovery/render-system-candidate.d.ts.map +1 -1
- package/dist/recovery/render-system-roots.d.ts +11 -0
- package/dist/recovery/render-system-roots.d.ts.map +1 -0
- package/dist/recovery/types.d.ts +76 -0
- package/dist/recovery/types.d.ts.map +1 -0
- package/dist/reflection/record-owner.d.ts +0 -2
- package/dist/reflection/record-owner.d.ts.map +1 -1
- package/dist/render-contract.d.ts +173 -30
- package/dist/render-contract.d.ts.map +1 -1
- package/dist/render-graph-primitives.d.ts +1 -0
- package/dist/render-graph-primitives.d.ts.map +1 -1
- package/dist/render-pipeline.d.ts +64 -5
- package/dist/render-pipeline.d.ts.map +1 -1
- package/dist/render-system-extract-tail.d.ts +7 -5
- package/dist/render-system-extract-tail.d.ts.map +1 -1
- package/dist/render-system-extract.d.ts +101 -41
- package/dist/render-system-extract.d.ts.map +1 -1
- package/dist/render-system-projections.d.ts +22 -0
- package/dist/render-system-projections.d.ts.map +1 -0
- package/dist/render-system.d.ts +27 -77
- package/dist/render-system.d.ts.map +1 -1
- package/dist/scene/render-scene-types.d.ts +14 -7
- package/dist/scene/render-scene-types.d.ts.map +1 -1
- package/dist/scene/render-scene.d.ts +29 -11
- package/dist/scene/render-scene.d.ts.map +1 -1
- package/dist/scene/shadow-visibility.d.ts +5 -0
- package/dist/scene/shadow-visibility.d.ts.map +1 -0
- package/dist/ssr/admission.d.ts +70 -1
- package/dist/ssr/admission.d.ts.map +1 -1
- package/dist/ssr/compose.d.ts +13 -0
- package/dist/ssr/compose.d.ts.map +1 -0
- package/dist/ssr/errors.d.ts +35 -0
- package/dist/ssr/errors.d.ts.map +1 -1
- package/dist/ssr/graph.d.ts +60 -0
- package/dist/ssr/graph.d.ts.map +1 -0
- package/dist/ssr/history.d.ts +97 -0
- package/dist/ssr/history.d.ts.map +1 -0
- package/dist/ssr/hiz.d.ts +37 -0
- package/dist/ssr/hiz.d.ts.map +1 -0
- package/dist/ssr/inspection.d.ts +42 -0
- package/dist/ssr/inspection.d.ts.map +1 -0
- package/dist/ssr/resources.d.ts +58 -0
- package/dist/ssr/resources.d.ts.map +1 -0
- package/dist/ssr/temporal.d.ts +38 -0
- package/dist/ssr/temporal.d.ts.map +1 -0
- package/dist/systems/skin-palette-allocator.d.ts +32 -10
- package/dist/systems/skin-palette-allocator.d.ts.map +1 -1
- package/dist/systems/skin-palette-types.d.ts +15 -0
- package/dist/systems/skin-palette-types.d.ts.map +1 -1
- package/dist/systems/transparent-dispatch.d.ts +9 -0
- package/dist/systems/transparent-dispatch.d.ts.map +1 -0
- package/dist/targets/material-source.d.ts +7 -0
- package/dist/targets/material-source.d.ts.map +1 -1
- package/dist/temporal/frame-coordinator.d.ts +7 -0
- package/dist/temporal/frame-coordinator.d.ts.map +1 -1
- package/dist/temporal/gpu.d.ts +8 -0
- package/dist/temporal/gpu.d.ts.map +1 -1
- package/dist/temporal/history.d.ts.map +1 -1
- package/dist/temporal/index.mjs +6 -6
- package/dist/temporal/inspection.d.ts.map +1 -1
- package/dist/temporal/standard-scene-data.d.ts +2 -1
- package/dist/temporal/standard-scene-data.d.ts.map +1 -1
- package/dist/temporal/temporal-view.d.ts +2 -0
- package/dist/temporal/temporal-view.d.ts.map +1 -1
- package/dist/typed-render-graph-primitives.d.ts +35 -1
- package/dist/typed-render-graph-primitives.d.ts.map +1 -1
- package/dist/typed-shadow-passes.d.ts +3 -1
- package/dist/typed-shadow-passes.d.ts.map +1 -1
- package/dist/volume/temporal.d.ts +6 -0
- package/dist/volume/temporal.d.ts.map +1 -1
- package/package.json +21 -20
- package/src/__tests__/auto-exposure-gpu-evidence.ts +291 -0
- package/src/__tests__/auto-exposure-inspection.unit.test.ts +80 -0
- package/src/__tests__/auto-exposure-transaction.integration.test.ts +99 -0
- package/src/__tests__/auto-exposure.browser.test.ts +33 -0
- package/src/__tests__/auto-exposure.dawn.test.ts +33 -0
- package/src/__tests__/detached-inspection.integration.test.ts +5 -0
- package/src/__tests__/device-scope-lifecycle.unit.test.ts +18 -0
- package/src/__tests__/device-scope-stale-matrix.unit.test.ts +18 -0
- package/src/__tests__/docs-gate-green.unit.test.ts +3 -3
- package/src/__tests__/factory-contract.integration.test.ts +67 -8
- package/src/__tests__/fallback-row-stride-surface.unit.test.ts +19 -0
- package/src/__tests__/feature-depth-input.dawn.test.ts +121 -0
- package/src/__tests__/feature-noise.unit.test.ts +38 -0
- package/src/__tests__/fixtures/taa-resolve-pinned-baseline.wgsl +301 -0
- package/src/__tests__/frame-camera-selection.unit.test.ts +131 -0
- package/src/__tests__/frame-plan-contract.unit.test.ts +24 -0
- package/src/__tests__/frame-targets.unit.test.ts +24 -0
- package/src/__tests__/fullscreen-feature-plan.unit.test.ts +3 -0
- package/src/__tests__/gpu-driven-baseline.characterization.test.ts +79 -0
- package/src/__tests__/gpu-driven-batch-topology-pbr.unit.test.ts +287 -6
- package/src/__tests__/gpu-driven-indirect-raster-evidence.ts +122 -142
- package/src/__tests__/gpu-driven-indirect-raster.browser.test.ts +10 -1
- package/src/__tests__/gpu-driven-lod-cache.unit.test.ts +264 -0
- package/src/__tests__/gpu-driven-mesh-world-identity.unit.test.ts +349 -0
- package/src/__tests__/gpu-driven-pbr.dawn.test.ts +1417 -0
- package/src/__tests__/gpu-driven-pbr.integration.test.ts +21 -0
- package/src/__tests__/gpu-driven-production-fixture.ts +96 -0
- package/src/__tests__/gpu-driven-production.integration.test.ts +1075 -93
- package/src/__tests__/gpu-driven-scaling.unit.test.ts +1 -3
- package/src/__tests__/gpu-driven-shadow-views.browser.test.ts +63 -0
- package/src/__tests__/gpu-driven-shadow-views.dawn.test.ts +294 -0
- package/src/__tests__/gpu-driven-shadow-views.integration.test.ts +97 -0
- package/src/__tests__/gpu-driven-shadow-views.unit.test.ts +168 -0
- package/src/__tests__/gpu-driven-skin-contract.test-d.ts +11 -0
- package/src/__tests__/gpu-driven-view-gpu-evidence.ts +72 -20
- package/src/__tests__/gpu-driven-view-graph.integration.test.ts +30 -9
- package/src/__tests__/gpu-driven-view.unit.test.ts +159 -52
- package/src/__tests__/gpu-pass-timing.browser.test.ts +6 -1
- package/src/__tests__/gpu-resource-store-stride.unit.test.ts +42 -0
- package/src/__tests__/gpu-scene-render-graph-gpu.ts +19 -5
- package/src/__tests__/gpu-scene.dawn.test.ts +40 -13
- package/src/__tests__/gpu-scene.unit.test.ts +559 -33
- package/src/__tests__/instances-culling.integration.test.ts +36 -10
- package/src/__tests__/instances-derived-bounds.unit.test.ts +54 -0
- package/src/__tests__/instances-store.unit.test.ts +242 -39
- package/src/__tests__/ktx2-basis-gpu-consumer.dawn.test.ts +6 -0
- package/src/__tests__/lighting-scene-roundtrip.integration.test.ts +13 -16
- package/src/__tests__/lut-lkg-transaction.integration.test.ts +122 -0
- package/src/__tests__/material-contract-inventory.unit.test.ts +5 -6
- package/src/__tests__/material-dispatch-shader-id.unit.test.ts +51 -0
- package/src/__tests__/material-lane-selection.unit.test.ts +60 -0
- package/src/__tests__/material-numeric-upload.unit.test.ts +53 -0
- package/src/__tests__/material-texture-handles.unit.test.ts +18 -0
- package/src/__tests__/material-texture-source.unit.test.ts +87 -0
- package/src/__tests__/materials-authoring-validation.unit.test.ts +41 -0
- package/src/__tests__/materials-standard-contract.unit.test.ts +52 -2
- package/src/__tests__/mesh-buffer-usage-surface.unit.test.ts +4 -0
- package/src/__tests__/normal-fallback.dawn.test.ts +122 -0
- package/src/__tests__/particle-material-input-layout.unit.test.ts +104 -0
- package/src/__tests__/physical-clearcoat.integration.test.ts +37 -3
- package/src/__tests__/pipeline-texture-specialization.unit.test.ts +138 -0
- package/src/__tests__/point-shadow-inspection.unit.test.ts +2 -0
- package/src/__tests__/prepared-gpu-driven-pbr-contract.test-d.ts +31 -0
- package/src/__tests__/prepared-gpu-driven-pbr-contract.unit.test.ts +39 -0
- package/src/__tests__/prepared-gpu-driven-pbr.integration.test.ts +35 -4
- package/src/__tests__/prepared-graphics-capability.unit.test.ts +21 -0
- package/src/__tests__/prepared-graphics-pipeline-warmup.unit.test.ts +6 -2
- package/src/__tests__/profiler-phase-catalog.test.ts +5 -0
- package/src/__tests__/public-surface.test-d.ts +3 -0
- package/src/__tests__/recovery-candidate-prepare.contract.test.ts +30 -12
- package/src/__tests__/reflection-fallback-async-publication.unit.test.ts +104 -0
- package/src/__tests__/reflection-probe-record-owner.characterization.unit.test.ts +2 -1
- package/src/__tests__/render-error-code-owner.test-d.ts +4 -0
- package/src/__tests__/render-error-detail-ssot.test-d.ts +22 -0
- package/src/__tests__/render-error-exhaustive.test-d.ts +15 -0
- package/src/__tests__/render-feature-gpu-work.integration.test.ts +285 -2
- package/src/__tests__/render-feature-plan.unit.test.ts +245 -0
- package/src/__tests__/render-feature-shadow-order.unit.test.ts +228 -0
- package/src/__tests__/render-feature-zero-work.unit.test.ts +35 -1
- package/src/__tests__/render-graph-fallback.integration.test.ts +2 -2
- package/src/__tests__/render-owner-cohesion.unit.test.ts +55 -0
- package/src/__tests__/render-scene-mixed-updates.integration.test.ts +426 -0
- package/src/__tests__/render-scene-projection.unit.test.ts +914 -23
- package/src/__tests__/render-scene-resource-updates.integration.test.ts +214 -0
- package/src/__tests__/render-scene-skin-lifecycle.integration.test.ts +173 -0
- package/src/__tests__/render-scene-temporal-retry.unit.test.ts +133 -0
- package/src/__tests__/render-target-material-source.test-d.ts +27 -3
- package/src/__tests__/renderer-factory-material-contract.unit.test.ts +60 -0
- package/src/__tests__/renderer-frame-transaction.integration.test.ts +923 -5
- package/src/__tests__/shader-manifest-fixture.ts +39 -0
- package/src/__tests__/skin-motion-regression.unit.test.ts +0 -33
- package/src/__tests__/skin-palette-persistent.integration.test.ts +28 -0
- package/src/__tests__/skin-palette-persistent.unit.test.ts +247 -0
- package/src/__tests__/skinned-shadow-caster.test.ts +118 -14
- package/src/__tests__/specular-environment-scale.dawn.test.ts +156 -0
- package/src/__tests__/ssr-admission-matrix.integration.test.ts +7 -1
- package/src/__tests__/ssr-confidence-compose.unit.test.ts +84 -0
- package/src/__tests__/ssr-coordinate-oracle.unit.test.ts +28 -0
- package/src/__tests__/ssr-format-probe-gating.integration.test.ts +82 -0
- package/src/__tests__/ssr-gpu-dispatch.browser.test.ts +91 -0
- package/src/__tests__/ssr-gpu-dispatch.dawn.test.ts +112 -0
- package/src/__tests__/ssr-gpu-dispatch.ts +946 -0
- package/src/__tests__/ssr-graph-topology.unit.test.ts +104 -0
- package/src/__tests__/ssr-history-filter.dawn.test.ts +198 -0
- package/src/__tests__/ssr-hit-color.dawn.test.ts +273 -0
- package/src/__tests__/ssr-hiz-odd-reduction.dawn.test.ts +569 -0
- package/src/__tests__/ssr-hiz-rescue.dawn.test.ts +279 -0
- package/src/__tests__/ssr-hiz.browser.test.ts +150 -0
- package/src/__tests__/ssr-hiz.dawn.test.ts +150 -0
- package/src/__tests__/ssr-hiz.unit.test.ts +56 -0
- package/src/__tests__/ssr-inspection.unit.test.ts +105 -0
- package/src/__tests__/ssr-memory-budget.unit.test.ts +45 -0
- package/src/__tests__/ssr-performance-sequence-aggregation.unit.test.ts +15 -0
- package/src/__tests__/ssr-public-surface.test-d.ts +37 -0
- package/src/__tests__/ssr-receiver-coverage.dawn.test.ts +387 -0
- package/src/__tests__/ssr-reflection-mip-reducer.dawn.test.ts +309 -0
- package/src/__tests__/ssr-reprojection-probe.ts +90 -0
- package/src/__tests__/ssr-roughness-mip.dawn.test.ts +163 -0
- package/src/__tests__/ssr-shader-prewarm.unit.test.ts +59 -0
- package/src/__tests__/ssr-spatial.integration.test.ts +141 -0
- package/src/__tests__/ssr-stable-lattice.dawn.test.ts +475 -0
- package/src/__tests__/ssr-temporal-history.unit.test.ts +202 -0
- package/src/__tests__/ssr-texel-crossing.dawn.test.ts +448 -0
- package/src/__tests__/ssr-zero-work.integration.test.ts +87 -0
- package/src/__tests__/standard-cluster-variant-resolution.unit.test.ts +44 -12
- package/src/__tests__/standard-clustered-pipeline.unit.test.ts +29 -0
- package/src/__tests__/standard-output-chain-contract.unit.test.ts +99 -0
- package/src/__tests__/standard-output-chain.integration.test.ts +73 -0
- package/src/__tests__/standard-output-gpu-evidence.ts +205 -0
- package/src/__tests__/standard-output.browser.test.ts +15 -0
- package/src/__tests__/standard-output.dawn.test.ts +15 -0
- package/src/__tests__/standard-pbr-artifact-assembly.unit.test.ts +38 -0
- package/src/__tests__/standard-pipeline.integration.test.ts +320 -3
- package/src/__tests__/standard-profile-oracle.unit.test.ts +22 -0
- package/src/__tests__/standard-surface-lighting.unit.test.ts +41 -0
- package/src/__tests__/standard-texture-specialization.dawn.test.ts +141 -0
- package/src/__tests__/surface-adjacent-regressions.integration.test.ts +6 -3
- package/src/__tests__/taa-coverage-edge.dawn.test.ts +193 -0
- package/src/__tests__/taa-history-clipping.dawn.test.ts +328 -0
- package/src/__tests__/taa-neighborhood-equivalence.dawn.test.ts +778 -0
- package/src/__tests__/taa-stability-feedback.browser.test.ts +23 -0
- package/src/__tests__/taa-stability-feedback.dawn.test.ts +68 -0
- package/src/__tests__/taa-stability-feedback.ts +341 -0
- package/src/__tests__/temporal-history-lifecycle.unit.test.ts +49 -7
- package/src/__tests__/temporal-reset-matrix.unit.test.ts +9 -0
- package/src/__tests__/temporal-transaction.integration.test.ts +28 -0
- package/src/__tests__/texture-usage-surface.unit.test.ts +4 -2
- package/src/__tests__/typed-pipeline-topology.unit.test.ts +109 -4
- package/src/__tests__/typed-scene-pass-material-cache.integration.test.ts +126 -0
- package/src/__tests__/vertex-layouts-ssot.unit.test.ts +47 -0
- package/src/__tests__/visibility-extract.perf.test.ts +20 -8
- package/src/__tests__/visibility-instances.integration.test.ts +19 -7
- package/src/__tests__/visibility-producer-matrix.integration.test.ts +20 -9
- package/src/assembly/atmosphere-shader-prewarm.ts +38 -0
- package/src/assembly/dynamic-geometry-host.ts +48 -0
- package/src/assembly/dynamic-geometry-runtime.ts +71 -0
- package/src/assembly/factory.ts +4 -0
- package/src/assembly/gpu-driven-owner.ts +29 -0
- package/src/assembly/host-contract.ts +10 -0
- package/src/assembly/material/assembly.ts +38 -0
- package/src/assembly/material-shader-policy.ts +71 -28
- package/src/assembly/recovery/failure-location.ts +62 -0
- package/src/assembly/recovery/renderer-recover.ts +19 -17
- package/src/assembly/renderer-facade.ts +12 -0
- package/src/assembly/renderer-feature-inspection.ts +13 -0
- package/src/assembly/renderer-frame-transaction.ts +63 -0
- package/src/assembly/renderer-helpers.ts +26 -0
- package/src/assembly/renderer-inspection.ts +6 -0
- package/src/assembly/shader-prewarm-policy.ts +32 -0
- package/src/assembly/skin-palette-owner.ts +21 -0
- package/src/assembly/ssr-shader-prewarm.ts +41 -0
- package/src/assembly/webgpu-device-loss.ts +75 -0
- package/src/assembly/webgpu-pbr-ready.ts +232 -0
- package/src/assembly/webgpu-ready-mipmap.ts +26 -0
- package/src/assembly/webgpu-ready.ts +142 -121
- package/src/assembly/webgpu-renderer-bootstrap.ts +85 -0
- package/src/assembly/webgpu-renderer-contract.ts +69 -0
- package/src/assembly/webgpu-renderer-guards.ts +32 -0
- package/src/assembly/webgpu-renderer-observation.ts +43 -0
- package/src/assembly/webgpu-renderer-recovery-failure.ts +62 -0
- package/src/assembly/webgpu-renderer.ts +666 -652
- package/src/assembly/webgpu-vertex-layouts.ts +233 -87
- package/src/components/__tests__/camera-exposure.contract.unit.test.ts +153 -0
- package/src/components/camera.ts +287 -7
- package/src/components/index.ts +1 -0
- package/src/components/instances.ts +45 -18
- package/src/components/scene-instance.ts +2 -1
- package/src/components/screen-space-reflection.ts +21 -0
- package/src/components/sprite-animation.ts +2 -2
- package/src/components/sprite-instances.ts +1 -1
- package/src/device/gpu-residency.ts +34 -31
- package/src/environment/background.ts +263 -0
- package/src/errors/gpu-driven.ts +39 -5
- package/src/errors/render.ts +27 -3
- package/src/extract/camera.ts +26 -1
- package/src/extract/gpu-driven.ts +185 -10
- package/src/features/host.ts +237 -19
- package/src/features/noise-texture.ts +91 -0
- package/src/features/plan.ts +553 -24
- package/src/features/prepared-gpu-work.ts +631 -49
- package/src/features/prepared-graphics-store.ts +31 -0
- package/src/features/prepared-graphics.ts +5 -0
- package/src/features/render-graph-compute.ts +41 -8
- package/src/features/render-graph-contribution.ts +141 -3
- package/src/features/render-graph-raster.ts +143 -30
- package/src/features/types.ts +11 -0
- package/src/fullscreen-post-process-pass.ts +3 -0
- package/src/gpu-driven/batch-topology.ts +424 -102
- package/src/gpu-driven/pbr-program.ts +31 -0
- package/src/gpu-driven/prepared-draw.ts +29 -4
- package/src/gpu-driven/production-raster.ts +2267 -694
- package/src/gpu-driven/shadow-views.ts +539 -0
- package/src/gpu-driven/view-gpu.ts +188 -41
- package/src/gpu-scene-schema.ts +52 -11
- package/src/gpu-scene.ts +186 -99
- package/src/gpu-texture-usage.ts +1 -0
- package/src/hdrp-buffers.ts +72 -36
- package/src/ibl/frame-resources.ts +38 -0
- package/src/ibl/skylight-bind-group.ts +5 -4
- package/src/index.ts +109 -1
- package/src/inspection-types.ts +191 -0
- package/src/instances-derived-bounds.ts +258 -34
- package/src/instances.ts +459 -150
- package/src/internal.ts +22 -0
- package/src/lifecycle.ts +2 -0
- package/src/material-row.ts +145 -0
- package/src/materials.ts +44 -8
- package/src/pbr-pipeline.ts +159 -17
- package/src/pipeline/standard-forward-lane.ts +52 -24
- package/src/pipeline/standard-output/__tests__/lut-admission.unit.test.ts +103 -0
- package/src/pipeline/standard-output/auto-exposure/__tests__/capability.unit.test.ts +40 -0
- package/src/pipeline/standard-output/auto-exposure/__tests__/gpu.contract.unit.test.ts +125 -0
- package/src/pipeline/standard-output/auto-exposure/__tests__/graph.contract.unit.test.ts +94 -0
- package/src/pipeline/standard-output/auto-exposure/__tests__/oracle.test.ts +108 -0
- package/src/pipeline/standard-output/auto-exposure/__tests__/preset.test.ts +26 -0
- package/src/pipeline/standard-output/auto-exposure/capability.ts +38 -0
- package/src/pipeline/standard-output/auto-exposure/gpu.ts +567 -0
- package/src/pipeline/standard-output/auto-exposure/graph.ts +221 -0
- package/src/pipeline/standard-output/auto-exposure/inspection.ts +231 -0
- package/src/pipeline/standard-output/auto-exposure/oracle.ts +291 -0
- package/src/pipeline/standard-output/auto-exposure/preset.ts +28 -0
- package/src/pipeline/standard-output/auto-exposure/state.ts +156 -0
- package/src/pipeline/standard-output/color-transform.ts +124 -0
- package/src/pipeline/standard-output/graph.ts +139 -0
- package/src/pipeline/standard-output/lut-admission.ts +121 -0
- package/src/pipeline/standard-output/lut-gpu.ts +399 -0
- package/src/pipeline/standard-output/lut-state.ts +176 -0
- package/src/pipeline/standard-output/resources.ts +121 -0
- package/src/pipeline/standard-output/types.ts +58 -0
- package/src/pipeline/standard-pipeline.ts +192 -59
- package/src/pipeline/standard-post.ts +186 -27
- package/src/pipeline-builder.ts +16 -6
- package/src/pipeline-spec-types.ts +4 -0
- package/src/pipeline-spec.ts +37 -29
- package/src/points-lines/standard-owner.ts +6 -14
- package/src/prepare/prepared-graphics-resolver.ts +9 -2
- package/src/record/__tests__/material-slot-plan.unit.test.ts +48 -0
- package/src/record/__tests__/mesh-ssbo.unit.test.ts +40 -1
- package/src/record/__tests__/recovery-pipeline.unit.test.ts +2 -29
- package/src/record/__tests__/sprite-material-abi.unit.test.ts +36 -5
- package/src/record/__tests__/typed-frame-graph-plan.unit.test.ts +45 -0
- package/src/record/__tests__/view-ubo-layout.unit.test.ts +5 -0
- package/src/record/dynamic-geometry-consumption.ts +59 -0
- package/src/record/frame-lighting.ts +12 -11
- package/src/record/frame-snapshot.ts +133 -23
- package/src/record/frame-targets.ts +9 -0
- package/src/record/frame.ts +725 -133
- package/src/record/main-pass-geometry.ts +149 -94
- package/src/record/main-pass-material.ts +115 -26
- package/src/record/main-pass-sprite-draws.ts +16 -107
- package/src/record/main-pass.ts +78 -8
- package/src/record/material-uniforms.ts +1 -1
- package/src/record/mesh-ssbo.ts +59 -15
- package/src/record/prepared-material-bindings.ts +234 -0
- package/src/record/recovery-pipeline.ts +59 -136
- package/src/record/render-context.ts +90 -22
- package/src/record/shadow-pass.ts +1231 -209
- package/src/record/skybox-post-pass.ts +14 -3
- package/src/record/typed-frame-graph.ts +1004 -44
- package/src/record/view-ubo.ts +11 -0
- package/src/recovery/render-system-candidate.ts +90 -66
- package/src/recovery/render-system-roots.ts +113 -0
- package/src/recovery/types.ts +77 -0
- package/src/reflection/record-owner.ts +26 -54
- package/src/render-contract.ts +195 -25
- package/src/render-graph-primitives.ts +6 -2
- package/src/render-pipeline.ts +70 -1
- package/src/render-system-extract-tail.ts +409 -160
- package/src/render-system-extract.ts +376 -102
- package/src/render-system-projections.ts +241 -0
- package/src/render-system.ts +681 -822
- package/src/scene/render-scene-types.ts +13 -4
- package/src/scene/render-scene.ts +569 -355
- package/src/scene/shadow-visibility.ts +21 -0
- package/src/ssr/admission.ts +380 -14
- package/src/ssr/compose.ts +144 -0
- package/src/ssr/errors.ts +48 -0
- package/src/ssr/graph.ts +777 -0
- package/src/ssr/history.ts +436 -0
- package/src/ssr/hiz.ts +124 -0
- package/src/ssr/inspection.ts +124 -0
- package/src/ssr/resources.ts +202 -0
- package/src/ssr/temporal.ts +164 -0
- package/src/systems/skin-palette-allocator.ts +495 -148
- package/src/systems/skin-palette-types.ts +17 -0
- package/src/systems/transparent-dispatch.ts +90 -0
- package/src/targets/material-source.ts +34 -0
- package/src/temporal/coverage.ts +1 -1
- package/src/temporal/frame-coordinator.ts +23 -2
- package/src/temporal/gpu.ts +74 -12
- package/src/temporal/history.ts +3 -1
- package/src/temporal/inspection.ts +2 -1
- package/src/temporal/standard-scene-data.ts +3 -1
- package/src/temporal/temporal-view.ts +3 -0
- package/src/transmission/__tests__/standard-transmission.dawn.test.ts +204 -139
- package/src/typed-render-graph-primitives.ts +266 -74
- package/src/typed-shadow-passes.ts +122 -12
- package/src/volume/temporal.ts +10 -0
- package/dist/chunk-GE3SDD72.mjs.map +0 -1
- package/dist/chunk-GF523LHF.mjs.map +0 -1
- package/dist/chunk-IQMKJLNU.mjs.map +0 -1
- package/dist/chunk-J52NMQKR.mjs.map +0 -1
- package/dist/chunk-J6KACNOH.mjs.map +0 -1
- package/dist/chunk-JAASCMXA.mjs.map +0 -1
- package/dist/chunk-MBU4ZVE7.mjs.map +0 -1
- package/dist/chunk-RBDBZ5R7.mjs.map +0 -1
- package/dist/chunk-VSL23LZE.mjs.map +0 -1
- package/src/__tests__/instances-world-ownership.integration.test.ts +0 -62
- package/src/scene/__tests__/changed-block-summary.candidate.test.ts +0 -36
package/src/render-system.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { RenderSceneBounds } from './scene/render-scene-types';
|
|
1
2
|
// @forgeax/engine-runtime - RenderSystem main entry (D-S2 three-stage Extract ->
|
|
2
3
|
// Prepare -> Record + 4-tier error fan-out).
|
|
3
4
|
//
|
|
@@ -16,31 +17,17 @@
|
|
|
16
17
|
// .invert` (charter proposition 5: no math reinvention; render-system.test.ts
|
|
17
18
|
// asserts `/@forgeax\/engine-math/` shows up in render-system.ts source).
|
|
18
19
|
|
|
19
|
-
import {
|
|
20
|
-
|
|
21
|
-
numMipLevels,
|
|
22
|
-
resolveAssetHandle,
|
|
23
|
-
} from '@forgeax/engine-assets-runtime';
|
|
24
|
-
import type { World } from '@forgeax/engine-ecs';
|
|
20
|
+
import { numMipLevels, resolveAssetHandle } from '@forgeax/engine-assets-runtime';
|
|
21
|
+
import { Time, type World } from '@forgeax/engine-ecs';
|
|
25
22
|
import type { RenderReadLease } from '@forgeax/engine-ecs/projection';
|
|
26
23
|
import type { RecorderSession } from '@forgeax/engine-profiler';
|
|
27
24
|
import type { CompiledRenderGraphInfo } from '@forgeax/engine-render-graph';
|
|
28
|
-
import type {
|
|
29
|
-
BindGroupEntry,
|
|
30
|
-
BindGroupLayout,
|
|
31
|
-
Buffer,
|
|
32
|
-
RenderPipeline,
|
|
33
|
-
RhiDevice,
|
|
34
|
-
} from '@forgeax/engine-rhi';
|
|
25
|
+
import type { BindGroupLayout, Buffer, RenderPipeline, RhiDevice } from '@forgeax/engine-rhi';
|
|
35
26
|
import { err, ok, type Result, RhiError } from '@forgeax/engine-rhi';
|
|
36
27
|
import {
|
|
37
|
-
derive,
|
|
38
28
|
deriveTextureLayout,
|
|
39
|
-
type Handle,
|
|
40
29
|
type MaterialAsset,
|
|
41
|
-
type MaterialTextureValue,
|
|
42
30
|
type RenderPipelineAsset,
|
|
43
|
-
RenderQueue,
|
|
44
31
|
type SamplerAsset,
|
|
45
32
|
type TextureAsset,
|
|
46
33
|
toShared,
|
|
@@ -50,9 +37,8 @@ import {
|
|
|
50
37
|
directionalShadowProfileFromQuality,
|
|
51
38
|
projectDirectionalShadowInspectionSource,
|
|
52
39
|
} from './assembly/directional-shadow-inspection';
|
|
40
|
+
import { createGpuDrivenOwner } from './assembly/gpu-driven-owner';
|
|
53
41
|
import { createClusterBinScratch } from './cluster-binner';
|
|
54
|
-
import type { DeviceScope, LifecycleResourceSpec } from './device/device-scope';
|
|
55
|
-
import type { EnvironmentGeneration } from './environment/generation';
|
|
56
42
|
import { EnvironmentLifecycle } from './environment/lifecycle';
|
|
57
43
|
import {
|
|
58
44
|
type ObservationUnavailableError,
|
|
@@ -60,11 +46,11 @@ import {
|
|
|
60
46
|
TransmissionCapabilityMissingError,
|
|
61
47
|
} from './errors/render';
|
|
62
48
|
import {
|
|
63
|
-
type RenderFeatureHost,
|
|
64
49
|
type RenderFeaturePreparedGraphicsResolverInput,
|
|
65
50
|
runRenderFeatureFrame,
|
|
66
51
|
settlePreparedGraphicsCompletion,
|
|
67
52
|
} from './features/host';
|
|
53
|
+
import { createFeatureNoiseResolver } from './features/noise-texture';
|
|
68
54
|
import {
|
|
69
55
|
createRenderFeatureGpuWorkOwner,
|
|
70
56
|
type RenderFeatureGpuWorkOwner,
|
|
@@ -79,22 +65,45 @@ import {
|
|
|
79
65
|
postProcessShaderModuleLabel,
|
|
80
66
|
postProcessShaderPipelineLabel,
|
|
81
67
|
} from './fullscreen-post-process-pass';
|
|
82
|
-
import { GpuDrivenProduction } from './gpu-driven/production-raster';
|
|
83
68
|
import type {
|
|
84
69
|
BloomInspection,
|
|
85
70
|
DirectionalShadowInspection,
|
|
86
71
|
GpuDrivenProductionInspection,
|
|
87
72
|
LodOcclusionInspection,
|
|
88
|
-
|
|
89
|
-
LodOcclusionWorldInspection,
|
|
73
|
+
MaterialTextureSourceInspection,
|
|
90
74
|
MotionBlurInspection,
|
|
91
75
|
ReflectionProbeInspection,
|
|
92
76
|
RenderSceneInspection,
|
|
93
77
|
SsrDependenciesInspection,
|
|
78
|
+
SsrSpatialInspection,
|
|
94
79
|
TemporalTargetInspection,
|
|
95
80
|
TransmissionInspection,
|
|
96
81
|
} from './inspection-types';
|
|
97
82
|
import { buildOcclusionProxyVertices } from './occlusion-proxy';
|
|
83
|
+
import {
|
|
84
|
+
AUTO_EXPOSURE_HISTOGRAM_BYTES,
|
|
85
|
+
retireAutoExposureGpuResources,
|
|
86
|
+
writeAutoExposureParameters,
|
|
87
|
+
} from './pipeline/standard-output/auto-exposure/gpu';
|
|
88
|
+
import {
|
|
89
|
+
type AutoExposureInspection,
|
|
90
|
+
createAutoExposureInspection,
|
|
91
|
+
} from './pipeline/standard-output/auto-exposure/inspection';
|
|
92
|
+
import {
|
|
93
|
+
createAutoExposureState,
|
|
94
|
+
resetAutoExposureState,
|
|
95
|
+
} from './pipeline/standard-output/auto-exposure/state';
|
|
96
|
+
import {
|
|
97
|
+
createStandardLutState,
|
|
98
|
+
inspectStandardLutState,
|
|
99
|
+
prepareStandardLutCandidate,
|
|
100
|
+
resetStandardLutState,
|
|
101
|
+
type StandardLutInspection,
|
|
102
|
+
} from './pipeline/standard-output/lut-state';
|
|
103
|
+
import {
|
|
104
|
+
prepareStandardOutputResources,
|
|
105
|
+
resetStandardOutputForDeviceLoss,
|
|
106
|
+
} from './pipeline/standard-output/resources';
|
|
98
107
|
import type { PointsLinesRetainedSnapshot } from './points-lines/snapshot';
|
|
99
108
|
import { StandardPointsLinesOwner } from './points-lines/standard-owner';
|
|
100
109
|
import {
|
|
@@ -102,6 +111,35 @@ import {
|
|
|
102
111
|
materialSamplerHandles,
|
|
103
112
|
materialTextureHandles,
|
|
104
113
|
} from './recovery/render-system-candidate';
|
|
114
|
+
|
|
115
|
+
export { materialTextureHandlesForResidency } from './recovery/render-system-candidate';
|
|
116
|
+
|
|
117
|
+
import {
|
|
118
|
+
createDynamicGeometryFrameBindings,
|
|
119
|
+
resetDynamicGeometryTemporalHistory,
|
|
120
|
+
} from './record/dynamic-geometry-consumption';
|
|
121
|
+
import type {
|
|
122
|
+
RecoveryGraphCandidate,
|
|
123
|
+
RecoveryGraphCandidatePreparation,
|
|
124
|
+
RecoveryGraphCandidateRuntime,
|
|
125
|
+
RecoveryGraphSetupSubmission,
|
|
126
|
+
RecoveryPostProcessResources,
|
|
127
|
+
RecoveryRootBundle,
|
|
128
|
+
RecoveryRootRuntime,
|
|
129
|
+
} from './recovery/types';
|
|
130
|
+
|
|
131
|
+
export type {
|
|
132
|
+
RecoveryGraphCandidate,
|
|
133
|
+
RecoveryGraphCandidatePreparation,
|
|
134
|
+
RecoveryGraphCandidateRuntime,
|
|
135
|
+
RecoveryGraphSetupSubmission,
|
|
136
|
+
RecoveryPointsLinesCandidate,
|
|
137
|
+
RecoveryPostProcessResources,
|
|
138
|
+
RecoveryRootBundle,
|
|
139
|
+
RecoveryRootRuntime,
|
|
140
|
+
} from './recovery/types';
|
|
141
|
+
|
|
142
|
+
import { prepareRenderSystemRecoveryRoots } from './recovery/render-system-roots';
|
|
105
143
|
import { ReflectionProbeRecordOwner } from './reflection/record-owner';
|
|
106
144
|
import {
|
|
107
145
|
OcclusionRenderRuntime,
|
|
@@ -113,18 +151,18 @@ import { inspectVolumetricFog } from './volume/inspection';
|
|
|
113
151
|
export type { RenderSceneInspection } from './inspection-types';
|
|
114
152
|
|
|
115
153
|
import { createCubeCaptureScheduler } from './capture/scheduler';
|
|
116
|
-
import type { GpuResidencyCache } from './device/gpu-residency';
|
|
117
154
|
import type { EnvironmentInspection } from './environment/inspection';
|
|
155
|
+
import { gpuDrivenShadowDrawKey } from './extract/gpu-driven';
|
|
118
156
|
import { GPU_BUFFER_USAGE_COPY_DST, GPU_BUFFER_USAGE_UNIFORM } from './gpu-usage';
|
|
119
157
|
import { resetHdrpBuffers } from './hdrp-buffers';
|
|
120
|
-
import {
|
|
158
|
+
import type { SkylightBindGroupResources } from './ibl/skylight-bind-group';
|
|
121
159
|
import {
|
|
122
160
|
disposeInstanceBufferChunks,
|
|
123
161
|
disposeInstanceBuffers,
|
|
124
162
|
disposeTransientInstanceBuffers,
|
|
125
163
|
} from './instance-buffer-cache';
|
|
126
164
|
import type { InstanceCollectionInspection } from './instances';
|
|
127
|
-
import {
|
|
165
|
+
import { InstanceCollectionStore } from './instances';
|
|
128
166
|
import {
|
|
129
167
|
type MeshMaterialBindingObservation,
|
|
130
168
|
type MeshMaterialBindingPreparationFailure,
|
|
@@ -163,12 +201,18 @@ import type {
|
|
|
163
201
|
GpuPassTimingSession,
|
|
164
202
|
} from './record/gpu-pass-timing/session';
|
|
165
203
|
import type { GpuTimingCapture } from './record/gpu-timing';
|
|
166
|
-
import {
|
|
167
|
-
import
|
|
204
|
+
import { resolveMaterialSkylight } from './record/main-pass-material';
|
|
205
|
+
import {
|
|
206
|
+
createPreparedResolverCaches,
|
|
207
|
+
type PreparedResolverCaches,
|
|
208
|
+
preparedMaterialBindings,
|
|
209
|
+
} from './record/prepared-material-bindings';
|
|
168
210
|
import type { PipelineState, RenderSystemInternals } from './record/render-context';
|
|
169
211
|
import type { CubeCaptureGraphState } from './record/typed-frame-graph';
|
|
170
212
|
import {
|
|
213
|
+
getRenderFeatureGraphInspection,
|
|
171
214
|
type RenderFeatureGraphCandidate,
|
|
215
|
+
recordRenderFeatureCandidate,
|
|
172
216
|
resetRenderFeatureGraphState,
|
|
173
217
|
settleVolumetricFogGraphCandidate,
|
|
174
218
|
} from './record/typed-frame-graph';
|
|
@@ -182,27 +226,27 @@ import {
|
|
|
182
226
|
} from './render-contract';
|
|
183
227
|
import type {
|
|
184
228
|
DispatchEntry,
|
|
185
|
-
ExtractedFrame,
|
|
186
229
|
ExtractedLights,
|
|
187
230
|
MaterialSnapshot,
|
|
188
231
|
RenderableSnapshot,
|
|
232
|
+
ShadowCasterMembership,
|
|
189
233
|
} from './render-system-extract';
|
|
190
234
|
import { extractFrames } from './render-system-extract';
|
|
191
235
|
import {
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
} from './scene/render-scene';
|
|
236
|
+
canonicalizeWorldComposition,
|
|
237
|
+
createLodWorldInspections,
|
|
238
|
+
} from './render-system-projections';
|
|
239
|
+
import { PersistentRenderScene } from './scene/render-scene';
|
|
196
240
|
import { inspectLodOcclusion } from './scene/visibility/inspection';
|
|
197
241
|
import { resolveSsaoParameters } from './ssao-config';
|
|
198
|
-
import { projectSsrDependencies, resolveSsrAdmissionGeneration } from './ssr/admission';
|
|
199
242
|
import {
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
} from './
|
|
243
|
+
projectSsrDependencies,
|
|
244
|
+
resolveSsrAdmissionGeneration,
|
|
245
|
+
type SsrSpatialAdmission,
|
|
246
|
+
zeroSsrAdmissionWork,
|
|
247
|
+
} from './ssr/admission';
|
|
248
|
+
import { projectSsrSpatialInspection } from './ssr/inspection';
|
|
249
|
+
import { sortTransparentDispatch } from './systems/transparent-dispatch';
|
|
206
250
|
import type { RenderTarget } from './targets/contracts';
|
|
207
251
|
import { createTemporalFrameTransaction, type TemporalFrame } from './temporal/frame';
|
|
208
252
|
import { retireTemporalGpuState } from './temporal/gpu';
|
|
@@ -219,147 +263,71 @@ import {
|
|
|
219
263
|
inspectTransmissionFromAdmission,
|
|
220
264
|
} from './transmission/inspection';
|
|
221
265
|
|
|
222
|
-
|
|
266
|
+
const WORLD_ENTITY_KEY_STRIDE = 4294967296;
|
|
267
|
+
|
|
268
|
+
/**
|
|
269
|
+
* Extract emits world/entity keys in the transient `worlds[]` index domain,
|
|
270
|
+
* while PersistentRenderScene owns stable renderer-local World keys for the
|
|
271
|
+
* retained GPU scene. Rebase ShadowCaster ownership at this orchestration
|
|
272
|
+
* boundary before both GPU projection and CPU residual recording consume it.
|
|
273
|
+
*/
|
|
274
|
+
function rebaseShadowCasterOwnership(
|
|
223
275
|
worlds: readonly World[],
|
|
224
|
-
|
|
225
|
-
|
|
276
|
+
stableWorldKeys: readonly number[],
|
|
277
|
+
entityKeys: ReadonlySet<number>,
|
|
278
|
+
drawKeys: ReadonlySet<string>,
|
|
279
|
+
membership: readonly ShadowCasterMembership[] | undefined,
|
|
226
280
|
): {
|
|
227
|
-
readonly
|
|
228
|
-
readonly
|
|
229
|
-
readonly
|
|
281
|
+
readonly entityKeys: ReadonlySet<number>;
|
|
282
|
+
readonly drawKeys: ReadonlySet<string>;
|
|
283
|
+
readonly membership: readonly ShadowCasterMembership[] | undefined;
|
|
230
284
|
} {
|
|
231
|
-
const
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
leases === undefined
|
|
243
|
-
? undefined
|
|
244
|
-
: Object.freeze(
|
|
245
|
-
order.map((entry) => leases[entry.index]).filter((lease) => lease !== undefined),
|
|
246
|
-
),
|
|
285
|
+
const rebaseWorldEntity = (composite: number): number => {
|
|
286
|
+
const transientWorldId = Math.floor(composite / WORLD_ENTITY_KEY_STRIDE);
|
|
287
|
+
if (
|
|
288
|
+
!Number.isInteger(transientWorldId) ||
|
|
289
|
+
transientWorldId < 0 ||
|
|
290
|
+
transientWorldId >= worlds.length
|
|
291
|
+
) {
|
|
292
|
+
return composite;
|
|
293
|
+
}
|
|
294
|
+
const entityKey = composite - transientWorldId * WORLD_ENTITY_KEY_STRIDE;
|
|
295
|
+
return worldEntityKey(stableWorldKeys[transientWorldId] ?? transientWorldId, entityKey);
|
|
247
296
|
};
|
|
248
|
-
}
|
|
249
297
|
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
)
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
lodVisible: 0,
|
|
284
|
-
lodSamples: [] as RenderableSnapshot[],
|
|
285
|
-
}));
|
|
286
|
-
// Keep this projection bounded: the old implementation filtered the full
|
|
287
|
-
// 100k renderable list twice per World on every frame and retained another
|
|
288
|
-
// Set-backed traversal just to derive the six counters below. One pass is
|
|
289
|
-
// enough because the inspection only needs counts, the first row identity,
|
|
290
|
-
// and at most 64 detached samples.
|
|
291
|
-
for (const renderable of renderables) {
|
|
292
|
-
const accumulator = accumulators[renderable.worldId];
|
|
293
|
-
if (accumulator === undefined) continue;
|
|
294
|
-
const visible = submitted.has(renderable);
|
|
295
|
-
accumulator.allCount += 1;
|
|
296
|
-
if (visible) accumulator.allVisible += 1;
|
|
297
|
-
if (accumulator.allSamples.length < sampleLimit) accumulator.allSamples.push(renderable);
|
|
298
|
-
if ((renderable.lods?.length ?? 0) > 0) {
|
|
299
|
-
accumulator.lodCount += 1;
|
|
300
|
-
if (visible) accumulator.lodVisible += 1;
|
|
301
|
-
if (accumulator.lodSamples.length < sampleLimit) accumulator.lodSamples.push(renderable);
|
|
302
|
-
}
|
|
303
|
-
}
|
|
304
|
-
const result: LodOcclusionWorldInspection[] = [];
|
|
305
|
-
for (let worldId = 0; worldId < worlds.length; worldId += 1) {
|
|
306
|
-
const world = worlds[worldId];
|
|
307
|
-
if (world === undefined) continue;
|
|
308
|
-
const accumulator = accumulators[worldId];
|
|
309
|
-
if (accumulator === undefined || accumulator.allCount === 0) {
|
|
310
|
-
result.push(
|
|
311
|
-
Object.freeze({ attachmentId: world.identity, rows: Object.freeze([]), attribution }),
|
|
312
|
-
);
|
|
313
|
-
continue;
|
|
314
|
-
}
|
|
315
|
-
const usesLod = accumulator.lodCount > 0;
|
|
316
|
-
const candidateCount = usesLod ? accumulator.lodCount : accumulator.allCount;
|
|
317
|
-
const visible = usesLod ? accumulator.lodVisible : accumulator.allVisible;
|
|
318
|
-
const samples = usesLod ? accumulator.lodSamples : accumulator.allSamples;
|
|
319
|
-
const first = samples[0];
|
|
320
|
-
const slot =
|
|
321
|
-
first === undefined
|
|
322
|
-
? undefined
|
|
323
|
-
: slots.get(worldEntityKey(worldKeys[first.worldId] ?? first.worldId, first.entityKey));
|
|
324
|
-
const row: LodOcclusionInspectionRow = {
|
|
325
|
-
root: {
|
|
326
|
-
guid: first === undefined ? 'none' : `asset-handle:${first.assetHandle}`,
|
|
327
|
-
sourceKey: `render-world:${world.identity}`,
|
|
328
|
-
},
|
|
329
|
-
view: {
|
|
330
|
-
attachmentId: world.identity,
|
|
331
|
-
cameraEntity: world === worlds[camera.worldId ?? 0] ? (camera.entityKey ?? 0) : 0,
|
|
332
|
-
viewRole: 'main',
|
|
333
|
-
viewGeneration: camera.historyVersion ?? 0,
|
|
334
|
-
},
|
|
335
|
-
slot: { primitiveSlot: slot?.slot ?? 0, slotGeneration: slot?.generation ?? 0 },
|
|
336
|
-
generation: frameId,
|
|
337
|
-
count: { candidates: candidateCount, visible, occluded: candidateCount - visible },
|
|
338
|
-
lodHistogram: [{ level: 0, count: candidateCount }],
|
|
339
|
-
queryLatencyUs: { median: 0, p95: 0, last: 0 },
|
|
340
|
-
pagePressure: query,
|
|
341
|
-
fallback,
|
|
342
|
-
degradation,
|
|
343
|
-
samples: samples.map((candidate, index) => ({
|
|
344
|
-
primitiveSlot:
|
|
345
|
-
slots.get(
|
|
346
|
-
worldEntityKey(worldKeys[candidate.worldId] ?? candidate.worldId, candidate.entityKey),
|
|
347
|
-
)?.slot ?? index,
|
|
348
|
-
level: 0,
|
|
349
|
-
visible: submitted.has(candidate),
|
|
350
|
-
})),
|
|
351
|
-
};
|
|
352
|
-
result.push(
|
|
353
|
-
Object.freeze({
|
|
354
|
-
attachmentId: world.identity,
|
|
355
|
-
rows: Object.freeze([row]),
|
|
356
|
-
attribution,
|
|
357
|
-
}),
|
|
358
|
-
);
|
|
359
|
-
}
|
|
360
|
-
return Object.freeze(
|
|
361
|
-
result.sort((left, right) => left.attachmentId.localeCompare(right.attachmentId)),
|
|
362
|
-
);
|
|
298
|
+
const stableMembership =
|
|
299
|
+
membership === undefined
|
|
300
|
+
? undefined
|
|
301
|
+
: membership.map((entry) => ({
|
|
302
|
+
...entry,
|
|
303
|
+
worldEntity: rebaseWorldEntity(entry.worldEntity),
|
|
304
|
+
}));
|
|
305
|
+
const stableDrawKeys =
|
|
306
|
+
stableMembership === undefined
|
|
307
|
+
? new Set(
|
|
308
|
+
[...drawKeys].map((key) => {
|
|
309
|
+
const parts = key.split(':');
|
|
310
|
+
if (parts.length !== 4) return key;
|
|
311
|
+
const transientWorldEntity = Number(parts[0]);
|
|
312
|
+
if (!Number.isFinite(transientWorldEntity)) return key;
|
|
313
|
+
return `${rebaseWorldEntity(transientWorldEntity)}:${parts[1]}:${parts[2]}:${parts[3]}`;
|
|
314
|
+
}),
|
|
315
|
+
)
|
|
316
|
+
: new Set(
|
|
317
|
+
stableMembership.map((entry) =>
|
|
318
|
+
gpuDrivenShadowDrawKey(
|
|
319
|
+
entry.worldEntity,
|
|
320
|
+
entry.materialHandle,
|
|
321
|
+
entry.drawItemIndex,
|
|
322
|
+
entry.passIndex,
|
|
323
|
+
),
|
|
324
|
+
),
|
|
325
|
+
);
|
|
326
|
+
return {
|
|
327
|
+
entityKeys: new Set([...entityKeys].map(rebaseWorldEntity)),
|
|
328
|
+
drawKeys: stableDrawKeys,
|
|
329
|
+
membership: stableMembership,
|
|
330
|
+
};
|
|
363
331
|
}
|
|
364
332
|
|
|
365
333
|
type TimingSessionHost = RenderSystemInternals & {
|
|
@@ -418,12 +386,6 @@ export interface RendererProducerRoot {
|
|
|
418
386
|
readonly disabledWork: 'zero' | 'lazy';
|
|
419
387
|
}
|
|
420
388
|
|
|
421
|
-
/** Device-bound post-process resources prepared off to the side of the active renderer. */
|
|
422
|
-
export interface RecoveryPostProcessResources {
|
|
423
|
-
readonly device: RhiDevice;
|
|
424
|
-
readonly paramsBuffers: Map<string, Buffer>;
|
|
425
|
-
}
|
|
426
|
-
|
|
427
389
|
const PRODUCER_ROOT_MATRIX: readonly RendererProducerRoot[] = Object.freeze([
|
|
428
390
|
{
|
|
429
391
|
kind: 'backend-surface',
|
|
@@ -520,129 +482,6 @@ export interface RecoveryProductionEvidence {
|
|
|
520
482
|
};
|
|
521
483
|
}
|
|
522
484
|
|
|
523
|
-
/**
|
|
524
|
-
* Unified transparent-queue sub-sort covering all four
|
|
525
|
-
* {@link TransparentSortConfig} modes. Reorders the
|
|
526
|
-
* `queue === RenderQueue.Transparent` segment of the dispatch list;
|
|
527
|
-
* all other queue segments keep their relative order.
|
|
528
|
-
*
|
|
529
|
-
* | mode | primary key | secondary key | tertiary key |
|
|
530
|
-
* |:--:|:--|:--|:--|
|
|
531
|
-
* | 0 (LAYER_Z) | `layer` ASC | `posZ` ASC | `materialHandle` ASC |
|
|
532
|
-
* | 1 (LAYER_Y) | `layer` ASC | `-(posY - pivotY * sizeY)` ASC | `materialHandle` ASC |
|
|
533
|
-
* | 2 (LAYER_YZ) | `layer` ASC | `(posY - pivotY * sizeY) + yzAlpha * posZ` ASC | `materialHandle` ASC |
|
|
534
|
-
* | 3 (DISTANCE) | `-(dist² from camera)` ASC (back-to-front, layer ignored) | — |
|
|
535
|
-
*
|
|
536
|
-
* The `materialHandle` tertiary key for modes 0/1/2 groups same-material
|
|
537
|
-
* entries together whenever the primary+secondary sort values are equal
|
|
538
|
-
* (e.g. tilemap tiles in the same row/layer share `posY` in LAYER_Y mode).
|
|
539
|
-
* Consecutive same-material groups then collapse into fold buckets in the
|
|
540
|
-
* record-stage fold operator, significantly reducing draw call count for
|
|
541
|
-
* tilemap-heavy scenes.
|
|
542
|
-
*
|
|
543
|
-
* `posX/Y/Z` = translation column of the entity's world mat4 (indices 12/13/14).
|
|
544
|
-
* `pivotY` = `RenderableSnapshot.material.paramSnapshot.pivotAndSize[1]` (default 0.5).
|
|
545
|
-
* `sizeY` = length of the Y-axis column of the world mat4 (indices 4/5/6).
|
|
546
|
-
*/
|
|
547
|
-
function sortTransparentDispatch(
|
|
548
|
-
dispatch: DispatchEntry[],
|
|
549
|
-
world: World,
|
|
550
|
-
cameras: readonly CameraSnapshot[],
|
|
551
|
-
renderables: readonly RenderableSnapshot[],
|
|
552
|
-
): DispatchEntry[] {
|
|
553
|
-
const cfg = getTransparentSortConfig(world);
|
|
554
|
-
const mode = cfg.mode;
|
|
555
|
-
|
|
556
|
-
// Indices of Transparent-queue entries within the dispatch list.
|
|
557
|
-
const transparentSlots: number[] = [];
|
|
558
|
-
for (let i = 0; i < dispatch.length; i++) {
|
|
559
|
-
if (dispatch[i]?.queue === RenderQueue.Transparent) transparentSlots.push(i);
|
|
560
|
-
}
|
|
561
|
-
if (transparentSlots.length <= 1) return dispatch;
|
|
562
|
-
|
|
563
|
-
let sortedSlotOrder: number[];
|
|
564
|
-
|
|
565
|
-
if (mode === TRANSPARENT_SORT_MODE_DISTANCE) {
|
|
566
|
-
const camera = cameras[0];
|
|
567
|
-
if (camera === undefined) return dispatch;
|
|
568
|
-
const camPos = camera.position;
|
|
569
|
-
|
|
570
|
-
// Squared camera distance per entry (negated → ascending = back-to-front).
|
|
571
|
-
// D-3: world position = translation column of GlobalTransform.world (m[12,13,14]).
|
|
572
|
-
const negDistSq = (entry: DispatchEntry): number => {
|
|
573
|
-
const tx = renderables[entry.renderableIndex]?.transform;
|
|
574
|
-
if (tx === undefined) return 0;
|
|
575
|
-
const w = tx.world;
|
|
576
|
-
const dx = (w[12] ?? 0) - (camPos[0] ?? 0);
|
|
577
|
-
const dy = (w[13] ?? 0) - (camPos[1] ?? 0);
|
|
578
|
-
const dz = (w[14] ?? 0) - (camPos[2] ?? 0);
|
|
579
|
-
return -(dx * dx + dy * dy + dz * dz);
|
|
580
|
-
};
|
|
581
|
-
|
|
582
|
-
sortedSlotOrder = transparentSlots.slice().sort((a, b) => {
|
|
583
|
-
const da = negDistSq(dispatch[a] as DispatchEntry);
|
|
584
|
-
const db = negDistSq(dispatch[b] as DispatchEntry);
|
|
585
|
-
if (da < db) return -1;
|
|
586
|
-
if (da > db) return 1;
|
|
587
|
-
return 0;
|
|
588
|
-
});
|
|
589
|
-
} else {
|
|
590
|
-
// Modes 0/1/2: primary = layer ASC, secondary = mode-formula ASC.
|
|
591
|
-
// sizeY = length of the Y-axis column (col1 = indices 4,5,6) of the
|
|
592
|
-
// world mat4; rotation-invariant and handles flipV sign correctly.
|
|
593
|
-
const sortVal = (entry: DispatchEntry): number => {
|
|
594
|
-
const tx = renderables[entry.renderableIndex]?.transform;
|
|
595
|
-
const w = tx?.world;
|
|
596
|
-
const posY = (w?.[13] ?? 0) as number;
|
|
597
|
-
const posZ = (w?.[14] ?? 0) as number;
|
|
598
|
-
if (mode === TRANSPARENT_SORT_MODE_LAYER_Z) return posZ;
|
|
599
|
-
const mat = renderables[entry.renderableIndex]?.material;
|
|
600
|
-
// feat-20260625-refactor-sprite-as-transparent-mesh M3 / w15: post
|
|
601
|
-
// SpriteFieldsSnapshot ablation, pivot lives in paramSnapshot
|
|
602
|
-
// .pivotAndSize[0..1] (UBO-aligned vec4 slot 2, plan D-6). Non-sprite
|
|
603
|
-
// materials carry paramSnapshot=undefined and fall back to 0.5.
|
|
604
|
-
const pivotAndSize = mat?.paramSnapshot?.pivotAndSize as readonly number[] | undefined;
|
|
605
|
-
const pivotY = (pivotAndSize?.[1] ?? 0.5) as number;
|
|
606
|
-
const wy4 = (w?.[4] ?? 0) as number;
|
|
607
|
-
const wy5 = (w?.[5] ?? 1) as number;
|
|
608
|
-
const wy6 = (w?.[6] ?? 0) as number;
|
|
609
|
-
const sizeY = Math.sqrt(wy4 * wy4 + wy5 * wy5 + wy6 * wy6);
|
|
610
|
-
const footY = posY - pivotY * sizeY;
|
|
611
|
-
if (mode === TRANSPARENT_SORT_MODE_LAYER_Y) return -footY;
|
|
612
|
-
if (mode === TRANSPARENT_SORT_MODE_LAYER_YZ) return footY + cfg.yzAlpha * posZ;
|
|
613
|
-
// Defensive fallback for an unknown mode that slips past setTransparentSortConfig.
|
|
614
|
-
return posZ;
|
|
615
|
-
};
|
|
616
|
-
|
|
617
|
-
sortedSlotOrder = transparentSlots.slice().sort((a, b) => {
|
|
618
|
-
const da = dispatch[a] as DispatchEntry;
|
|
619
|
-
const db = dispatch[b] as DispatchEntry;
|
|
620
|
-
const la = da.layer;
|
|
621
|
-
const lb = db.layer;
|
|
622
|
-
if (la !== lb) return la - lb;
|
|
623
|
-
const va = sortVal(da);
|
|
624
|
-
const vb = sortVal(db);
|
|
625
|
-
if (va < vb) return -1;
|
|
626
|
-
if (va > vb) return 1;
|
|
627
|
-
// Tertiary tiebreaker: group same-materialHandle entries together so
|
|
628
|
-
// fold-eligible consecutive runs form. Entries at equal (layer,
|
|
629
|
-
// sortVal) — e.g. tilemap tiles in the same row under LAYER_Y — are
|
|
630
|
-
// depth-equivalent; reordering them by material does not change the
|
|
631
|
-
// visual result but maximises fold-bucket width.
|
|
632
|
-
return da.materialHandle - db.materialHandle;
|
|
633
|
-
});
|
|
634
|
-
}
|
|
635
|
-
|
|
636
|
-
// Scatter the reordered Transparent entries back into their original slots.
|
|
637
|
-
const result = dispatch.slice();
|
|
638
|
-
for (let k = 0; k < transparentSlots.length; k++) {
|
|
639
|
-
const targetSlot = transparentSlots[k] as number;
|
|
640
|
-
const sourceSlot = sortedSlotOrder[k] as number;
|
|
641
|
-
result[targetSlot] = dispatch[sourceSlot] as DispatchEntry;
|
|
642
|
-
}
|
|
643
|
-
return result;
|
|
644
|
-
}
|
|
645
|
-
|
|
646
485
|
/**
|
|
647
486
|
* Engine-internal Extract / Prepare / Record driver; constructed by createRenderer.
|
|
648
487
|
*
|
|
@@ -660,6 +499,9 @@ function sortTransparentDispatch(
|
|
|
660
499
|
* whose shader identity is `forgeax::default-standard-pbr`).
|
|
661
500
|
*/
|
|
662
501
|
export interface RenderSystem {
|
|
502
|
+
bounds(world: World, entity: number): RenderSceneBounds | undefined;
|
|
503
|
+
/** Complete explicit SSR capability preparation before drawing a device generation. */
|
|
504
|
+
initializeSsr(device?: RhiDevice): Promise<void>;
|
|
663
505
|
/** Returns true only when this invocation reached queue submission. */
|
|
664
506
|
draw(
|
|
665
507
|
worlds: readonly World[],
|
|
@@ -677,7 +519,7 @@ export interface RenderSystem {
|
|
|
677
519
|
/** Prepare a detached graph candidate without entering the frame record path. */
|
|
678
520
|
prepareRecoveryGraphCandidate(
|
|
679
521
|
runtime: RecoveryGraphCandidateRuntime,
|
|
680
|
-
):
|
|
522
|
+
): RecoveryGraphCandidatePreparation;
|
|
681
523
|
/** Finish and submit detached candidate setup, never a frame receipt. */
|
|
682
524
|
submitCandidateSetup(
|
|
683
525
|
candidate: RecoveryGraphCandidate,
|
|
@@ -703,6 +545,8 @@ export interface RenderSystem {
|
|
|
703
545
|
readonly pipelineDispatchCounts: {
|
|
704
546
|
readonly unlit: number;
|
|
705
547
|
};
|
|
548
|
+
/** Renderer-owned source for explicit large instance collections. */
|
|
549
|
+
readonly instances: InstanceCollectionStore;
|
|
706
550
|
/** Detached residency and upload facts for explicit instance collections. */
|
|
707
551
|
readonly instanceCollectionsInspection: readonly InstanceCollectionInspection[];
|
|
708
552
|
/**
|
|
@@ -717,11 +561,17 @@ export interface RenderSystem {
|
|
|
717
561
|
readonly reflectionProbes: ReflectionProbeInspection;
|
|
718
562
|
/** Live producer/RHI/temporal receipts projected through SSR admission. */
|
|
719
563
|
readonly ssrDependencies: SsrDependenciesInspection;
|
|
564
|
+
/** Live SSR spatial admission and bounded graph/history projection. */
|
|
565
|
+
readonly ssr: SsrSpatialInspection;
|
|
720
566
|
/** Producer completion fence included in the public FrameReceipt. */
|
|
721
567
|
readonly reflectionFallbackCompletion: Promise<void> | undefined;
|
|
722
568
|
/** True while a progressive CubeCamera candidate still owns unfinished faces. */
|
|
723
569
|
isCubeCapturePending(target: RenderTarget): boolean;
|
|
724
570
|
readonly environment: EnvironmentInspection;
|
|
571
|
+
/** Detached auto-exposure state published after a successful frame submit. */
|
|
572
|
+
readonly autoExposure: AutoExposureInspection | undefined;
|
|
573
|
+
/** Detached Standard LUT state published after a successful frame submit. */
|
|
574
|
+
readonly standardLut: StandardLutInspection;
|
|
725
575
|
readonly temporal: TemporalInspection;
|
|
726
576
|
readonly bloom: BloomInspection;
|
|
727
577
|
readonly motionBlurInspection: MotionBlurInspection | undefined;
|
|
@@ -756,6 +606,10 @@ export interface RenderSystem {
|
|
|
756
606
|
readonly lastSuccessfulCameraAntialias: CameraSnapshot['antialias'] | undefined;
|
|
757
607
|
/** Detached compiled-graph facts used by the renderer inspection owner. */
|
|
758
608
|
readonly perFrameGraphInfo: CompiledRenderGraphInfo | undefined;
|
|
609
|
+
/** Detached feature signature/compile/lifetime counters. */
|
|
610
|
+
readonly featureGraphInspection: import('./inspection-types').RenderFeatureGraphInspection;
|
|
611
|
+
/** Detached material texture-source probe counters from the last extract. */
|
|
612
|
+
readonly materialTextureSources: MaterialTextureSourceInspection;
|
|
759
613
|
/** Production-owner recovery facts used by Renderer.inspect(). */
|
|
760
614
|
readonly recoveryEvidence: RecoveryProductionEvidence;
|
|
761
615
|
/**
|
|
@@ -878,13 +732,6 @@ function makePreparedPipelinePendingError(): RhiError {
|
|
|
878
732
|
});
|
|
879
733
|
}
|
|
880
734
|
|
|
881
|
-
/** The single Points/Lines owner’s staged device-generation handoff. */
|
|
882
|
-
export interface RecoveryPointsLinesCandidate {
|
|
883
|
-
createRecoveryRoot(scope: DeviceScope): LifecycleResourceSpec<unknown>;
|
|
884
|
-
publish(): void;
|
|
885
|
-
release(): void;
|
|
886
|
-
}
|
|
887
|
-
|
|
888
735
|
function preparationFailureFrom(error: unknown): MeshMaterialBindingPreparationFailure | undefined {
|
|
889
736
|
if (typeof error !== 'object' || error === null) return undefined;
|
|
890
737
|
const value = error as {
|
|
@@ -912,58 +759,6 @@ function preparationFailureFrom(error: unknown): MeshMaterialBindingPreparationF
|
|
|
912
759
|
};
|
|
913
760
|
}
|
|
914
761
|
|
|
915
|
-
/** Candidate-only device/runtime inputs used by the recovery prepare seam. */
|
|
916
|
-
export interface RecoveryGraphCandidateRuntime {
|
|
917
|
-
readonly internals: RenderSystemInternals;
|
|
918
|
-
readonly pipelineState: PipelineState;
|
|
919
|
-
}
|
|
920
|
-
|
|
921
|
-
/** Detached graph state prepared on a replacement device, before publication. */
|
|
922
|
-
export interface RecoveryGraphCandidate {
|
|
923
|
-
readonly frameState: RenderFrameState;
|
|
924
|
-
readonly setupWorks: readonly MipmapEncoderWork[];
|
|
925
|
-
readonly device: RhiDevice;
|
|
926
|
-
readonly generation: number;
|
|
927
|
-
readonly gpuDrivenProduction?: GpuDrivenProduction;
|
|
928
|
-
readonly gpuDrivenScene?: PersistentGpuDrivenCandidate;
|
|
929
|
-
/** Staged CPU-expanded Points/Lines buffers owned by the same RenderSystem. */
|
|
930
|
-
readonly pointsLines?: RecoveryPointsLinesCandidate;
|
|
931
|
-
readonly featureHost?: RenderFeatureHost;
|
|
932
|
-
readonly featureGpuWork?: RenderFeatureGpuWorkOwner;
|
|
933
|
-
readonly featureGraphCandidate?: RenderFeatureGraphCandidate;
|
|
934
|
-
readonly postProcessPipelines?: ReadonlyMap<string, RenderPipeline>;
|
|
935
|
-
readonly recoveryReadiness: RecoveryPipelineReadiness;
|
|
936
|
-
/** Release all candidate roots before publication; safe to call repeatedly. */
|
|
937
|
-
readonly release: () => void;
|
|
938
|
-
/** Transfer candidate-root ownership to the published RenderSystem. */
|
|
939
|
-
readonly markPublished: () => void;
|
|
940
|
-
}
|
|
941
|
-
|
|
942
|
-
/** Candidate setup completion; completion is bounded by the recovery owner. */
|
|
943
|
-
export interface RecoveryGraphSetupSubmission {
|
|
944
|
-
readonly completion?: PromiseLike<unknown>;
|
|
945
|
-
}
|
|
946
|
-
|
|
947
|
-
export type RecoveryGraphCandidatePreparation =
|
|
948
|
-
| { readonly kind: 'no-seed' }
|
|
949
|
-
| { readonly kind: 'ready'; readonly candidate: RecoveryGraphCandidate }
|
|
950
|
-
| { readonly kind: 'failed'; readonly reason: string; readonly cause?: unknown };
|
|
951
|
-
|
|
952
|
-
/** Explicit candidate-owned inputs for lifecycle-root preparation. */
|
|
953
|
-
export interface RecoveryRootRuntime {
|
|
954
|
-
readonly scope: DeviceScope;
|
|
955
|
-
readonly device: RhiDevice;
|
|
956
|
-
readonly gpuStore: GpuResidencyCache;
|
|
957
|
-
readonly graphCandidate?: RecoveryGraphCandidate | undefined;
|
|
958
|
-
}
|
|
959
|
-
|
|
960
|
-
/** Candidate roots plus the one synchronous owner switch at publication. */
|
|
961
|
-
export interface RecoveryRootBundle {
|
|
962
|
-
readonly roots: readonly LifecycleResourceSpec<unknown>[];
|
|
963
|
-
publish(): void;
|
|
964
|
-
discard(): void;
|
|
965
|
-
}
|
|
966
|
-
|
|
967
762
|
/**
|
|
968
763
|
* Project the producer-owned material and GPU store state into the one
|
|
969
764
|
* renderer observation surface. This is intentionally recomputed from the
|
|
@@ -1088,42 +883,37 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
1088
883
|
let releaseProfilerCatalog =
|
|
1089
884
|
phaseCatalogRegistration?.ok === true ? phaseCatalogRegistration.value : undefined;
|
|
1090
885
|
let preparedWorlds: readonly World[] = [];
|
|
1091
|
-
|
|
886
|
+
const resolveFeatureNoise = createFeatureNoiseResolver({
|
|
887
|
+
scope: internals.deviceScope,
|
|
888
|
+
getDevice: () => internals.device,
|
|
889
|
+
onError: (error) => internals.errorRegistry.fire(error),
|
|
890
|
+
});
|
|
891
|
+
let preparedFeatureSkylightResources: SkylightBindGroupResources | undefined;
|
|
892
|
+
const dynamicGeometryFrames = createDynamicGeometryFrameBindings();
|
|
1092
893
|
let latestCamera: CameraSnapshot | undefined;
|
|
1093
894
|
const pointsLinesOwner = new StandardPointsLinesOwner(internals);
|
|
1094
|
-
const instanceCollections = new
|
|
895
|
+
const instanceCollections = new InstanceCollectionStore();
|
|
1095
896
|
const reflectionProbeOwner = new ReflectionProbeRecordOwner(internals);
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
897
|
+
const ssrFormatReceipts = new WeakMap<
|
|
898
|
+
RhiDevice,
|
|
899
|
+
import('@forgeax/engine-rhi').RhiTextureFormatCapabilityReceipt
|
|
900
|
+
>();
|
|
1099
901
|
let ssrFallbackGeneration: number | undefined;
|
|
1100
|
-
const ensureSsrFormatProbe = (): void => {
|
|
1101
|
-
if (internals.ssrIdentity === undefined) return;
|
|
1102
|
-
const generation = internals.deviceScope.generation;
|
|
902
|
+
const ensureSsrFormatProbe = async (device = internals.device): Promise<void> => {
|
|
1103
903
|
if (
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
typeof internals.device.probeTextureFormatCapability !== 'function'
|
|
1108
|
-
) {
|
|
904
|
+
internals.ssrIdentity === undefined ||
|
|
905
|
+
typeof device.probeTextureFormatCapability !== 'function'
|
|
906
|
+
)
|
|
1109
907
|
return;
|
|
908
|
+
// RHI memoizes the probe per physical device. Retain the detached candidate
|
|
909
|
+
// receipt without publishing it: inspection selects only the active device.
|
|
910
|
+
// A failed/late recovery therefore cannot overwrite the active generation.
|
|
911
|
+
try {
|
|
912
|
+
const result = await device.probeTextureFormatCapability();
|
|
913
|
+
if (result.ok) ssrFormatReceipts.set(device, result.value);
|
|
914
|
+
} catch {
|
|
915
|
+
// Missing capability remains an explicit fallback-only admission.
|
|
1110
916
|
}
|
|
1111
|
-
ssrFormatProbeGeneration = generation;
|
|
1112
|
-
const device = internals.device;
|
|
1113
|
-
ssrFormatProbe = device
|
|
1114
|
-
.probeTextureFormatCapability()
|
|
1115
|
-
.then((result) => {
|
|
1116
|
-
if (internals.device !== device || internals.deviceScope.generation !== generation) return;
|
|
1117
|
-
ssrFormatReceipt = result.ok ? result.value : undefined;
|
|
1118
|
-
})
|
|
1119
|
-
.catch(() => {
|
|
1120
|
-
if (internals.device === device && internals.deviceScope.generation === generation) {
|
|
1121
|
-
ssrFormatReceipt = undefined;
|
|
1122
|
-
}
|
|
1123
|
-
})
|
|
1124
|
-
.finally(() => {
|
|
1125
|
-
ssrFormatProbe = undefined;
|
|
1126
|
-
});
|
|
1127
917
|
};
|
|
1128
918
|
const cubeCaptureScheduler = createCubeCaptureScheduler({ maxFacesPerFrame: 1 });
|
|
1129
919
|
const cubeCaptureState: CubeCaptureGraphState = { work: [] };
|
|
@@ -1134,7 +924,6 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
1134
924
|
internals.gpuStore.invalidateMesh(handle, preparedWorlds[worldId] ?? worldId);
|
|
1135
925
|
},
|
|
1136
926
|
instanceCollections,
|
|
1137
|
-
getSkinPaletteAllocator: () => internals.getPipelineState()?.skinPaletteAllocator ?? null,
|
|
1138
927
|
});
|
|
1139
928
|
let environmentLifecycle = new EnvironmentLifecycle(internals.deviceScope);
|
|
1140
929
|
const transmissionAdmission = new TransmissionCandidateAdmission();
|
|
@@ -1278,7 +1067,12 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
1278
1067
|
}),
|
|
1279
1068
|
),
|
|
1280
1069
|
} satisfies import('./pipeline-builder').PipelineBuilderShaderModuleFactory);
|
|
1281
|
-
let
|
|
1070
|
+
let gpuDrivenRecoveryCount = 0;
|
|
1071
|
+
let gpuDrivenProduction = createGpuDrivenOwner(
|
|
1072
|
+
internals.device,
|
|
1073
|
+
gpuDrivenShaderFactory,
|
|
1074
|
+
gpuDrivenRecoveryCount,
|
|
1075
|
+
);
|
|
1282
1076
|
let occlusionRuntime: OcclusionRenderRuntime | undefined = new OcclusionRenderRuntime(
|
|
1283
1077
|
internals.device,
|
|
1284
1078
|
persistentRenderScene.visibilityFacetStore(),
|
|
@@ -1346,6 +1140,13 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
1346
1140
|
const frameState: RenderFrameState = {
|
|
1347
1141
|
frameNumber: 0,
|
|
1348
1142
|
reflectionFallbackDemand: false,
|
|
1143
|
+
ssrRequested: false,
|
|
1144
|
+
ssrSpatialAdmission: undefined,
|
|
1145
|
+
ssrHistoryOwner: undefined,
|
|
1146
|
+
ssrHistoryCandidate: undefined,
|
|
1147
|
+
ssrTemporalParamsPayload: new Uint8Array(32),
|
|
1148
|
+
ssrLastCameraEntity: undefined,
|
|
1149
|
+
ssrLastHistoryVersion: undefined,
|
|
1349
1150
|
graphGeneration: 0,
|
|
1350
1151
|
successfulTemporalFrameIndex: 0,
|
|
1351
1152
|
lastSuccessfulBloom: 'off',
|
|
@@ -1376,6 +1177,14 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
1376
1177
|
reflectionFallbackObservationSource: undefined,
|
|
1377
1178
|
lastSuccessfulCameraAntialias: undefined,
|
|
1378
1179
|
temporalGpuState: undefined,
|
|
1180
|
+
autoExposureGpuResources: undefined,
|
|
1181
|
+
pendingAutoExposureGpuResources: undefined,
|
|
1182
|
+
autoExposureState: undefined,
|
|
1183
|
+
pendingAutoExposureState: undefined,
|
|
1184
|
+
standardLutGpuResources: undefined,
|
|
1185
|
+
pendingStandardLutGpuResources: undefined,
|
|
1186
|
+
standardLutState: createStandardLutState({ deviceEpoch: internals.deviceScope.generation }),
|
|
1187
|
+
pendingStandardLutState: undefined,
|
|
1379
1188
|
activeTemporalGpuState: undefined,
|
|
1380
1189
|
retiringTemporalGpuStates: new Set(),
|
|
1381
1190
|
lastSuccessfulTemporalView: undefined,
|
|
@@ -1385,7 +1194,7 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
1385
1194
|
currentDirectionalShadowView: null,
|
|
1386
1195
|
currentSpotShadowView: null,
|
|
1387
1196
|
instanceBuffers: new Map(),
|
|
1388
|
-
|
|
1197
|
+
instanceCollections,
|
|
1389
1198
|
instanceBufferChunks: new Map(),
|
|
1390
1199
|
probeBlendBuffers: new Map(),
|
|
1391
1200
|
probeBlendRecordBufferCapacity: 0,
|
|
@@ -1468,6 +1277,25 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
1468
1277
|
// tiles until the first frame with a castShadow spot (AC-03).
|
|
1469
1278
|
spotShadowSnapshots: [],
|
|
1470
1279
|
};
|
|
1280
|
+
const resolveSsrDependencies = (requested: boolean): SsrDependenciesInspection => {
|
|
1281
|
+
// Explicit SSR capability preparation belongs to initialization. Inspection
|
|
1282
|
+
// only projects receipts and never starts work or creates image history.
|
|
1283
|
+
const owner = reflectionProbeOwner.inspect();
|
|
1284
|
+
const temporal =
|
|
1285
|
+
frameState.lastSuccessfulTemporalView === undefined
|
|
1286
|
+
? undefined
|
|
1287
|
+
: ({
|
|
1288
|
+
successfulSubmit: true,
|
|
1289
|
+
generation: frameState.lastSuccessfulTemporalView.input.deviceGeneration,
|
|
1290
|
+
} as const);
|
|
1291
|
+
return projectSsrDependencies({
|
|
1292
|
+
requested,
|
|
1293
|
+
identity: internals.ssrIdentity,
|
|
1294
|
+
reflectionFallback: owner.reflectionFallback,
|
|
1295
|
+
format: ssrFormatReceipts.get(internals.device),
|
|
1296
|
+
temporal,
|
|
1297
|
+
});
|
|
1298
|
+
};
|
|
1471
1299
|
let directFrameId = 0;
|
|
1472
1300
|
let submittedFrameCount = 0;
|
|
1473
1301
|
let lastSubmittedGeneration: number | undefined;
|
|
@@ -1475,6 +1303,122 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
1475
1303
|
let lastDirectionalShadowCandidate: 'accepted' | 'failed' = 'failed';
|
|
1476
1304
|
let lastDirectionalShadowError: DirectionalShadowInspectionSource['error'];
|
|
1477
1305
|
|
|
1306
|
+
/**
|
|
1307
|
+
* Stage the detached auto/LUT facts beside the GPU candidates already owned
|
|
1308
|
+
* by RenderFrameState. The typed graph promotes both records only after its
|
|
1309
|
+
* single finish/submit transaction succeeds; no side registry or compile
|
|
1310
|
+
* callback can publish a value early.
|
|
1311
|
+
*/
|
|
1312
|
+
function stageLiveFeatureState(camera: CameraSnapshot | undefined, deltaTime: number): void {
|
|
1313
|
+
frameState.pendingAutoExposureState = undefined;
|
|
1314
|
+
frameState.pendingStandardLutState = undefined;
|
|
1315
|
+
const output = camera?.output;
|
|
1316
|
+
if (output === undefined) return;
|
|
1317
|
+
|
|
1318
|
+
const publicFrameId =
|
|
1319
|
+
(internals as RenderSystemInternals & { readonly observationFrameId?: number })
|
|
1320
|
+
.observationFrameId ?? frameState.frameNumber;
|
|
1321
|
+
const targetGeneration = Math.max(1, camera?.historyVersion ?? 0);
|
|
1322
|
+
const deviceEpoch = internals.deviceScope.generation;
|
|
1323
|
+
|
|
1324
|
+
if (
|
|
1325
|
+
output.exposure.kind === 'auto' &&
|
|
1326
|
+
(frameState.pendingAutoExposureGpuResources !== undefined ||
|
|
1327
|
+
frameState.autoExposureGpuResources !== undefined)
|
|
1328
|
+
) {
|
|
1329
|
+
let state = frameState.autoExposureState;
|
|
1330
|
+
if (state === undefined || state.fallback !== output.exposure.fallback) {
|
|
1331
|
+
const created = createAutoExposureState({
|
|
1332
|
+
fallback: output.exposure.fallback,
|
|
1333
|
+
targetGeneration,
|
|
1334
|
+
deviceEpoch,
|
|
1335
|
+
frameId: publicFrameId,
|
|
1336
|
+
});
|
|
1337
|
+
if (!created.ok) {
|
|
1338
|
+
internals.errorRegistry.fire(created.error);
|
|
1339
|
+
return;
|
|
1340
|
+
}
|
|
1341
|
+
state = created.value;
|
|
1342
|
+
} else if (state.targetGeneration !== targetGeneration || state.deviceEpoch !== deviceEpoch) {
|
|
1343
|
+
state = resetAutoExposureState(state, 'camera-change', {
|
|
1344
|
+
targetGeneration,
|
|
1345
|
+
deviceEpoch,
|
|
1346
|
+
});
|
|
1347
|
+
}
|
|
1348
|
+
const resources =
|
|
1349
|
+
frameState.pendingAutoExposureGpuResources ?? frameState.autoExposureGpuResources;
|
|
1350
|
+
if (resources !== undefined) {
|
|
1351
|
+
const parameterWrite = writeAutoExposureParameters(resources, {
|
|
1352
|
+
compensationEv: output.exposure.compensationEv,
|
|
1353
|
+
rangeMinEv: output.exposure.rangeEv[0],
|
|
1354
|
+
rangeMaxEv: output.exposure.rangeEv[1],
|
|
1355
|
+
upRate: output.exposure.rates[0],
|
|
1356
|
+
downRate: output.exposure.rates[1],
|
|
1357
|
+
deltaTime,
|
|
1358
|
+
fallback: output.exposure.fallback,
|
|
1359
|
+
generation: state.targetGeneration,
|
|
1360
|
+
});
|
|
1361
|
+
if (!parameterWrite.ok) {
|
|
1362
|
+
internals.errorRegistry.fire(parameterWrite.error as RhiError);
|
|
1363
|
+
return;
|
|
1364
|
+
}
|
|
1365
|
+
}
|
|
1366
|
+
// The GPU adapt pass owns the numeric candidate. CPU staging carries
|
|
1367
|
+
// only the generation/transaction facts needed for submit publication.
|
|
1368
|
+
frameState.pendingAutoExposureState = Object.freeze({
|
|
1369
|
+
state,
|
|
1370
|
+
generation: state.targetGeneration,
|
|
1371
|
+
deviceEpoch: state.deviceEpoch,
|
|
1372
|
+
frameId: publicFrameId,
|
|
1373
|
+
});
|
|
1374
|
+
}
|
|
1375
|
+
|
|
1376
|
+
let lutState = frameState.standardLutState;
|
|
1377
|
+
if (lutState.targetGeneration !== targetGeneration || lutState.deviceEpoch !== deviceEpoch) {
|
|
1378
|
+
lutState = resetStandardLutState(lutState, 'device-recovered', {
|
|
1379
|
+
targetGeneration,
|
|
1380
|
+
deviceEpoch,
|
|
1381
|
+
});
|
|
1382
|
+
frameState.standardLutState = lutState;
|
|
1383
|
+
}
|
|
1384
|
+
const wantsLut = output.colorLutStrength > 0 && output.colorLut > 0;
|
|
1385
|
+
const lutResources =
|
|
1386
|
+
frameState.pendingStandardLutGpuResources ?? frameState.standardLutGpuResources;
|
|
1387
|
+
if (wantsLut && lutResources !== undefined) {
|
|
1388
|
+
const prepared = prepareStandardLutCandidate(lutState, {
|
|
1389
|
+
// sourceKey is the Catalog-owned identity returned by the same
|
|
1390
|
+
// preparation that built the live LUT bind group; numeric handles do
|
|
1391
|
+
// not cross the inspection boundary.
|
|
1392
|
+
resident: lutResources.sourceKey,
|
|
1393
|
+
sourceKey: lutResources.sourceKey,
|
|
1394
|
+
generation: lutState.targetGeneration,
|
|
1395
|
+
deviceEpoch: lutState.deviceEpoch,
|
|
1396
|
+
frameId: publicFrameId,
|
|
1397
|
+
});
|
|
1398
|
+
if (prepared.ok) {
|
|
1399
|
+
frameState.pendingStandardLutState = Object.freeze({
|
|
1400
|
+
state: lutState,
|
|
1401
|
+
candidate: prepared.value,
|
|
1402
|
+
remove: false,
|
|
1403
|
+
targetGeneration,
|
|
1404
|
+
deviceEpoch,
|
|
1405
|
+
});
|
|
1406
|
+
}
|
|
1407
|
+
} else if (!wantsLut && lutState.resident !== null) {
|
|
1408
|
+
frameState.pendingStandardLutState = Object.freeze({
|
|
1409
|
+
state: lutState,
|
|
1410
|
+
remove: true,
|
|
1411
|
+
targetGeneration,
|
|
1412
|
+
deviceEpoch,
|
|
1413
|
+
});
|
|
1414
|
+
}
|
|
1415
|
+
}
|
|
1416
|
+
|
|
1417
|
+
function discardLiveFeatureState(): void {
|
|
1418
|
+
frameState.pendingAutoExposureState = undefined;
|
|
1419
|
+
frameState.pendingStandardLutState = undefined;
|
|
1420
|
+
}
|
|
1421
|
+
|
|
1478
1422
|
function beginProfilePhase(session: RecorderSession | undefined, phase: RenderPhase): boolean {
|
|
1479
1423
|
if (session === undefined) return false;
|
|
1480
1424
|
try {
|
|
@@ -1706,22 +1650,21 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
1706
1650
|
const getPostProcessPipeline = (
|
|
1707
1651
|
id: string,
|
|
1708
1652
|
bgl: BindGroupLayout,
|
|
1709
|
-
|
|
1653
|
+
colorFormats: readonly GPUTextureFormat[],
|
|
1710
1654
|
entryOverride?: PostProcessShaderEntry,
|
|
1711
1655
|
): RenderPipeline | null => {
|
|
1712
1656
|
const entry = entryOverride ?? lookupPostProcess(id);
|
|
1713
1657
|
if (entry === undefined) return null;
|
|
1714
1658
|
const signature = postProcessShaderEntrySignature(entry);
|
|
1715
|
-
const key = `${id}|${
|
|
1659
|
+
const key = `${id}|${colorFormats.join(',')}|${signature}`;
|
|
1716
1660
|
const cached = postProcessPipelineCache.get(key);
|
|
1717
1661
|
if (cached !== undefined) return cached;
|
|
1718
|
-
internals.recoveryColdWorkGuard?.notePipelineColdWork();
|
|
1719
1662
|
const factory = internals.buildPostProcessPipeline;
|
|
1720
1663
|
if (factory === undefined) return null;
|
|
1721
1664
|
const built = factory(
|
|
1722
1665
|
entry,
|
|
1723
1666
|
bgl,
|
|
1724
|
-
|
|
1667
|
+
colorFormats,
|
|
1725
1668
|
postProcessShaderPipelineLabel(id, entry.source),
|
|
1726
1669
|
);
|
|
1727
1670
|
if (built === null) return null;
|
|
@@ -1892,193 +1835,18 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
1892
1835
|
createBindGroup: 0,
|
|
1893
1836
|
keys: [],
|
|
1894
1837
|
};
|
|
1895
|
-
type PreparedResolverCaches = {
|
|
1896
|
-
readonly preparedPipelineIds: WeakMap<object, string>;
|
|
1897
|
-
readonly preparedMaterialPipelineShaders: WeakMap<object, string>;
|
|
1898
|
-
readonly preparedGroup0Pipelines: WeakSet<object>;
|
|
1899
|
-
readonly preparedViewOnlyPipelines: WeakSet<object>;
|
|
1900
|
-
readonly preparedRenderMaterialPipelines: WeakSet<object>;
|
|
1901
|
-
readonly preparedAssetHandles: WeakMap<World, Map<string, number>>;
|
|
1902
|
-
};
|
|
1903
|
-
const createPreparedResolverCaches = (): PreparedResolverCaches => ({
|
|
1904
|
-
preparedPipelineIds: new WeakMap(),
|
|
1905
|
-
preparedMaterialPipelineShaders: new WeakMap(),
|
|
1906
|
-
preparedGroup0Pipelines: new WeakSet(),
|
|
1907
|
-
preparedViewOnlyPipelines: new WeakSet(),
|
|
1908
|
-
preparedRenderMaterialPipelines: new WeakSet(),
|
|
1909
|
-
preparedAssetHandles: new WeakMap(),
|
|
1910
|
-
});
|
|
1911
1838
|
const activePreparedResolverCaches = createPreparedResolverCaches();
|
|
1912
|
-
const preparedHandle = <Brand extends string>(
|
|
1913
|
-
runtime: RenderSystemInternals,
|
|
1914
|
-
caches: PreparedResolverCaches,
|
|
1915
|
-
world: World,
|
|
1916
|
-
guid: string,
|
|
1917
|
-
brand: Brand,
|
|
1918
|
-
): Handle<Brand, 'shared'> | undefined => {
|
|
1919
|
-
let handles = caches.preparedAssetHandles.get(world);
|
|
1920
|
-
if (handles === undefined) {
|
|
1921
|
-
handles = new Map();
|
|
1922
|
-
caches.preparedAssetHandles.set(world, handles);
|
|
1923
|
-
}
|
|
1924
|
-
const key = `${brand}:${guid.toLowerCase()}`;
|
|
1925
|
-
const cached = handles.get(key);
|
|
1926
|
-
if (cached !== undefined) return cached as Handle<Brand, 'shared'>;
|
|
1927
|
-
const asset = runtime.assets.lookup(guid);
|
|
1928
|
-
if (asset === undefined) return undefined;
|
|
1929
|
-
const handle = world.allocSharedRef(brand, asset);
|
|
1930
|
-
handles.set(key, handle as number);
|
|
1931
|
-
return handle;
|
|
1932
|
-
};
|
|
1933
|
-
const preparedMaterialBindings = (
|
|
1934
|
-
runtime: RenderSystemInternals,
|
|
1935
|
-
caches: PreparedResolverCaches,
|
|
1936
|
-
worlds: readonly World[],
|
|
1937
|
-
materialShaderId: string,
|
|
1938
|
-
worldIndex: number,
|
|
1939
|
-
materialGuid: string,
|
|
1940
|
-
layout: BindGroupLayout,
|
|
1941
|
-
) => {
|
|
1942
|
-
const world = worlds[worldIndex];
|
|
1943
|
-
const material = runtime.assets.lookup(materialGuid) as MaterialAsset | undefined;
|
|
1944
|
-
const pipelineState = runtime.getPipelineState();
|
|
1945
|
-
if (world === undefined || material?.kind !== 'material' || pipelineState === null) {
|
|
1946
|
-
return err(new Error('prepared material asset is unavailable'));
|
|
1947
|
-
}
|
|
1948
|
-
const schema = runtime.getParamSchema?.(materialShaderId) ?? [];
|
|
1949
|
-
const values = material.values ?? {};
|
|
1950
|
-
const derived = derive(schema);
|
|
1951
|
-
const fields = [...derived.textureFieldNames];
|
|
1952
|
-
let buffer: Buffer | undefined;
|
|
1953
|
-
let payloadByteLength = 0;
|
|
1954
|
-
if (derived.uboLayout.totalBytes > 0) {
|
|
1955
|
-
const payload = new Uint8Array(Math.max(16, derived.uboLayout.totalBytes));
|
|
1956
|
-
applyParamSnapshotToUbo(
|
|
1957
|
-
payload,
|
|
1958
|
-
schema,
|
|
1959
|
-
values as Readonly<Record<string, number | readonly number[]>>,
|
|
1960
|
-
);
|
|
1961
|
-
const created = runtime.device.createBuffer({
|
|
1962
|
-
label: `prepared-material:${materialGuid}`,
|
|
1963
|
-
size: payload.byteLength,
|
|
1964
|
-
usage: GPU_BUFFER_USAGE_UNIFORM | GPU_BUFFER_USAGE_COPY_DST,
|
|
1965
|
-
});
|
|
1966
|
-
if (!created.ok) return created;
|
|
1967
|
-
buffer = created.value;
|
|
1968
|
-
payloadByteLength = payload.byteLength;
|
|
1969
|
-
const written = runtime.device.queue.writeBuffer(buffer, 0, payload);
|
|
1970
|
-
if (!written.ok) {
|
|
1971
|
-
runtime.device.destroyBuffer(buffer);
|
|
1972
|
-
return written;
|
|
1973
|
-
}
|
|
1974
|
-
}
|
|
1975
|
-
const textureResources: Array<{
|
|
1976
|
-
sampler: import('@forgeax/engine-rhi').Sampler;
|
|
1977
|
-
view: import('@forgeax/engine-rhi').TextureView;
|
|
1978
|
-
}> = [];
|
|
1979
|
-
for (let index = 0; index < fields.length; index += 1) {
|
|
1980
|
-
const field = fields[index];
|
|
1981
|
-
const value = field === undefined ? undefined : values[field];
|
|
1982
|
-
const textureValue =
|
|
1983
|
-
typeof value === 'object' && value !== null && 'texture' in value
|
|
1984
|
-
? (value as MaterialTextureValue)
|
|
1985
|
-
: undefined;
|
|
1986
|
-
let sampler = pipelineState.defaultSampler;
|
|
1987
|
-
if (textureValue?.sampler !== undefined) {
|
|
1988
|
-
const handle = preparedHandle(
|
|
1989
|
-
runtime,
|
|
1990
|
-
caches,
|
|
1991
|
-
world,
|
|
1992
|
-
String(textureValue.sampler),
|
|
1993
|
-
'SamplerAsset',
|
|
1994
|
-
);
|
|
1995
|
-
if (handle !== undefined) {
|
|
1996
|
-
const asset = resolveAssetHandle<SamplerAsset>(world, handle);
|
|
1997
|
-
if (asset.ok) {
|
|
1998
|
-
const resident = runtime.gpuStore.ensureSamplerResident(handle, asset.value, world);
|
|
1999
|
-
if (resident.ok) sampler = resident.value;
|
|
2000
|
-
}
|
|
2001
|
-
}
|
|
2002
|
-
}
|
|
2003
|
-
let view = pipelineState.defaultWhiteTextureView;
|
|
2004
|
-
if (textureValue !== undefined) {
|
|
2005
|
-
const handle = preparedHandle(
|
|
2006
|
-
runtime,
|
|
2007
|
-
caches,
|
|
2008
|
-
world,
|
|
2009
|
-
String(textureValue.texture),
|
|
2010
|
-
'TextureAsset',
|
|
2011
|
-
);
|
|
2012
|
-
if (handle !== undefined) {
|
|
2013
|
-
view = residentTextureView(world, runtime.gpuStore, runtime, handle) ?? view;
|
|
2014
|
-
}
|
|
2015
|
-
}
|
|
2016
|
-
textureResources.push({ sampler, view });
|
|
2017
|
-
}
|
|
2018
|
-
const entries: BindGroupEntry[] = [];
|
|
2019
|
-
let textureIndex = 0;
|
|
2020
|
-
for (let index = 0; index < derived.bglEntries.length; index += 1) {
|
|
2021
|
-
const expected = derived.bglEntries[index];
|
|
2022
|
-
if (expected?.buffer?.type === 'uniform' && buffer !== undefined) {
|
|
2023
|
-
entries.push({
|
|
2024
|
-
binding: expected.binding,
|
|
2025
|
-
resource: { kind: 'buffer', value: { buffer, size: payloadByteLength } },
|
|
2026
|
-
});
|
|
2027
|
-
continue;
|
|
2028
|
-
}
|
|
2029
|
-
const textureResource = textureResources[textureIndex];
|
|
2030
|
-
if (
|
|
2031
|
-
expected?.sampler?.type === 'filtering' &&
|
|
2032
|
-
derived.bglEntries[index + 1]?.texture !== undefined &&
|
|
2033
|
-
textureResource !== undefined
|
|
2034
|
-
) {
|
|
2035
|
-
entries.push({
|
|
2036
|
-
binding: expected.binding,
|
|
2037
|
-
resource: { kind: 'sampler', value: textureResource.sampler },
|
|
2038
|
-
});
|
|
2039
|
-
continue;
|
|
2040
|
-
}
|
|
2041
|
-
if (expected?.texture !== undefined && textureResource !== undefined) {
|
|
2042
|
-
entries.push({
|
|
2043
|
-
binding: expected.binding,
|
|
2044
|
-
resource: { kind: 'textureView', value: textureResource.view },
|
|
2045
|
-
});
|
|
2046
|
-
textureIndex += 1;
|
|
2047
|
-
continue;
|
|
2048
|
-
}
|
|
2049
|
-
if (buffer !== undefined) runtime.device.destroyBuffer(buffer);
|
|
2050
|
-
return err(new Error('prepared material schema contains unsupported binding kinds'));
|
|
2051
|
-
}
|
|
2052
|
-
const fallback = pipelineState.skylightFallback;
|
|
2053
|
-
if (fallback === null) {
|
|
2054
|
-
if (buffer !== undefined) runtime.device.destroyBuffer(buffer);
|
|
2055
|
-
return err(new Error('prepared material skylight fallback is unavailable'));
|
|
2056
|
-
}
|
|
2057
|
-
const completeEntries = assembleMaterialWithSkylightEntries(entries, {
|
|
2058
|
-
irradianceView: fallback.irradianceView,
|
|
2059
|
-
irradianceSampler: fallback.sampler,
|
|
2060
|
-
prefilterView: fallback.prefilterView,
|
|
2061
|
-
prefilterSampler: fallback.sampler,
|
|
2062
|
-
brdfLutView: fallback.brdfLutView,
|
|
2063
|
-
brdfLutSampler: fallback.sampler,
|
|
2064
|
-
intensityBuffer: fallback.intensityBuffer,
|
|
2065
|
-
});
|
|
2066
|
-
const group = runtime.device.createBindGroup({ layout, entries: completeEntries });
|
|
2067
|
-
if (!group.ok) {
|
|
2068
|
-
if (buffer !== undefined) runtime.device.destroyBuffer(buffer);
|
|
2069
|
-
return group;
|
|
2070
|
-
}
|
|
2071
|
-
if (buffer === undefined) return group;
|
|
2072
|
-
return ok({
|
|
2073
|
-
handle: group.value,
|
|
2074
|
-
dynamicOffsets: [0, 0],
|
|
2075
|
-
release: () => runtime.device.destroyBuffer(buffer),
|
|
2076
|
-
});
|
|
2077
|
-
};
|
|
2078
1839
|
const lastFrustumStats: { culled: number; total: number } = { culled: 0, total: 0 };
|
|
2079
1840
|
const lastVisibilityStats: { explicitlyHidden: number } = { explicitlyHidden: 0 };
|
|
1841
|
+
let lastMaterialTextureSources: MaterialTextureSourceInspection = {
|
|
1842
|
+
sourceFieldsVisited: 0,
|
|
1843
|
+
numericSharedRefProbes: 0,
|
|
1844
|
+
sourceCacheHits: 0,
|
|
1845
|
+
sourceCacheMisses: 0,
|
|
1846
|
+
producerRoutes: Object.freeze({}),
|
|
1847
|
+
};
|
|
2080
1848
|
let lastMeshMaterialBindings: readonly MeshMaterialBindingObservation[] = [];
|
|
2081
|
-
let
|
|
1849
|
+
let lastMeshMaterialBindingRenderables: readonly RenderableSnapshot[] | undefined;
|
|
2082
1850
|
const createPreparedResolverFactory =
|
|
2083
1851
|
(
|
|
2084
1852
|
runtime: RenderSystemInternals,
|
|
@@ -2115,7 +1883,7 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
2115
1883
|
const pipeline = runtime.getPostProcessPipeline?.(
|
|
2116
1884
|
descriptor.shader,
|
|
2117
1885
|
fullscreen.bindGroupLayout,
|
|
2118
|
-
descriptor.colorFormats
|
|
1886
|
+
descriptor.colorFormats as readonly GPUTextureFormat[],
|
|
2119
1887
|
postProcessEntry,
|
|
2120
1888
|
);
|
|
2121
1889
|
if (pipeline !== null && pipeline !== undefined) {
|
|
@@ -2128,14 +1896,26 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
2128
1896
|
? err(makePreparedPipelinePendingError())
|
|
2129
1897
|
: ok(pipeline);
|
|
2130
1898
|
}
|
|
2131
|
-
const
|
|
1899
|
+
const clusteredParticleMesh =
|
|
1900
|
+
runtime.device.caps.storageBuffer &&
|
|
1901
|
+
(descriptor.shader === 'forgeax::vfx-render.particles.mesh' ||
|
|
1902
|
+
descriptor.shader === 'forgeax::vfx-render.particles.mesh-inputs');
|
|
1903
|
+
const requestedVariantSet = clusteredParticleMesh
|
|
1904
|
+
? 'CLUSTER_FORWARD_AVAILABLE=true'
|
|
1905
|
+
: undefined;
|
|
1906
|
+
// A colorless prepared program is a depth-only pass. Vertex-only
|
|
1907
|
+
// shadow programs must use the depth policy; resolving them as
|
|
1908
|
+
// forward asks Dawn for a non-existent `fs_main` entry point.
|
|
1909
|
+
const preparedPassKind =
|
|
1910
|
+
descriptor.colorFormats.length === 0 ? 'shadow-caster' : 'forward';
|
|
1911
|
+
const preparedPipelineEntry = runtime.getMaterialShaderPipelineEntry?.(
|
|
2132
1912
|
descriptor.shader,
|
|
2133
1913
|
descriptor.colorFormats[0] === 'rgba16float',
|
|
2134
1914
|
descriptor.renderState,
|
|
2135
1915
|
descriptor.topology,
|
|
2136
1916
|
descriptor.indexFormat,
|
|
2137
|
-
|
|
2138
|
-
|
|
1917
|
+
requestedVariantSet,
|
|
1918
|
+
preparedPassKind,
|
|
2139
1919
|
undefined,
|
|
2140
1920
|
descriptor.sampleCount ?? 1,
|
|
2141
1921
|
// Prepared graphics own their declared attachment format. Passing
|
|
@@ -2150,7 +1930,41 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
2150
1930
|
descriptor.vertexLayout,
|
|
2151
1931
|
undefined,
|
|
2152
1932
|
input.shaderModuleMode,
|
|
1933
|
+
undefined,
|
|
1934
|
+
undefined,
|
|
1935
|
+
undefined,
|
|
1936
|
+
undefined,
|
|
1937
|
+
undefined,
|
|
1938
|
+
descriptor.particleInputLanes,
|
|
2153
1939
|
);
|
|
1940
|
+
const preparedPipeline =
|
|
1941
|
+
preparedPipelineEntry === undefined
|
|
1942
|
+
? (runtime.getMaterialShaderPipeline?.(
|
|
1943
|
+
descriptor.shader,
|
|
1944
|
+
descriptor.colorFormats[0] === 'rgba16float',
|
|
1945
|
+
descriptor.renderState,
|
|
1946
|
+
descriptor.topology,
|
|
1947
|
+
descriptor.indexFormat,
|
|
1948
|
+
requestedVariantSet,
|
|
1949
|
+
preparedPassKind,
|
|
1950
|
+
undefined,
|
|
1951
|
+
descriptor.sampleCount ?? 1,
|
|
1952
|
+
descriptor.colorFormats[0] as GPUTextureFormat,
|
|
1953
|
+
undefined,
|
|
1954
|
+
descriptor.depthFormat === undefined
|
|
1955
|
+
? null
|
|
1956
|
+
: (descriptor.depthFormat as GPUTextureFormat),
|
|
1957
|
+
descriptor.vertexLayout,
|
|
1958
|
+
undefined,
|
|
1959
|
+
input.shaderModuleMode,
|
|
1960
|
+
undefined,
|
|
1961
|
+
undefined,
|
|
1962
|
+
undefined,
|
|
1963
|
+
undefined,
|
|
1964
|
+
undefined,
|
|
1965
|
+
descriptor.particleInputLanes,
|
|
1966
|
+
) ?? null)
|
|
1967
|
+
: (preparedPipelineEntry?.pipeline ?? null);
|
|
2154
1968
|
// A requested material shader is an exact pipeline contract. During
|
|
2155
1969
|
// async shader warmup, substituting the generic unlit pipeline can
|
|
2156
1970
|
// mismatch vertex layouts and HDR attachment formats, turning a
|
|
@@ -2167,7 +1981,12 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
2167
1981
|
preparedRenderMaterialPipelines.add(pipeline as object);
|
|
2168
1982
|
}
|
|
2169
1983
|
}
|
|
2170
|
-
return pipeline === null
|
|
1984
|
+
return pipeline === null
|
|
1985
|
+
? err(makePreparedPipelinePendingError())
|
|
1986
|
+
: ok({
|
|
1987
|
+
handle: pipeline,
|
|
1988
|
+
standardLighting: preparedPipelineEntry?.group2Contract === 'cluster',
|
|
1989
|
+
});
|
|
2171
1990
|
},
|
|
2172
1991
|
resolveBindings: (descriptor, pipeline) => {
|
|
2173
1992
|
const materialShaderId = preparedMaterialPipelineShaders.get(pipeline as object);
|
|
@@ -2183,6 +2002,14 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
2183
2002
|
if (bindingContract === 'view-and-scene-depth') {
|
|
2184
2003
|
return ok(undefined);
|
|
2185
2004
|
}
|
|
2005
|
+
if (
|
|
2006
|
+
preparedRenderMaterialPipelines.has(pipeline as object) &&
|
|
2007
|
+
descriptor.values.group === 0 &&
|
|
2008
|
+
descriptor.values.sceneDepth === undefined &&
|
|
2009
|
+
descriptor.values.sceneDepthBinding !== undefined
|
|
2010
|
+
) {
|
|
2011
|
+
return err(new Error('prepared scene-depth pipeline requires a scene target'));
|
|
2012
|
+
}
|
|
2186
2013
|
if (preparedGroup0Pipelines.has(pipeline as object)) {
|
|
2187
2014
|
const layout =
|
|
2188
2015
|
(materialShaderId === undefined
|
|
@@ -2236,6 +2063,7 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
2236
2063
|
material.world,
|
|
2237
2064
|
material.guid,
|
|
2238
2065
|
layout,
|
|
2066
|
+
preparedFeatureSkylightResources,
|
|
2239
2067
|
);
|
|
2240
2068
|
}
|
|
2241
2069
|
return layout === undefined
|
|
@@ -2319,23 +2147,20 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
2319
2147
|
createPreparedResolverCaches,
|
|
2320
2148
|
});
|
|
2321
2149
|
return {
|
|
2150
|
+
instances: instanceCollections,
|
|
2151
|
+
initializeSsr: ensureSsrFormatProbe,
|
|
2322
2152
|
get instanceCollectionsInspection(): readonly InstanceCollectionInspection[] {
|
|
2323
|
-
return instanceCollections._inspections(
|
|
2324
|
-
frameState.instanceResidency,
|
|
2325
|
-
frameState.frameNumber - 1,
|
|
2326
|
-
);
|
|
2153
|
+
return instanceCollections._inspections();
|
|
2327
2154
|
},
|
|
2328
2155
|
releaseProfilerCatalog(): void {
|
|
2329
2156
|
releaseProfilerCatalog?.();
|
|
2330
2157
|
releaseProfilerCatalog = undefined;
|
|
2331
2158
|
},
|
|
2332
2159
|
invalidateGeometryHistory(): void {
|
|
2333
|
-
frameState
|
|
2334
|
-
|
|
2335
|
-
|
|
2336
|
-
|
|
2337
|
-
frameState.successfulTemporalFrameIndex = 0;
|
|
2338
|
-
frameState.pendingTemporalCommit = { kind: 'none' };
|
|
2160
|
+
resetDynamicGeometryTemporalHistory(frameState);
|
|
2161
|
+
},
|
|
2162
|
+
bounds(world, entity) {
|
|
2163
|
+
return persistentRenderScene.bounds(world, entity);
|
|
2339
2164
|
},
|
|
2340
2165
|
get renderScene(): RenderSceneInspection {
|
|
2341
2166
|
return {
|
|
@@ -2350,32 +2175,46 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
2350
2175
|
return reflectionProbeOwner.inspect();
|
|
2351
2176
|
},
|
|
2352
2177
|
get ssrDependencies(): SsrDependenciesInspection {
|
|
2353
|
-
|
|
2354
|
-
|
|
2355
|
-
|
|
2356
|
-
const
|
|
2357
|
-
|
|
2358
|
-
|
|
2359
|
-
frameState.
|
|
2360
|
-
|
|
2361
|
-
|
|
2362
|
-
|
|
2363
|
-
|
|
2364
|
-
|
|
2365
|
-
|
|
2366
|
-
|
|
2367
|
-
|
|
2368
|
-
|
|
2369
|
-
|
|
2370
|
-
|
|
2371
|
-
|
|
2372
|
-
|
|
2373
|
-
|
|
2374
|
-
|
|
2375
|
-
|
|
2376
|
-
|
|
2377
|
-
|
|
2378
|
-
|
|
2178
|
+
return resolveSsrDependencies(frameState.ssrRequested === true);
|
|
2179
|
+
},
|
|
2180
|
+
get ssr(): SsrSpatialInspection {
|
|
2181
|
+
const camera = latestCamera;
|
|
2182
|
+
const lane = internals.standardProfile?.renderPath === 'deferred' ? 'deferred' : 'forward';
|
|
2183
|
+
const admission: SsrSpatialAdmission =
|
|
2184
|
+
frameState.ssrSpatialAdmission ??
|
|
2185
|
+
Object.freeze({
|
|
2186
|
+
status: camera?.screenSpaceReflection === undefined ? 'not-requested' : 'requested',
|
|
2187
|
+
lane,
|
|
2188
|
+
config: camera?.screenSpaceReflection,
|
|
2189
|
+
viewRange: camera === undefined ? 0 : camera.far - camera.near,
|
|
2190
|
+
work: zeroSsrAdmissionWork(),
|
|
2191
|
+
});
|
|
2192
|
+
const admitted = admission.status === 'admitted';
|
|
2193
|
+
const status =
|
|
2194
|
+
admitted && internals.ssrShaders === undefined
|
|
2195
|
+
? ('structural-only' as const)
|
|
2196
|
+
: admission.status;
|
|
2197
|
+
const graph = frameState.compiledFrameGraph?.inspect();
|
|
2198
|
+
const passRoster =
|
|
2199
|
+
admitted && graph !== undefined
|
|
2200
|
+
? graph.passes.filter((pass) => pass.name.startsWith('ssr-')).map((pass) => pass.name)
|
|
2201
|
+
: [];
|
|
2202
|
+
const history = frameState.ssrHistoryOwner?.inspect();
|
|
2203
|
+
const dependencies = resolveSsrDependencies(frameState.ssrRequested === true);
|
|
2204
|
+
const fallbackSource = dependencies.reflectionFallback?.source;
|
|
2205
|
+
return projectSsrSpatialInspection(admission, {
|
|
2206
|
+
status,
|
|
2207
|
+
...(history === undefined
|
|
2208
|
+
? {}
|
|
2209
|
+
: {
|
|
2210
|
+
history: {
|
|
2211
|
+
state: history.state,
|
|
2212
|
+
bytes: history.activeBytes + history.candidateBytes + history.retiringBytes,
|
|
2213
|
+
resetCount: history.resetCount,
|
|
2214
|
+
},
|
|
2215
|
+
}),
|
|
2216
|
+
passRoster,
|
|
2217
|
+
...(fallbackSource === undefined ? {} : { fallbackSource }),
|
|
2379
2218
|
});
|
|
2380
2219
|
},
|
|
2381
2220
|
get reflectionFallbackCompletion(): Promise<void> | undefined {
|
|
@@ -2387,6 +2226,27 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
2387
2226
|
get environment(): EnvironmentInspection {
|
|
2388
2227
|
return environmentLifecycle.inspect();
|
|
2389
2228
|
},
|
|
2229
|
+
get autoExposure(): AutoExposureInspection | undefined {
|
|
2230
|
+
const camera = latestCamera;
|
|
2231
|
+
const state = frameState.autoExposureState;
|
|
2232
|
+
if (camera?.output?.exposure.kind !== 'auto' || state === undefined) return undefined;
|
|
2233
|
+
const actual = state.acceptedEv > 0 ? state.acceptedEv : null;
|
|
2234
|
+
return createAutoExposureInspection({
|
|
2235
|
+
requested: camera.output.exposure,
|
|
2236
|
+
actual,
|
|
2237
|
+
actualState:
|
|
2238
|
+
actual === null ? (state.receipt.committed ? 'gpu-resident' : 'fallback') : 'accepted',
|
|
2239
|
+
fallback: state.fallback,
|
|
2240
|
+
lastKnownGood: state.lastKnownGood,
|
|
2241
|
+
targetGeneration: state.targetGeneration,
|
|
2242
|
+
reset: state.reset,
|
|
2243
|
+
cost: { histogramBytes: AUTO_EXPOSURE_HISTOGRAM_BYTES, passCount: 3, physicalPassCount: 1 },
|
|
2244
|
+
receipt: state.receipt,
|
|
2245
|
+
});
|
|
2246
|
+
},
|
|
2247
|
+
get standardLut(): StandardLutInspection {
|
|
2248
|
+
return inspectStandardLutState(frameState.standardLutState);
|
|
2249
|
+
},
|
|
2390
2250
|
get temporal(): TemporalInspection {
|
|
2391
2251
|
return inspectTemporal(frameState.lastSuccessfulTemporalView, undefined, {
|
|
2392
2252
|
...(frameState.activeTemporalGpuState === undefined
|
|
@@ -2526,6 +2386,14 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
2526
2386
|
return persistentRenderScene.pointsLinesSnapshots();
|
|
2527
2387
|
},
|
|
2528
2388
|
detachScene(world: World): void {
|
|
2389
|
+
const worldId = preparedWorlds.indexOf(world);
|
|
2390
|
+
const allocator = internals.getPipelineState()?.skinPaletteAllocator;
|
|
2391
|
+
if (allocator !== undefined && allocator !== null) {
|
|
2392
|
+
for (const slot of persistentRenderScene.compositionSlots()) {
|
|
2393
|
+
if (slot.worldId === worldId && slot.snapshot.skin !== undefined)
|
|
2394
|
+
allocator.releasePersistentSlice(slot.snapshot.skin.identity);
|
|
2395
|
+
}
|
|
2396
|
+
}
|
|
2529
2397
|
persistentRenderScene.detach(world);
|
|
2530
2398
|
},
|
|
2531
2399
|
draw(
|
|
@@ -2543,8 +2411,7 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
2543
2411
|
let submitted = false;
|
|
2544
2412
|
// A failed draw must never leave a previous frame eligible to publish a
|
|
2545
2413
|
// newly accepted dynamic-geometry candidate.
|
|
2546
|
-
|
|
2547
|
-
const frameConsumedDynamicGeometryBindings = new WeakMap<World, Map<number, number>>();
|
|
2414
|
+
dynamicGeometryFrames.begin();
|
|
2548
2415
|
if (profileSession !== undefined && opts.profileFrame === undefined) {
|
|
2549
2416
|
try {
|
|
2550
2417
|
ownsProfileFrame = profileSession.beginFrame(++directFrameId).ok;
|
|
@@ -2557,7 +2424,7 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
2557
2424
|
// cameraOwner drives the surfaced cameras + frustum
|
|
2558
2425
|
// cull; resourceOwner drives skylight/skybox/postProcess + per-world
|
|
2559
2426
|
// record config.
|
|
2560
|
-
const { cameraOwner, resourceOwner } = composition.owners;
|
|
2427
|
+
const { cameraOwner, resourceOwner, cameraEntityKey } = composition.owners;
|
|
2561
2428
|
// Keep the compiled graph as last-known-good until the candidate topology
|
|
2562
2429
|
// compiles. The failed candidate frame does not execute it; successful
|
|
2563
2430
|
// replacement retires it atomically in ensureCompiledFrameGraph.
|
|
@@ -2571,37 +2438,20 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
2571
2438
|
}
|
|
2572
2439
|
dispatchCounts.unlit = 0;
|
|
2573
2440
|
|
|
2574
|
-
// feat-20260708-composited-multi-world-rendering M3 / D-2 / m3-i2:
|
|
2575
|
-
// extractFrames merges per-world snapshots (renderables + lights from
|
|
2576
|
-
// every world, cameras + singleton resources from the owner world),
|
|
2577
|
-
// runs read-only extractFrame per world over the already-updated World,
|
|
2578
|
-
// resets frame state once, and isolates
|
|
2579
|
-
// per-world errors (AC-09).
|
|
2580
|
-
// Single-world draw([world], { cameraOwner: 0, resourceOwner: 0 }) is the identity path
|
|
2581
|
-
// (worldId=0), byte-for-byte equivalent to the pre-M3 direct
|
|
2582
|
-
// extractFrame path (AC-03 regression guarantee).
|
|
2583
|
-
//
|
|
2584
|
-
// Entry validation (empty worlds / owner out of range) is enforced by
|
|
2585
|
-
// the public renderer.draw facade (createRenderer.ts, D-5) before this
|
|
2586
|
-
// internal method is reached; the owner world is guaranteed present.
|
|
2587
|
-
//
|
|
2588
|
-
// feat-20260709-editor-world-partition M1 / w5+w6 (D-3): per-world
|
|
2589
|
-
// record configuration (transparent-sort mode, fold buckets, skybox /
|
|
2590
|
-
// asset resolution) is read from the resource-owner world — the world
|
|
2591
|
-
// that owns skylight / skybox / postProcessParams. w6 sources it from
|
|
2592
|
-
// the dedicated resourceOwner index. The variable is named
|
|
2593
|
-
// `resourceWorld` so the record-stage reads are self-describing (they
|
|
2594
|
-
// are resource-owner reads, not camera reads).
|
|
2595
2441
|
const resourceWorld = compositionWorlds[resourceOwner] as World;
|
|
2596
2442
|
const frame = runProfiledRenderPhase(profileSession, 'extract', () => {
|
|
2597
2443
|
return persistentRenderScene.extractComposition(
|
|
2598
2444
|
compositionWorlds,
|
|
2599
2445
|
{ cameraOwner, resourceOwner },
|
|
2600
2446
|
internals.assets.catalogEpoch,
|
|
2601
|
-
(
|
|
2447
|
+
(renderables) =>
|
|
2602
2448
|
extractFrames(
|
|
2603
2449
|
compositionWorlds,
|
|
2604
|
-
{
|
|
2450
|
+
{
|
|
2451
|
+
cameraOwner,
|
|
2452
|
+
resourceOwner,
|
|
2453
|
+
...(cameraEntityKey === undefined ? {} : { cameraEntityKey }),
|
|
2454
|
+
},
|
|
2605
2455
|
internals.assets,
|
|
2606
2456
|
internals.getPipelineState(),
|
|
2607
2457
|
persistentRenderScene.materialSnapshotCacheStore(),
|
|
@@ -2626,13 +2476,11 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
2626
2476
|
},
|
|
2627
2477
|
}),
|
|
2628
2478
|
cull: 'none',
|
|
2629
|
-
renderables: request === 'none' ? 'none' : 'full',
|
|
2630
|
-
...(request === 'none' || request === 'full'
|
|
2631
|
-
? {}
|
|
2632
|
-
: { renderableEntitiesByWorld: request.entitiesByWorld }),
|
|
2633
2479
|
retainHidden: true,
|
|
2480
|
+
renderables,
|
|
2634
2481
|
instanceCollections,
|
|
2635
|
-
...(internals.
|
|
2482
|
+
...(!internals.device.caps.storageBuffer ||
|
|
2483
|
+
internals.getMaterialShaderArtifact === undefined
|
|
2636
2484
|
? {}
|
|
2637
2485
|
: { getMaterialShaderArtifact: internals.getMaterialShaderArtifact }),
|
|
2638
2486
|
},
|
|
@@ -2641,7 +2489,7 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
2641
2489
|
);
|
|
2642
2490
|
});
|
|
2643
2491
|
const {
|
|
2644
|
-
cameras,
|
|
2492
|
+
cameras: extractedCameras,
|
|
2645
2493
|
cubeCameras,
|
|
2646
2494
|
lights,
|
|
2647
2495
|
environment,
|
|
@@ -2649,6 +2497,9 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
2649
2497
|
volumetricFog,
|
|
2650
2498
|
renderables,
|
|
2651
2499
|
dispatch,
|
|
2500
|
+
shadowCasterEntityKeys: extractedShadowCasterEntityKeys,
|
|
2501
|
+
shadowCasterDrawKeys: extractedShadowCasterDrawKeys,
|
|
2502
|
+
shadowCasterMembership: extractedShadowCasterMembership,
|
|
2652
2503
|
skylight,
|
|
2653
2504
|
skylightCount,
|
|
2654
2505
|
skybox,
|
|
@@ -2658,6 +2509,28 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
2658
2509
|
visibilityStats,
|
|
2659
2510
|
postProcessParams,
|
|
2660
2511
|
} = frame;
|
|
2512
|
+
const cameras = extractedCameras;
|
|
2513
|
+
const preparedOutput = prepareStandardOutputResources(
|
|
2514
|
+
frameState,
|
|
2515
|
+
internals,
|
|
2516
|
+
cameras[0],
|
|
2517
|
+
compositionWorlds[cameraOwner] as World,
|
|
2518
|
+
);
|
|
2519
|
+
if (!preparedOutput.ok) {
|
|
2520
|
+
internals.errorRegistry.fire(preparedOutput.error);
|
|
2521
|
+
return false;
|
|
2522
|
+
}
|
|
2523
|
+
const stableShadowOwnership = rebaseShadowCasterOwnership(
|
|
2524
|
+
compositionWorlds,
|
|
2525
|
+
persistentRenderScene.visibilityWorldKeysFor(compositionWorlds),
|
|
2526
|
+
extractedShadowCasterEntityKeys,
|
|
2527
|
+
extractedShadowCasterDrawKeys,
|
|
2528
|
+
extractedShadowCasterMembership,
|
|
2529
|
+
);
|
|
2530
|
+
const shadowCasterEntityKeys = stableShadowOwnership.entityKeys;
|
|
2531
|
+
const shadowCasterDrawKeys = stableShadowOwnership.drawKeys;
|
|
2532
|
+
const shadowCasterMembership = stableShadowOwnership.membership;
|
|
2533
|
+
const shadowCasterProjection = persistentRenderScene.shadowCasterProjection();
|
|
2661
2534
|
lastDirectionalShadowLights = lights;
|
|
2662
2535
|
lastDirectionalShadowCandidate = 'failed';
|
|
2663
2536
|
lastDirectionalShadowError = lights.directionalShadowError;
|
|
@@ -2669,6 +2542,26 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
2669
2542
|
skylight,
|
|
2670
2543
|
);
|
|
2671
2544
|
latestCamera = cameras[0];
|
|
2545
|
+
frameState.ssrRequested = latestCamera?.screenSpaceReflection !== undefined;
|
|
2546
|
+
// Resolve before a committed fallback change resets accumulation.
|
|
2547
|
+
// Fresh spatial SSR does not require a previous temporal submission.
|
|
2548
|
+
// Inspection uses the read-only projection above and never resets state.
|
|
2549
|
+
const ssrDependencies = resolveSsrDependencies(frameState.ssrRequested);
|
|
2550
|
+
const reset = resolveSsrAdmissionGeneration(
|
|
2551
|
+
ssrFallbackGeneration,
|
|
2552
|
+
ssrDependencies.reflectionFallback?.projectionGeneration,
|
|
2553
|
+
);
|
|
2554
|
+
if (reset.changed) {
|
|
2555
|
+
frameState.temporalFrameTransaction.reset('signature-change');
|
|
2556
|
+
frameState.temporalFrame = undefined;
|
|
2557
|
+
frameState.temporalFrameInput = undefined;
|
|
2558
|
+
frameState.lastSuccessfulTemporalView = undefined;
|
|
2559
|
+
frameState.successfulTemporalFrameIndex = 0;
|
|
2560
|
+
frameState.pendingTemporalCommit = { kind: 'none' };
|
|
2561
|
+
frameState.ssrHistoryOwner?.reset('reflection-generation');
|
|
2562
|
+
frameState.ssrHistoryCandidate = undefined;
|
|
2563
|
+
}
|
|
2564
|
+
ssrFallbackGeneration = reset.generation;
|
|
2672
2565
|
persistentRenderScene.updateVisibilityFacet(compositionWorlds, latestCamera, renderables);
|
|
2673
2566
|
let occlusionProjection:
|
|
2674
2567
|
| import('./scene/visibility/occlusion-runtime').OcclusionFrameProjection
|
|
@@ -2940,6 +2833,9 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
2940
2833
|
if (temporalDemanded) {
|
|
2941
2834
|
persistentRenderScene.prepareTemporalFrame(submissionRenderables);
|
|
2942
2835
|
}
|
|
2836
|
+
frameState.environmentFrame = environment as
|
|
2837
|
+
| import('./environment/frame').SelectedEnvironmentFrame
|
|
2838
|
+
| undefined;
|
|
2943
2839
|
environmentLifecycle.bindScope(internals.deviceScope);
|
|
2944
2840
|
if (fogFailure !== undefined) {
|
|
2945
2841
|
environmentLifecycle.recordSelectionFailure(fogFailure);
|
|
@@ -2970,8 +2866,8 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
2970
2866
|
updateTransmissionInspection(transmissionAntialias, false);
|
|
2971
2867
|
return false;
|
|
2972
2868
|
}
|
|
2973
|
-
if (
|
|
2974
|
-
|
|
2869
|
+
if (lastMeshMaterialBindingRenderables !== renderables) {
|
|
2870
|
+
lastMeshMaterialBindingRenderables = renderables;
|
|
2975
2871
|
lastMeshMaterialBindings = renderables.map((renderable) => {
|
|
2976
2872
|
const materialWorld = preparedWorlds[renderable.worldId];
|
|
2977
2873
|
return projectMeshMaterialBindingObservation({
|
|
@@ -3024,6 +2920,15 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
3024
2920
|
lastFrustumStats.culled = frustumStats.culled;
|
|
3025
2921
|
lastFrustumStats.total = frustumStats.total;
|
|
3026
2922
|
lastVisibilityStats.explicitlyHidden = visibilityStats.explicitlyHidden;
|
|
2923
|
+
if (frame.materialTextureSources !== undefined) {
|
|
2924
|
+
lastMaterialTextureSources = Object.freeze({
|
|
2925
|
+
sourceFieldsVisited: frame.materialTextureSources.sourceFieldsVisited,
|
|
2926
|
+
numericSharedRefProbes: frame.materialTextureSources.numericSharedRefProbes,
|
|
2927
|
+
sourceCacheHits: frame.materialTextureSources.sourceCacheHits,
|
|
2928
|
+
sourceCacheMisses: frame.materialTextureSources.sourceCacheMisses,
|
|
2929
|
+
producerRoutes: Object.freeze({ ...frame.materialTextureSources.producerRoutes }),
|
|
2930
|
+
});
|
|
2931
|
+
}
|
|
3027
2932
|
const featureTargets =
|
|
3028
2933
|
preparedPipelineState === null || cameras[0] === undefined
|
|
3029
2934
|
? []
|
|
@@ -3034,6 +2939,11 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
3034
2939
|
storageBuffer: internals.device.caps.storageBuffer,
|
|
3035
2940
|
multisample: internals.device.caps.backendKind !== 'wgpu-webgl2',
|
|
3036
2941
|
});
|
|
2942
|
+
preparedFeatureSkylightResources =
|
|
2943
|
+
preparedPipelineState === null
|
|
2944
|
+
? undefined
|
|
2945
|
+
: resolveMaterialSkylight(internals, preparedPipelineState, skylight, skylightCount)
|
|
2946
|
+
.skylightResources;
|
|
3037
2947
|
let featureGraphCandidate: RenderFeatureGraphCandidate | undefined;
|
|
3038
2948
|
const preparedResourceBatches = runProfiledRenderPhase(profileSession, 'features', () => {
|
|
3039
2949
|
if (internals.featureHost === undefined) return [];
|
|
@@ -3049,6 +2959,28 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
3049
2959
|
...(internals.getMaterialShaderBindingContract === undefined
|
|
3050
2960
|
? {}
|
|
3051
2961
|
: { materialShaderBindingContract: internals.getMaterialShaderBindingContract }),
|
|
2962
|
+
...(preparedPipelineState === null
|
|
2963
|
+
? {}
|
|
2964
|
+
: {
|
|
2965
|
+
preparedDataInterfaces: {
|
|
2966
|
+
camera: {
|
|
2967
|
+
kind: 'buffer' as const,
|
|
2968
|
+
value: preparedPipelineState.viewUniformBuffer,
|
|
2969
|
+
size: 64,
|
|
2970
|
+
usage: 'uniform' as const,
|
|
2971
|
+
},
|
|
2972
|
+
'scene-depth': {
|
|
2973
|
+
kind: 'texture-view' as const,
|
|
2974
|
+
value: preparedPipelineState.shadowFallbackTextureView,
|
|
2975
|
+
},
|
|
2976
|
+
get noise() {
|
|
2977
|
+
const value = resolveFeatureNoise(frameState.frameNumber);
|
|
2978
|
+
return value === undefined
|
|
2979
|
+
? undefined
|
|
2980
|
+
: { kind: 'texture-view' as const, value };
|
|
2981
|
+
},
|
|
2982
|
+
},
|
|
2983
|
+
}),
|
|
3052
2984
|
createPreparedGraphicsResolver: preparedResolverFactory,
|
|
3053
2985
|
gpuWork: featureGpuWork,
|
|
3054
2986
|
});
|
|
@@ -3072,10 +3004,11 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
3072
3004
|
featureGraphCandidate = {
|
|
3073
3005
|
plans: featureFrame.plans,
|
|
3074
3006
|
fullscreenEffects: featureFrame.fullscreenEffects,
|
|
3075
|
-
...(featureFrame.
|
|
3076
|
-
? {}
|
|
3077
|
-
: {
|
|
3007
|
+
...(featureFrame.requiresPreparedResourceKey
|
|
3008
|
+
? { preparedResourceKey: `frame-${frameState.frameNumber}` }
|
|
3009
|
+
: {}),
|
|
3078
3010
|
onRejected: () => {
|
|
3011
|
+
featureFrame.onAborted();
|
|
3079
3012
|
for (const batch of featureFrame.preparedResourceBatches) {
|
|
3080
3013
|
const released = batch.release();
|
|
3081
3014
|
if (!released.ok) {
|
|
@@ -3085,8 +3018,15 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
3085
3018
|
discardPostProcessParamsCandidate(postProcessParamsCandidate.value);
|
|
3086
3019
|
},
|
|
3087
3020
|
onAbandoned: () => {
|
|
3021
|
+
featureFrame.onAborted();
|
|
3088
3022
|
discardPostProcessParamsCandidate(postProcessParamsCandidate.value);
|
|
3089
3023
|
},
|
|
3024
|
+
onSubmitted: () => {
|
|
3025
|
+
featureFrame.onSubmitted();
|
|
3026
|
+
},
|
|
3027
|
+
onAborted: () => {
|
|
3028
|
+
featureFrame.onAborted();
|
|
3029
|
+
},
|
|
3090
3030
|
onAccepted: () => {
|
|
3091
3031
|
for (const [id, previous] of activeFeaturePostProcessEntries) {
|
|
3092
3032
|
const next = featureFrame.fullscreenEffects.get(id);
|
|
@@ -3107,6 +3047,7 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
3107
3047
|
activeFeaturePostProcessEntries = featureFrame.fullscreenEffects;
|
|
3108
3048
|
},
|
|
3109
3049
|
};
|
|
3050
|
+
recordRenderFeatureCandidate(internals, featureGraphCandidate);
|
|
3110
3051
|
return featureFrame.preparedResourceBatches;
|
|
3111
3052
|
});
|
|
3112
3053
|
|
|
@@ -3184,13 +3125,32 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
3184
3125
|
if (cameras[0]?.bloom === 'on') {
|
|
3185
3126
|
internals.getPipelineState()?.perPassResources.ensureBloomResources?.();
|
|
3186
3127
|
}
|
|
3128
|
+
const liveOutput = cameras[0]?.output;
|
|
3129
|
+
const hasLiveFeatureState =
|
|
3130
|
+
liveOutput !== undefined ||
|
|
3131
|
+
frameState.autoExposureGpuResources !== undefined ||
|
|
3132
|
+
frameState.pendingAutoExposureGpuResources !== undefined ||
|
|
3133
|
+
frameState.autoExposureState !== undefined ||
|
|
3134
|
+
frameState.pendingAutoExposureState !== undefined ||
|
|
3135
|
+
frameState.standardLutGpuResources !== undefined ||
|
|
3136
|
+
frameState.pendingStandardLutGpuResources !== undefined ||
|
|
3137
|
+
frameState.standardLutState.resident !== null ||
|
|
3138
|
+
frameState.pendingStandardLutState !== undefined;
|
|
3139
|
+
if (hasLiveFeatureState) {
|
|
3140
|
+
const cameraWorld = compositionWorlds[cameraOwner] as World;
|
|
3141
|
+
const deltaTime = cameraWorld.getResource(Time).delta;
|
|
3142
|
+
stageLiveFeatureState(
|
|
3143
|
+
cameras[0],
|
|
3144
|
+
Number.isFinite(deltaTime) ? Math.max(0, deltaTime) : 0,
|
|
3145
|
+
);
|
|
3146
|
+
}
|
|
3187
3147
|
submitted = runProfiledRenderPhase(profileSession, 'record', () =>
|
|
3188
3148
|
recordFrame(
|
|
3189
3149
|
internals,
|
|
3190
3150
|
resourceWorld,
|
|
3191
3151
|
cameras,
|
|
3192
3152
|
lights,
|
|
3193
|
-
|
|
3153
|
+
submissionRenderables,
|
|
3194
3154
|
orderedDispatch,
|
|
3195
3155
|
frameState,
|
|
3196
3156
|
dispatchCounts,
|
|
@@ -3226,32 +3186,20 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
3226
3186
|
environment?.fogSignature ?? '',
|
|
3227
3187
|
environmentReady && environment !== undefined,
|
|
3228
3188
|
persistentRenderScene.transmissionTopologyDemand(),
|
|
3189
|
+
shadowCasterEntityKeys,
|
|
3190
|
+
shadowCasterDrawKeys,
|
|
3229
3191
|
volumetricFog,
|
|
3230
3192
|
timingCapture,
|
|
3231
|
-
|
|
3232
|
-
|
|
3233
|
-
|
|
3234
|
-
|
|
3235
|
-
|
|
3236
|
-
|
|
3237
|
-
bindings = new Map();
|
|
3238
|
-
frameConsumedDynamicGeometryBindings.set(world, bindings);
|
|
3239
|
-
}
|
|
3240
|
-
bindings.set(renderable.entityKey, renderable.assetHandle);
|
|
3241
|
-
},
|
|
3193
|
+
shadowCasterMembership,
|
|
3194
|
+
shadowCasterProjection,
|
|
3195
|
+
worldKeys,
|
|
3196
|
+
undefined,
|
|
3197
|
+
ssrDependencies,
|
|
3198
|
+
dynamicGeometryFrames.onRenderableDraw(compositionWorlds),
|
|
3242
3199
|
),
|
|
3243
3200
|
);
|
|
3244
|
-
|
|
3245
|
-
|
|
3246
|
-
}
|
|
3247
|
-
if (submitted) {
|
|
3248
|
-
try {
|
|
3249
|
-
internals.recoveryColdWorkGuard?.finish();
|
|
3250
|
-
} catch (cause) {
|
|
3251
|
-
submitted = false;
|
|
3252
|
-
throw cause;
|
|
3253
|
-
}
|
|
3254
|
-
}
|
|
3201
|
+
dynamicGeometryFrames.commit(submitted);
|
|
3202
|
+
if (!submitted) discardLiveFeatureState();
|
|
3255
3203
|
if (submitted && lastLodOcclusionInspection !== undefined) {
|
|
3256
3204
|
const query = ensureOcclusionRuntime().inspect();
|
|
3257
3205
|
lastLodOcclusionInspection = {
|
|
@@ -3346,6 +3294,7 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
3346
3294
|
}
|
|
3347
3295
|
}
|
|
3348
3296
|
} catch (err) {
|
|
3297
|
+
discardLiveFeatureState();
|
|
3349
3298
|
if (!submitted) {
|
|
3350
3299
|
internals.getPipelineState()?.perPassResources.discardBloomResources?.();
|
|
3351
3300
|
}
|
|
@@ -3359,7 +3308,11 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
3359
3308
|
}
|
|
3360
3309
|
: err instanceof RhiError
|
|
3361
3310
|
? err
|
|
3362
|
-
: {
|
|
3311
|
+
: {
|
|
3312
|
+
code: 'unknown' as const,
|
|
3313
|
+
message: String(err),
|
|
3314
|
+
name: (err as Error)?.name,
|
|
3315
|
+
};
|
|
3363
3316
|
internals.errorRegistry.fire(
|
|
3364
3317
|
new RhiError({
|
|
3365
3318
|
code: 'webgpu-runtime-error',
|
|
@@ -3379,14 +3332,8 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
3379
3332
|
}
|
|
3380
3333
|
return submitted;
|
|
3381
3334
|
},
|
|
3382
|
-
isDynamicGeometryConsumed(
|
|
3383
|
-
world
|
|
3384
|
-
entity: number,
|
|
3385
|
-
meshHandle: number | undefined,
|
|
3386
|
-
): boolean {
|
|
3387
|
-
if (!Number.isInteger(entity) || meshHandle === undefined) return false;
|
|
3388
|
-
return lastSubmittedDynamicGeometryBindings.get(world)?.get(entity) === meshHandle;
|
|
3389
|
-
},
|
|
3335
|
+
isDynamicGeometryConsumed: (world, entity, meshHandle) =>
|
|
3336
|
+
dynamicGeometryFrames.isConsumed(world, entity, meshHandle),
|
|
3390
3337
|
pipelineDispatchCounts: dispatchCounts,
|
|
3391
3338
|
observeCurrentFrame(options: FrameObservationOptions) {
|
|
3392
3339
|
const currentFrameId = frameState.frameNumber - 1;
|
|
@@ -3457,6 +3404,12 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
3457
3404
|
get perFrameGraphInfo(): CompiledRenderGraphInfo | undefined {
|
|
3458
3405
|
return frameState.compiledFrameGraph?.inspect();
|
|
3459
3406
|
},
|
|
3407
|
+
get featureGraphInspection(): import('./inspection-types').RenderFeatureGraphInspection {
|
|
3408
|
+
return getRenderFeatureGraphInspection(internals);
|
|
3409
|
+
},
|
|
3410
|
+
get materialTextureSources(): MaterialTextureSourceInspection {
|
|
3411
|
+
return lastMaterialTextureSources;
|
|
3412
|
+
},
|
|
3460
3413
|
get recoveryEvidence(): RecoveryProductionEvidence {
|
|
3461
3414
|
const graph = frameState.compiledFrameGraph?.inspect();
|
|
3462
3415
|
return Object.freeze({
|
|
@@ -3583,6 +3536,7 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
3583
3536
|
(internals as TimingSessionHost).gpuPassTimingSubmittedWork = undefined;
|
|
3584
3537
|
(internals as TimingSessionHost).gpuPassTimingFrameIdentity = undefined;
|
|
3585
3538
|
(internals as TimingSessionHost).gpuPassTimingBeginReason = undefined;
|
|
3539
|
+
internals.getPipelineState()?.skinPaletteAllocator?.dispose();
|
|
3586
3540
|
pointsLinesOwner.dispose();
|
|
3587
3541
|
persistentRenderScene.dispose();
|
|
3588
3542
|
instanceCollections.dispose();
|
|
@@ -3590,6 +3544,10 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
3590
3544
|
occlusionRuntime?.dispose();
|
|
3591
3545
|
disposeFeatureGpuWork();
|
|
3592
3546
|
reflectionProbeOwner.dispose();
|
|
3547
|
+
frameState.ssrHistoryOwner?.dispose();
|
|
3548
|
+
frameState.ssrHistoryOwner = undefined;
|
|
3549
|
+
frameState.ssrHistoryCandidate = undefined;
|
|
3550
|
+
frameState.ssrSpatialAdmission = undefined;
|
|
3593
3551
|
// Bloom generations are renderer-owned rather than graph-owned. Drain
|
|
3594
3552
|
// candidate, active, and fence-retiring bundles before the rest of the
|
|
3595
3553
|
// frame state is torn down; the owner callback is idempotent so the
|
|
@@ -3610,6 +3568,19 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
3610
3568
|
frameState.lastSuccessfulCameraAntialias = undefined;
|
|
3611
3569
|
frameState.currentDirectionalShadowView = null;
|
|
3612
3570
|
frameState.currentSpotShadowView = null;
|
|
3571
|
+
if (frameState.pendingAutoExposureGpuResources !== undefined) {
|
|
3572
|
+
retireAutoExposureGpuResources(frameState.pendingAutoExposureGpuResources);
|
|
3573
|
+
frameState.pendingAutoExposureGpuResources = undefined;
|
|
3574
|
+
}
|
|
3575
|
+
if (frameState.autoExposureGpuResources !== undefined) {
|
|
3576
|
+
retireAutoExposureGpuResources(frameState.autoExposureGpuResources);
|
|
3577
|
+
frameState.autoExposureGpuResources = undefined;
|
|
3578
|
+
}
|
|
3579
|
+
frameState.autoExposureState = undefined;
|
|
3580
|
+
frameState.pendingAutoExposureState = undefined;
|
|
3581
|
+
frameState.pendingStandardLutGpuResources = undefined;
|
|
3582
|
+
frameState.standardLutGpuResources = undefined;
|
|
3583
|
+
frameState.pendingStandardLutState = undefined;
|
|
3613
3584
|
if (frameState.temporalGpuState !== undefined) {
|
|
3614
3585
|
retireTemporalGpuState(frameState.temporalGpuState);
|
|
3615
3586
|
frameState.temporalGpuState = undefined;
|
|
@@ -3655,7 +3626,6 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
3655
3626
|
// so destroy failures fire structured errors (unified per-frame +
|
|
3656
3627
|
// dispose error strategy).
|
|
3657
3628
|
disposeInstanceBuffers(frameState.instanceBuffers, internals.errorRegistry);
|
|
3658
|
-
frameState.instanceResidency?.clear();
|
|
3659
3629
|
if (frameState.instanceBufferChunks !== undefined) {
|
|
3660
3630
|
disposeInstanceBufferChunks(frameState.instanceBufferChunks, internals.errorRegistry);
|
|
3661
3631
|
}
|
|
@@ -3696,9 +3666,8 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
3696
3666
|
// their handles without invoking destroy on a device that can no longer
|
|
3697
3667
|
// service cleanup; the staged candidate owns the replacement buffers.
|
|
3698
3668
|
pointsLinesOwner.abandonForDeviceLoss();
|
|
3699
|
-
|
|
3700
|
-
|
|
3701
|
-
ssrFormatProbe = undefined;
|
|
3669
|
+
resetStandardOutputForDeviceLoss(frameState, internals.deviceScope.generation);
|
|
3670
|
+
ssrFormatReceipts.delete(internals.device);
|
|
3702
3671
|
ssrFallbackGeneration = undefined;
|
|
3703
3672
|
transmissionAdmission.markDeviceLost();
|
|
3704
3673
|
lastTransmissionKey = '';
|
|
@@ -3716,13 +3685,11 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
3716
3685
|
updateTransmissionInspection(lastTransmissionAntialias, false);
|
|
3717
3686
|
persistentRenderScene.resetGpuForRecover();
|
|
3718
3687
|
gpuDrivenProduction.dispose();
|
|
3719
|
-
|
|
3720
|
-
|
|
3721
|
-
// explicitly so the first published draw never routes through an owner
|
|
3722
|
-
// recreated against the old physical device.
|
|
3723
|
-
gpuDrivenProduction = GpuDrivenProduction.forDevice(
|
|
3688
|
+
gpuDrivenRecoveryCount += 1;
|
|
3689
|
+
gpuDrivenProduction = createGpuDrivenOwner(
|
|
3724
3690
|
replacementDevice ?? internals.device,
|
|
3725
3691
|
gpuDrivenShaderFactory,
|
|
3692
|
+
gpuDrivenRecoveryCount,
|
|
3726
3693
|
);
|
|
3727
3694
|
occlusionRuntime?.dispose();
|
|
3728
3695
|
// The replacement device is installed by the host after this hook. Do
|
|
@@ -3732,6 +3699,13 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
3732
3699
|
disposeFeatureGpuWork();
|
|
3733
3700
|
featureGpuWork = createFeatureGpuWorkOwner(internals);
|
|
3734
3701
|
reflectionProbeOwner.dispose();
|
|
3702
|
+
frameState.ssrHistoryOwner?.dispose();
|
|
3703
|
+
frameState.ssrHistoryOwner = undefined;
|
|
3704
|
+
frameState.ssrHistoryCandidate = undefined;
|
|
3705
|
+
frameState.ssrSpatialAdmission = undefined;
|
|
3706
|
+
frameState.ssrRequested = false;
|
|
3707
|
+
frameState.ssrLastCameraEntity = undefined;
|
|
3708
|
+
frameState.ssrLastHistoryVersion = undefined;
|
|
3735
3709
|
// A recovered device cannot retain handles from the lost device. The
|
|
3736
3710
|
// Bloom owner abandons candidates and retires every committed generation
|
|
3737
3711
|
// before the new PipelineState is rebuilt.
|
|
@@ -3801,7 +3775,7 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
3801
3775
|
frameState.retiredCompiledFrameGraphs.clear();
|
|
3802
3776
|
frameState.instanceBuffers.clear();
|
|
3803
3777
|
frameState.instanceBufferChunks?.clear();
|
|
3804
|
-
|
|
3778
|
+
instanceCollections._resetResidency();
|
|
3805
3779
|
delete frameState.probeBlendRecordBuffer;
|
|
3806
3780
|
frameState.probeBlendRecordBufferCapacity = 0;
|
|
3807
3781
|
frameState.probeBlendBuffers.clear();
|
|
@@ -3844,124 +3818,9 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
3844
3818
|
publishRecoveryPostProcessResources(prepared.value);
|
|
3845
3819
|
},
|
|
3846
3820
|
prepareRecoveryRoots(runtime: RecoveryRootRuntime): RecoveryRootBundle {
|
|
3847
|
-
|
|
3848
|
-
|
|
3849
|
-
|
|
3850
|
-
const candidateEnvironmentLifecycle = environmentLifecycle.createRecoveryCandidate(
|
|
3851
|
-
runtime.scope,
|
|
3852
|
-
);
|
|
3853
|
-
const roots: LifecycleResourceSpec<unknown>[] = [];
|
|
3854
|
-
let candidateEnvironmentGeneration: EnvironmentGeneration | undefined;
|
|
3855
|
-
let environmentRootCleaned = false;
|
|
3856
|
-
let published = false;
|
|
3857
|
-
if (candidateEnvironmentLifecycle.hasRecoveryFrame()) {
|
|
3858
|
-
const environmentRoot = candidateEnvironmentLifecycle.createRecoveryRoot(runtime.scope);
|
|
3859
|
-
roots.push({
|
|
3860
|
-
...environmentRoot,
|
|
3861
|
-
create: async () => {
|
|
3862
|
-
const generation = (await environmentRoot.create()) as EnvironmentGeneration;
|
|
3863
|
-
candidateEnvironmentGeneration = generation;
|
|
3864
|
-
return generation;
|
|
3865
|
-
},
|
|
3866
|
-
cleanup: (value) => {
|
|
3867
|
-
if (environmentRootCleaned) return;
|
|
3868
|
-
environmentRootCleaned = true;
|
|
3869
|
-
if (candidateEnvironmentGeneration === value) {
|
|
3870
|
-
candidateEnvironmentGeneration = undefined;
|
|
3871
|
-
}
|
|
3872
|
-
if (published) {
|
|
3873
|
-
candidateEnvironmentLifecycle.retirePublishedGeneration(
|
|
3874
|
-
value as EnvironmentGeneration,
|
|
3875
|
-
);
|
|
3876
|
-
} else {
|
|
3877
|
-
environmentRoot.cleanup(value);
|
|
3878
|
-
}
|
|
3879
|
-
},
|
|
3880
|
-
});
|
|
3881
|
-
}
|
|
3882
|
-
const graphCandidate = runtime.graphCandidate;
|
|
3883
|
-
if (graphCandidate !== undefined) {
|
|
3884
|
-
const releaseGraphCandidate = (): void => graphCandidate.release();
|
|
3885
|
-
const compiledGraph = graphCandidate.frameState.compiledFrameGraph;
|
|
3886
|
-
if (compiledGraph !== null) {
|
|
3887
|
-
roots.push({
|
|
3888
|
-
kind: 'pipeline',
|
|
3889
|
-
create: () => {
|
|
3890
|
-
if (!runtime.scope.isAlive()) {
|
|
3891
|
-
throw new Error('Recovery graph candidate scope is not active.');
|
|
3892
|
-
}
|
|
3893
|
-
if (graphCandidate.frameState.compiledFrameGraph !== compiledGraph) {
|
|
3894
|
-
throw new Error('Recovery graph candidate was changed before aggregate assembly.');
|
|
3895
|
-
}
|
|
3896
|
-
return compiledGraph;
|
|
3897
|
-
},
|
|
3898
|
-
// All graph/feature/GPU-driven candidate resources share one
|
|
3899
|
-
// owner. The root is a real release seam, not a marker; the
|
|
3900
|
-
// candidate latch makes every root cleanup call harmless after
|
|
3901
|
-
// the first one.
|
|
3902
|
-
cleanup: releaseGraphCandidate,
|
|
3903
|
-
});
|
|
3904
|
-
}
|
|
3905
|
-
if (graphCandidate.featureHost !== undefined) {
|
|
3906
|
-
const featureRoot = graphCandidate.featureHost.createRecoveryRoot(runtime.scope);
|
|
3907
|
-
roots.push({ ...featureRoot, cleanup: releaseGraphCandidate });
|
|
3908
|
-
}
|
|
3909
|
-
if (graphCandidate.featureGpuWork !== undefined) {
|
|
3910
|
-
const featureWorkRoot = graphCandidate.featureGpuWork.createRecoveryRoot(runtime.scope);
|
|
3911
|
-
roots.push({ ...featureWorkRoot, cleanup: releaseGraphCandidate });
|
|
3912
|
-
}
|
|
3913
|
-
if (graphCandidate.gpuDrivenProduction !== undefined) {
|
|
3914
|
-
const productionRoot = graphCandidate.gpuDrivenProduction.createRecoveryRoot(
|
|
3915
|
-
runtime.scope,
|
|
3916
|
-
);
|
|
3917
|
-
roots.push({ ...productionRoot, cleanup: releaseGraphCandidate });
|
|
3918
|
-
}
|
|
3919
|
-
if (graphCandidate.gpuDrivenScene?.state !== undefined) {
|
|
3920
|
-
const sceneRoot = graphCandidate.gpuDrivenScene.createRecoveryRoot(runtime.scope);
|
|
3921
|
-
roots.push({ ...sceneRoot, cleanup: releaseGraphCandidate });
|
|
3922
|
-
}
|
|
3923
|
-
if (graphCandidate.pointsLines !== undefined) {
|
|
3924
|
-
const pointsLinesRoot = graphCandidate.pointsLines.createRecoveryRoot(runtime.scope);
|
|
3925
|
-
roots.push({ ...pointsLinesRoot, cleanup: releaseGraphCandidate });
|
|
3926
|
-
}
|
|
3927
|
-
if (runtime.gpuStore.recoveryResourceCount() > 0) {
|
|
3928
|
-
const gpuStoreRoot = runtime.gpuStore.createRecoveryRoot(runtime.scope);
|
|
3929
|
-
roots.push({ ...gpuStoreRoot, cleanup: releaseGraphCandidate });
|
|
3930
|
-
}
|
|
3931
|
-
}
|
|
3932
|
-
let discarded = false;
|
|
3933
|
-
return {
|
|
3934
|
-
roots: Object.freeze(roots),
|
|
3935
|
-
publish: () => {
|
|
3936
|
-
if (published || discarded) return;
|
|
3937
|
-
if (
|
|
3938
|
-
candidateEnvironmentGeneration !== undefined &&
|
|
3939
|
-
!candidateEnvironmentGeneration.retired
|
|
3940
|
-
) {
|
|
3941
|
-
environmentLifecycle.retireActiveForReplacement();
|
|
3942
|
-
candidateEnvironmentLifecycle.publish(candidateEnvironmentGeneration);
|
|
3943
|
-
}
|
|
3944
|
-
published = true;
|
|
3945
|
-
environmentLifecycle = candidateEnvironmentLifecycle;
|
|
3946
|
-
Object.assign(frameState, { environmentLifecycle });
|
|
3947
|
-
},
|
|
3948
|
-
discard: () => {
|
|
3949
|
-
if (published || discarded) return;
|
|
3950
|
-
discarded = true;
|
|
3951
|
-
if (candidateEnvironmentGeneration !== undefined) {
|
|
3952
|
-
candidateEnvironmentLifecycle.discard(candidateEnvironmentGeneration);
|
|
3953
|
-
candidateEnvironmentGeneration = undefined;
|
|
3954
|
-
}
|
|
3955
|
-
candidateEnvironmentLifecycle.discardRecoveryCandidates();
|
|
3956
|
-
// The transaction can fail before it reaches any graph root (for
|
|
3957
|
-
// example while the environment root is created). Keep the graph,
|
|
3958
|
-
// feature, GPU-driven, and residency resources on the same real
|
|
3959
|
-
// candidate owner in that case; later scope/factory cleanup is a
|
|
3960
|
-
// harmless repeat through the candidate latch.
|
|
3961
|
-
graphCandidate?.release();
|
|
3962
|
-
runtime.scope.abandon();
|
|
3963
|
-
},
|
|
3964
|
-
};
|
|
3821
|
+
return prepareRenderSystemRecoveryRoots(runtime, environmentLifecycle, frameState, (next) => {
|
|
3822
|
+
environmentLifecycle = next;
|
|
3823
|
+
});
|
|
3965
3824
|
},
|
|
3966
3825
|
};
|
|
3967
3826
|
}
|