@forgeax/engine-render 0.1.27 → 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 +842 -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 +52 -0
- package/dist/assembly/dynamic-geometry-host.d.ts.map +1 -0
- 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 +19 -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 +3 -3
- package/dist/{chunk-ADHHVYLW.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-KM2NOX2I.mjs → chunk-BQVQOQJH.mjs} +958 -254
- package/dist/chunk-BQVQOQJH.mjs.map +1 -0
- package/dist/{chunk-HKXTW355.mjs → chunk-BTWH7BP4.mjs} +386 -17
- package/dist/chunk-BTWH7BP4.mjs.map +1 -0
- package/dist/{chunk-TMIASV2N.mjs → chunk-FUODTTIA.mjs} +3934 -676
- package/dist/chunk-FUODTTIA.mjs.map +1 -0
- package/dist/{chunk-FJ6P52EE.mjs → chunk-ILQ5MEZF.mjs} +3 -17
- package/dist/chunk-ILQ5MEZF.mjs.map +1 -0
- package/dist/{chunk-E34VL5VI.mjs → chunk-JQTSEI3Z.mjs} +3 -3
- package/dist/{chunk-E34VL5VI.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-ZZ4YQ474.mjs → chunk-NRNXBLIJ.mjs} +577 -7
- package/dist/chunk-NRNXBLIJ.mjs.map +1 -0
- package/dist/{chunk-JDWARUOI.mjs → chunk-PA5DRJNI.mjs} +17 -3
- package/dist/chunk-PA5DRJNI.mjs.map +1 -0
- package/dist/{chunk-XDP6XE5V.mjs → chunk-S4DNKQYQ.mjs} +1118 -446
- 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 +13805 -7186
- package/dist/construct-renderer.mjs.map +1 -1
- package/dist/device/gpu-residency.d.ts +11 -17
- package/dist/device/gpu-residency.d.ts.map +1 -1
- package/dist/device/mesh-residency-lifetime.d.ts +21 -0
- package/dist/device/mesh-residency-lifetime.d.ts.map +1 -0
- package/dist/dynamic-geometry.d.ts +125 -0
- package/dist/dynamic-geometry.d.ts.map +1 -0
- 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 +21 -8
- package/dist/index.d.ts.map +1 -1
- package/dist/index.mjs +8 -7
- package/dist/index.mjs.map +1 -1
- 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 +118 -10
- 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 +76 -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 +185 -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 +34 -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__/dynamic-geometry-host.unit.test.ts +1123 -0
- package/src/__tests__/dynamic-geometry.unit.test.ts +233 -0
- package/src/__tests__/factory-contract.integration.test.ts +73 -22
- 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__/mesh-submission-lifetime.unit.test.ts +53 -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 +61 -1
- 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 +887 -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 +36 -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 +29 -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 +675 -614
- 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 +3 -3
- package/src/components/sprite-instances.ts +1 -1
- package/src/device/gpu-residency.ts +96 -93
- package/src/device/mesh-residency-lifetime.ts +73 -0
- package/src/dynamic-geometry.ts +736 -0
- 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 +125 -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 +727 -133
- package/src/record/main-pass-geometry.ts +162 -98
- package/src/record/main-pass-material.ts +115 -26
- package/src/record/main-pass-sprite-draws.ts +18 -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 +92 -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 +1006 -53
- 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 +219 -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 +692 -791
- 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-ADHHVYLW.mjs.map +0 -1
- package/dist/chunk-FJ6P52EE.mjs.map +0 -1
- package/dist/chunk-GE3SDD72.mjs.map +0 -1
- package/dist/chunk-GF523LHF.mjs.map +0 -1
- package/dist/chunk-HKXTW355.mjs.map +0 -1
- package/dist/chunk-JDWARUOI.mjs.map +0 -1
- package/dist/chunk-KM2NOX2I.mjs.map +0 -1
- package/dist/chunk-TMIASV2N.mjs.map +0 -1
- package/dist/chunk-XDP6XE5V.mjs.map +0 -1
- package/dist/chunk-ZZ4YQ474.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
|
-
|
|
250
|
-
interface LodInspectionQuerySummary {
|
|
251
|
-
readonly used: number;
|
|
252
|
-
readonly capacity: number;
|
|
253
|
-
}
|
|
254
297
|
|
|
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
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
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[],
|
|
@@ -667,10 +509,17 @@ export interface RenderSystem {
|
|
|
667
509
|
renderReadLeases?: readonly RenderReadLease[],
|
|
668
510
|
timingCapture?: GpuTimingCapture,
|
|
669
511
|
): boolean;
|
|
512
|
+
/**
|
|
513
|
+
* Return the asset binding consumed by the last successful record pass.
|
|
514
|
+
* Dynamic geometry uses this renderer-owned frame fact as its publication
|
|
515
|
+
* barrier; ECS component presence alone is not a draw receipt.
|
|
516
|
+
*/
|
|
517
|
+
isDynamicGeometryConsumed(world: World, entity: number, meshHandle: number | undefined): boolean;
|
|
518
|
+
invalidateGeometryHistory(): void;
|
|
670
519
|
/** Prepare a detached graph candidate without entering the frame record path. */
|
|
671
520
|
prepareRecoveryGraphCandidate(
|
|
672
521
|
runtime: RecoveryGraphCandidateRuntime,
|
|
673
|
-
):
|
|
522
|
+
): RecoveryGraphCandidatePreparation;
|
|
674
523
|
/** Finish and submit detached candidate setup, never a frame receipt. */
|
|
675
524
|
submitCandidateSetup(
|
|
676
525
|
candidate: RecoveryGraphCandidate,
|
|
@@ -696,6 +545,8 @@ export interface RenderSystem {
|
|
|
696
545
|
readonly pipelineDispatchCounts: {
|
|
697
546
|
readonly unlit: number;
|
|
698
547
|
};
|
|
548
|
+
/** Renderer-owned source for explicit large instance collections. */
|
|
549
|
+
readonly instances: InstanceCollectionStore;
|
|
699
550
|
/** Detached residency and upload facts for explicit instance collections. */
|
|
700
551
|
readonly instanceCollectionsInspection: readonly InstanceCollectionInspection[];
|
|
701
552
|
/**
|
|
@@ -710,11 +561,17 @@ export interface RenderSystem {
|
|
|
710
561
|
readonly reflectionProbes: ReflectionProbeInspection;
|
|
711
562
|
/** Live producer/RHI/temporal receipts projected through SSR admission. */
|
|
712
563
|
readonly ssrDependencies: SsrDependenciesInspection;
|
|
564
|
+
/** Live SSR spatial admission and bounded graph/history projection. */
|
|
565
|
+
readonly ssr: SsrSpatialInspection;
|
|
713
566
|
/** Producer completion fence included in the public FrameReceipt. */
|
|
714
567
|
readonly reflectionFallbackCompletion: Promise<void> | undefined;
|
|
715
568
|
/** True while a progressive CubeCamera candidate still owns unfinished faces. */
|
|
716
569
|
isCubeCapturePending(target: RenderTarget): boolean;
|
|
717
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;
|
|
718
575
|
readonly temporal: TemporalInspection;
|
|
719
576
|
readonly bloom: BloomInspection;
|
|
720
577
|
readonly motionBlurInspection: MotionBlurInspection | undefined;
|
|
@@ -749,6 +606,10 @@ export interface RenderSystem {
|
|
|
749
606
|
readonly lastSuccessfulCameraAntialias: CameraSnapshot['antialias'] | undefined;
|
|
750
607
|
/** Detached compiled-graph facts used by the renderer inspection owner. */
|
|
751
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;
|
|
752
613
|
/** Production-owner recovery facts used by Renderer.inspect(). */
|
|
753
614
|
readonly recoveryEvidence: RecoveryProductionEvidence;
|
|
754
615
|
/**
|
|
@@ -871,13 +732,6 @@ function makePreparedPipelinePendingError(): RhiError {
|
|
|
871
732
|
});
|
|
872
733
|
}
|
|
873
734
|
|
|
874
|
-
/** The single Points/Lines owner’s staged device-generation handoff. */
|
|
875
|
-
export interface RecoveryPointsLinesCandidate {
|
|
876
|
-
createRecoveryRoot(scope: DeviceScope): LifecycleResourceSpec<unknown>;
|
|
877
|
-
publish(): void;
|
|
878
|
-
release(): void;
|
|
879
|
-
}
|
|
880
|
-
|
|
881
735
|
function preparationFailureFrom(error: unknown): MeshMaterialBindingPreparationFailure | undefined {
|
|
882
736
|
if (typeof error !== 'object' || error === null) return undefined;
|
|
883
737
|
const value = error as {
|
|
@@ -905,58 +759,6 @@ function preparationFailureFrom(error: unknown): MeshMaterialBindingPreparationF
|
|
|
905
759
|
};
|
|
906
760
|
}
|
|
907
761
|
|
|
908
|
-
/** Candidate-only device/runtime inputs used by the recovery prepare seam. */
|
|
909
|
-
export interface RecoveryGraphCandidateRuntime {
|
|
910
|
-
readonly internals: RenderSystemInternals;
|
|
911
|
-
readonly pipelineState: PipelineState;
|
|
912
|
-
}
|
|
913
|
-
|
|
914
|
-
/** Detached graph state prepared on a replacement device, before publication. */
|
|
915
|
-
export interface RecoveryGraphCandidate {
|
|
916
|
-
readonly frameState: RenderFrameState;
|
|
917
|
-
readonly setupWorks: readonly MipmapEncoderWork[];
|
|
918
|
-
readonly device: RhiDevice;
|
|
919
|
-
readonly generation: number;
|
|
920
|
-
readonly gpuDrivenProduction?: GpuDrivenProduction;
|
|
921
|
-
readonly gpuDrivenScene?: PersistentGpuDrivenCandidate;
|
|
922
|
-
/** Staged CPU-expanded Points/Lines buffers owned by the same RenderSystem. */
|
|
923
|
-
readonly pointsLines?: RecoveryPointsLinesCandidate;
|
|
924
|
-
readonly featureHost?: RenderFeatureHost;
|
|
925
|
-
readonly featureGpuWork?: RenderFeatureGpuWorkOwner;
|
|
926
|
-
readonly featureGraphCandidate?: RenderFeatureGraphCandidate;
|
|
927
|
-
readonly postProcessPipelines?: ReadonlyMap<string, RenderPipeline>;
|
|
928
|
-
readonly recoveryReadiness: RecoveryPipelineReadiness;
|
|
929
|
-
/** Release all candidate roots before publication; safe to call repeatedly. */
|
|
930
|
-
readonly release: () => void;
|
|
931
|
-
/** Transfer candidate-root ownership to the published RenderSystem. */
|
|
932
|
-
readonly markPublished: () => void;
|
|
933
|
-
}
|
|
934
|
-
|
|
935
|
-
/** Candidate setup completion; completion is bounded by the recovery owner. */
|
|
936
|
-
export interface RecoveryGraphSetupSubmission {
|
|
937
|
-
readonly completion?: PromiseLike<unknown>;
|
|
938
|
-
}
|
|
939
|
-
|
|
940
|
-
export type RecoveryGraphCandidatePreparation =
|
|
941
|
-
| { readonly kind: 'no-seed' }
|
|
942
|
-
| { readonly kind: 'ready'; readonly candidate: RecoveryGraphCandidate }
|
|
943
|
-
| { readonly kind: 'failed'; readonly reason: string; readonly cause?: unknown };
|
|
944
|
-
|
|
945
|
-
/** Explicit candidate-owned inputs for lifecycle-root preparation. */
|
|
946
|
-
export interface RecoveryRootRuntime {
|
|
947
|
-
readonly scope: DeviceScope;
|
|
948
|
-
readonly device: RhiDevice;
|
|
949
|
-
readonly gpuStore: GpuResidencyCache;
|
|
950
|
-
readonly graphCandidate?: RecoveryGraphCandidate | undefined;
|
|
951
|
-
}
|
|
952
|
-
|
|
953
|
-
/** Candidate roots plus the one synchronous owner switch at publication. */
|
|
954
|
-
export interface RecoveryRootBundle {
|
|
955
|
-
readonly roots: readonly LifecycleResourceSpec<unknown>[];
|
|
956
|
-
publish(): void;
|
|
957
|
-
discard(): void;
|
|
958
|
-
}
|
|
959
|
-
|
|
960
762
|
/**
|
|
961
763
|
* Project the producer-owned material and GPU store state into the one
|
|
962
764
|
* renderer observation surface. This is intentionally recomputed from the
|
|
@@ -1081,41 +883,37 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
1081
883
|
let releaseProfilerCatalog =
|
|
1082
884
|
phaseCatalogRegistration?.ok === true ? phaseCatalogRegistration.value : undefined;
|
|
1083
885
|
let preparedWorlds: readonly World[] = [];
|
|
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();
|
|
1084
893
|
let latestCamera: CameraSnapshot | undefined;
|
|
1085
894
|
const pointsLinesOwner = new StandardPointsLinesOwner(internals);
|
|
1086
|
-
const instanceCollections = new
|
|
895
|
+
const instanceCollections = new InstanceCollectionStore();
|
|
1087
896
|
const reflectionProbeOwner = new ReflectionProbeRecordOwner(internals);
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
897
|
+
const ssrFormatReceipts = new WeakMap<
|
|
898
|
+
RhiDevice,
|
|
899
|
+
import('@forgeax/engine-rhi').RhiTextureFormatCapabilityReceipt
|
|
900
|
+
>();
|
|
1091
901
|
let ssrFallbackGeneration: number | undefined;
|
|
1092
|
-
const ensureSsrFormatProbe = (): void => {
|
|
1093
|
-
if (internals.ssrIdentity === undefined) return;
|
|
1094
|
-
const generation = internals.deviceScope.generation;
|
|
902
|
+
const ensureSsrFormatProbe = async (device = internals.device): Promise<void> => {
|
|
1095
903
|
if (
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
typeof internals.device.probeTextureFormatCapability !== 'function'
|
|
1100
|
-
) {
|
|
904
|
+
internals.ssrIdentity === undefined ||
|
|
905
|
+
typeof device.probeTextureFormatCapability !== 'function'
|
|
906
|
+
)
|
|
1101
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.
|
|
1102
916
|
}
|
|
1103
|
-
ssrFormatProbeGeneration = generation;
|
|
1104
|
-
const device = internals.device;
|
|
1105
|
-
ssrFormatProbe = device
|
|
1106
|
-
.probeTextureFormatCapability()
|
|
1107
|
-
.then((result) => {
|
|
1108
|
-
if (internals.device !== device || internals.deviceScope.generation !== generation) return;
|
|
1109
|
-
ssrFormatReceipt = result.ok ? result.value : undefined;
|
|
1110
|
-
})
|
|
1111
|
-
.catch(() => {
|
|
1112
|
-
if (internals.device === device && internals.deviceScope.generation === generation) {
|
|
1113
|
-
ssrFormatReceipt = undefined;
|
|
1114
|
-
}
|
|
1115
|
-
})
|
|
1116
|
-
.finally(() => {
|
|
1117
|
-
ssrFormatProbe = undefined;
|
|
1118
|
-
});
|
|
1119
917
|
};
|
|
1120
918
|
const cubeCaptureScheduler = createCubeCaptureScheduler({ maxFacesPerFrame: 1 });
|
|
1121
919
|
const cubeCaptureState: CubeCaptureGraphState = { work: [] };
|
|
@@ -1126,7 +924,6 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
1126
924
|
internals.gpuStore.invalidateMesh(handle, preparedWorlds[worldId] ?? worldId);
|
|
1127
925
|
},
|
|
1128
926
|
instanceCollections,
|
|
1129
|
-
getSkinPaletteAllocator: () => internals.getPipelineState()?.skinPaletteAllocator ?? null,
|
|
1130
927
|
});
|
|
1131
928
|
let environmentLifecycle = new EnvironmentLifecycle(internals.deviceScope);
|
|
1132
929
|
const transmissionAdmission = new TransmissionCandidateAdmission();
|
|
@@ -1270,7 +1067,12 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
1270
1067
|
}),
|
|
1271
1068
|
),
|
|
1272
1069
|
} satisfies import('./pipeline-builder').PipelineBuilderShaderModuleFactory);
|
|
1273
|
-
let
|
|
1070
|
+
let gpuDrivenRecoveryCount = 0;
|
|
1071
|
+
let gpuDrivenProduction = createGpuDrivenOwner(
|
|
1072
|
+
internals.device,
|
|
1073
|
+
gpuDrivenShaderFactory,
|
|
1074
|
+
gpuDrivenRecoveryCount,
|
|
1075
|
+
);
|
|
1274
1076
|
let occlusionRuntime: OcclusionRenderRuntime | undefined = new OcclusionRenderRuntime(
|
|
1275
1077
|
internals.device,
|
|
1276
1078
|
persistentRenderScene.visibilityFacetStore(),
|
|
@@ -1338,6 +1140,13 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
1338
1140
|
const frameState: RenderFrameState = {
|
|
1339
1141
|
frameNumber: 0,
|
|
1340
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,
|
|
1341
1150
|
graphGeneration: 0,
|
|
1342
1151
|
successfulTemporalFrameIndex: 0,
|
|
1343
1152
|
lastSuccessfulBloom: 'off',
|
|
@@ -1368,6 +1177,14 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
1368
1177
|
reflectionFallbackObservationSource: undefined,
|
|
1369
1178
|
lastSuccessfulCameraAntialias: undefined,
|
|
1370
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,
|
|
1371
1188
|
activeTemporalGpuState: undefined,
|
|
1372
1189
|
retiringTemporalGpuStates: new Set(),
|
|
1373
1190
|
lastSuccessfulTemporalView: undefined,
|
|
@@ -1377,7 +1194,7 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
1377
1194
|
currentDirectionalShadowView: null,
|
|
1378
1195
|
currentSpotShadowView: null,
|
|
1379
1196
|
instanceBuffers: new Map(),
|
|
1380
|
-
|
|
1197
|
+
instanceCollections,
|
|
1381
1198
|
instanceBufferChunks: new Map(),
|
|
1382
1199
|
probeBlendBuffers: new Map(),
|
|
1383
1200
|
probeBlendRecordBufferCapacity: 0,
|
|
@@ -1460,6 +1277,25 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
1460
1277
|
// tiles until the first frame with a castShadow spot (AC-03).
|
|
1461
1278
|
spotShadowSnapshots: [],
|
|
1462
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
|
+
};
|
|
1463
1299
|
let directFrameId = 0;
|
|
1464
1300
|
let submittedFrameCount = 0;
|
|
1465
1301
|
let lastSubmittedGeneration: number | undefined;
|
|
@@ -1467,6 +1303,122 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
1467
1303
|
let lastDirectionalShadowCandidate: 'accepted' | 'failed' = 'failed';
|
|
1468
1304
|
let lastDirectionalShadowError: DirectionalShadowInspectionSource['error'];
|
|
1469
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
|
+
|
|
1470
1422
|
function beginProfilePhase(session: RecorderSession | undefined, phase: RenderPhase): boolean {
|
|
1471
1423
|
if (session === undefined) return false;
|
|
1472
1424
|
try {
|
|
@@ -1698,22 +1650,21 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
1698
1650
|
const getPostProcessPipeline = (
|
|
1699
1651
|
id: string,
|
|
1700
1652
|
bgl: BindGroupLayout,
|
|
1701
|
-
|
|
1653
|
+
colorFormats: readonly GPUTextureFormat[],
|
|
1702
1654
|
entryOverride?: PostProcessShaderEntry,
|
|
1703
1655
|
): RenderPipeline | null => {
|
|
1704
1656
|
const entry = entryOverride ?? lookupPostProcess(id);
|
|
1705
1657
|
if (entry === undefined) return null;
|
|
1706
1658
|
const signature = postProcessShaderEntrySignature(entry);
|
|
1707
|
-
const key = `${id}|${
|
|
1659
|
+
const key = `${id}|${colorFormats.join(',')}|${signature}`;
|
|
1708
1660
|
const cached = postProcessPipelineCache.get(key);
|
|
1709
1661
|
if (cached !== undefined) return cached;
|
|
1710
|
-
internals.recoveryColdWorkGuard?.notePipelineColdWork();
|
|
1711
1662
|
const factory = internals.buildPostProcessPipeline;
|
|
1712
1663
|
if (factory === undefined) return null;
|
|
1713
1664
|
const built = factory(
|
|
1714
1665
|
entry,
|
|
1715
1666
|
bgl,
|
|
1716
|
-
|
|
1667
|
+
colorFormats,
|
|
1717
1668
|
postProcessShaderPipelineLabel(id, entry.source),
|
|
1718
1669
|
);
|
|
1719
1670
|
if (built === null) return null;
|
|
@@ -1884,193 +1835,18 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
1884
1835
|
createBindGroup: 0,
|
|
1885
1836
|
keys: [],
|
|
1886
1837
|
};
|
|
1887
|
-
type PreparedResolverCaches = {
|
|
1888
|
-
readonly preparedPipelineIds: WeakMap<object, string>;
|
|
1889
|
-
readonly preparedMaterialPipelineShaders: WeakMap<object, string>;
|
|
1890
|
-
readonly preparedGroup0Pipelines: WeakSet<object>;
|
|
1891
|
-
readonly preparedViewOnlyPipelines: WeakSet<object>;
|
|
1892
|
-
readonly preparedRenderMaterialPipelines: WeakSet<object>;
|
|
1893
|
-
readonly preparedAssetHandles: WeakMap<World, Map<string, number>>;
|
|
1894
|
-
};
|
|
1895
|
-
const createPreparedResolverCaches = (): PreparedResolverCaches => ({
|
|
1896
|
-
preparedPipelineIds: new WeakMap(),
|
|
1897
|
-
preparedMaterialPipelineShaders: new WeakMap(),
|
|
1898
|
-
preparedGroup0Pipelines: new WeakSet(),
|
|
1899
|
-
preparedViewOnlyPipelines: new WeakSet(),
|
|
1900
|
-
preparedRenderMaterialPipelines: new WeakSet(),
|
|
1901
|
-
preparedAssetHandles: new WeakMap(),
|
|
1902
|
-
});
|
|
1903
1838
|
const activePreparedResolverCaches = createPreparedResolverCaches();
|
|
1904
|
-
const preparedHandle = <Brand extends string>(
|
|
1905
|
-
runtime: RenderSystemInternals,
|
|
1906
|
-
caches: PreparedResolverCaches,
|
|
1907
|
-
world: World,
|
|
1908
|
-
guid: string,
|
|
1909
|
-
brand: Brand,
|
|
1910
|
-
): Handle<Brand, 'shared'> | undefined => {
|
|
1911
|
-
let handles = caches.preparedAssetHandles.get(world);
|
|
1912
|
-
if (handles === undefined) {
|
|
1913
|
-
handles = new Map();
|
|
1914
|
-
caches.preparedAssetHandles.set(world, handles);
|
|
1915
|
-
}
|
|
1916
|
-
const key = `${brand}:${guid.toLowerCase()}`;
|
|
1917
|
-
const cached = handles.get(key);
|
|
1918
|
-
if (cached !== undefined) return cached as Handle<Brand, 'shared'>;
|
|
1919
|
-
const asset = runtime.assets.lookup(guid);
|
|
1920
|
-
if (asset === undefined) return undefined;
|
|
1921
|
-
const handle = world.allocSharedRef(brand, asset);
|
|
1922
|
-
handles.set(key, handle as number);
|
|
1923
|
-
return handle;
|
|
1924
|
-
};
|
|
1925
|
-
const preparedMaterialBindings = (
|
|
1926
|
-
runtime: RenderSystemInternals,
|
|
1927
|
-
caches: PreparedResolverCaches,
|
|
1928
|
-
worlds: readonly World[],
|
|
1929
|
-
materialShaderId: string,
|
|
1930
|
-
worldIndex: number,
|
|
1931
|
-
materialGuid: string,
|
|
1932
|
-
layout: BindGroupLayout,
|
|
1933
|
-
) => {
|
|
1934
|
-
const world = worlds[worldIndex];
|
|
1935
|
-
const material = runtime.assets.lookup(materialGuid) as MaterialAsset | undefined;
|
|
1936
|
-
const pipelineState = runtime.getPipelineState();
|
|
1937
|
-
if (world === undefined || material?.kind !== 'material' || pipelineState === null) {
|
|
1938
|
-
return err(new Error('prepared material asset is unavailable'));
|
|
1939
|
-
}
|
|
1940
|
-
const schema = runtime.getParamSchema?.(materialShaderId) ?? [];
|
|
1941
|
-
const values = material.values ?? {};
|
|
1942
|
-
const derived = derive(schema);
|
|
1943
|
-
const fields = [...derived.textureFieldNames];
|
|
1944
|
-
let buffer: Buffer | undefined;
|
|
1945
|
-
let payloadByteLength = 0;
|
|
1946
|
-
if (derived.uboLayout.totalBytes > 0) {
|
|
1947
|
-
const payload = new Uint8Array(Math.max(16, derived.uboLayout.totalBytes));
|
|
1948
|
-
applyParamSnapshotToUbo(
|
|
1949
|
-
payload,
|
|
1950
|
-
schema,
|
|
1951
|
-
values as Readonly<Record<string, number | readonly number[]>>,
|
|
1952
|
-
);
|
|
1953
|
-
const created = runtime.device.createBuffer({
|
|
1954
|
-
label: `prepared-material:${materialGuid}`,
|
|
1955
|
-
size: payload.byteLength,
|
|
1956
|
-
usage: GPU_BUFFER_USAGE_UNIFORM | GPU_BUFFER_USAGE_COPY_DST,
|
|
1957
|
-
});
|
|
1958
|
-
if (!created.ok) return created;
|
|
1959
|
-
buffer = created.value;
|
|
1960
|
-
payloadByteLength = payload.byteLength;
|
|
1961
|
-
const written = runtime.device.queue.writeBuffer(buffer, 0, payload);
|
|
1962
|
-
if (!written.ok) {
|
|
1963
|
-
runtime.device.destroyBuffer(buffer);
|
|
1964
|
-
return written;
|
|
1965
|
-
}
|
|
1966
|
-
}
|
|
1967
|
-
const textureResources: Array<{
|
|
1968
|
-
sampler: import('@forgeax/engine-rhi').Sampler;
|
|
1969
|
-
view: import('@forgeax/engine-rhi').TextureView;
|
|
1970
|
-
}> = [];
|
|
1971
|
-
for (let index = 0; index < fields.length; index += 1) {
|
|
1972
|
-
const field = fields[index];
|
|
1973
|
-
const value = field === undefined ? undefined : values[field];
|
|
1974
|
-
const textureValue =
|
|
1975
|
-
typeof value === 'object' && value !== null && 'texture' in value
|
|
1976
|
-
? (value as MaterialTextureValue)
|
|
1977
|
-
: undefined;
|
|
1978
|
-
let sampler = pipelineState.defaultSampler;
|
|
1979
|
-
if (textureValue?.sampler !== undefined) {
|
|
1980
|
-
const handle = preparedHandle(
|
|
1981
|
-
runtime,
|
|
1982
|
-
caches,
|
|
1983
|
-
world,
|
|
1984
|
-
String(textureValue.sampler),
|
|
1985
|
-
'SamplerAsset',
|
|
1986
|
-
);
|
|
1987
|
-
if (handle !== undefined) {
|
|
1988
|
-
const asset = resolveAssetHandle<SamplerAsset>(world, handle);
|
|
1989
|
-
if (asset.ok) {
|
|
1990
|
-
const resident = runtime.gpuStore.ensureSamplerResident(handle, asset.value, world);
|
|
1991
|
-
if (resident.ok) sampler = resident.value;
|
|
1992
|
-
}
|
|
1993
|
-
}
|
|
1994
|
-
}
|
|
1995
|
-
let view = pipelineState.defaultWhiteTextureView;
|
|
1996
|
-
if (textureValue !== undefined) {
|
|
1997
|
-
const handle = preparedHandle(
|
|
1998
|
-
runtime,
|
|
1999
|
-
caches,
|
|
2000
|
-
world,
|
|
2001
|
-
String(textureValue.texture),
|
|
2002
|
-
'TextureAsset',
|
|
2003
|
-
);
|
|
2004
|
-
if (handle !== undefined) {
|
|
2005
|
-
view = residentTextureView(world, runtime.gpuStore, runtime, handle) ?? view;
|
|
2006
|
-
}
|
|
2007
|
-
}
|
|
2008
|
-
textureResources.push({ sampler, view });
|
|
2009
|
-
}
|
|
2010
|
-
const entries: BindGroupEntry[] = [];
|
|
2011
|
-
let textureIndex = 0;
|
|
2012
|
-
for (let index = 0; index < derived.bglEntries.length; index += 1) {
|
|
2013
|
-
const expected = derived.bglEntries[index];
|
|
2014
|
-
if (expected?.buffer?.type === 'uniform' && buffer !== undefined) {
|
|
2015
|
-
entries.push({
|
|
2016
|
-
binding: expected.binding,
|
|
2017
|
-
resource: { kind: 'buffer', value: { buffer, size: payloadByteLength } },
|
|
2018
|
-
});
|
|
2019
|
-
continue;
|
|
2020
|
-
}
|
|
2021
|
-
const textureResource = textureResources[textureIndex];
|
|
2022
|
-
if (
|
|
2023
|
-
expected?.sampler?.type === 'filtering' &&
|
|
2024
|
-
derived.bglEntries[index + 1]?.texture !== undefined &&
|
|
2025
|
-
textureResource !== undefined
|
|
2026
|
-
) {
|
|
2027
|
-
entries.push({
|
|
2028
|
-
binding: expected.binding,
|
|
2029
|
-
resource: { kind: 'sampler', value: textureResource.sampler },
|
|
2030
|
-
});
|
|
2031
|
-
continue;
|
|
2032
|
-
}
|
|
2033
|
-
if (expected?.texture !== undefined && textureResource !== undefined) {
|
|
2034
|
-
entries.push({
|
|
2035
|
-
binding: expected.binding,
|
|
2036
|
-
resource: { kind: 'textureView', value: textureResource.view },
|
|
2037
|
-
});
|
|
2038
|
-
textureIndex += 1;
|
|
2039
|
-
continue;
|
|
2040
|
-
}
|
|
2041
|
-
if (buffer !== undefined) runtime.device.destroyBuffer(buffer);
|
|
2042
|
-
return err(new Error('prepared material schema contains unsupported binding kinds'));
|
|
2043
|
-
}
|
|
2044
|
-
const fallback = pipelineState.skylightFallback;
|
|
2045
|
-
if (fallback === null) {
|
|
2046
|
-
if (buffer !== undefined) runtime.device.destroyBuffer(buffer);
|
|
2047
|
-
return err(new Error('prepared material skylight fallback is unavailable'));
|
|
2048
|
-
}
|
|
2049
|
-
const completeEntries = assembleMaterialWithSkylightEntries(entries, {
|
|
2050
|
-
irradianceView: fallback.irradianceView,
|
|
2051
|
-
irradianceSampler: fallback.sampler,
|
|
2052
|
-
prefilterView: fallback.prefilterView,
|
|
2053
|
-
prefilterSampler: fallback.sampler,
|
|
2054
|
-
brdfLutView: fallback.brdfLutView,
|
|
2055
|
-
brdfLutSampler: fallback.sampler,
|
|
2056
|
-
intensityBuffer: fallback.intensityBuffer,
|
|
2057
|
-
});
|
|
2058
|
-
const group = runtime.device.createBindGroup({ layout, entries: completeEntries });
|
|
2059
|
-
if (!group.ok) {
|
|
2060
|
-
if (buffer !== undefined) runtime.device.destroyBuffer(buffer);
|
|
2061
|
-
return group;
|
|
2062
|
-
}
|
|
2063
|
-
if (buffer === undefined) return group;
|
|
2064
|
-
return ok({
|
|
2065
|
-
handle: group.value,
|
|
2066
|
-
dynamicOffsets: [0, 0],
|
|
2067
|
-
release: () => runtime.device.destroyBuffer(buffer),
|
|
2068
|
-
});
|
|
2069
|
-
};
|
|
2070
1839
|
const lastFrustumStats: { culled: number; total: number } = { culled: 0, total: 0 };
|
|
2071
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
|
+
};
|
|
2072
1848
|
let lastMeshMaterialBindings: readonly MeshMaterialBindingObservation[] = [];
|
|
2073
|
-
let
|
|
1849
|
+
let lastMeshMaterialBindingRenderables: readonly RenderableSnapshot[] | undefined;
|
|
2074
1850
|
const createPreparedResolverFactory =
|
|
2075
1851
|
(
|
|
2076
1852
|
runtime: RenderSystemInternals,
|
|
@@ -2107,7 +1883,7 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
2107
1883
|
const pipeline = runtime.getPostProcessPipeline?.(
|
|
2108
1884
|
descriptor.shader,
|
|
2109
1885
|
fullscreen.bindGroupLayout,
|
|
2110
|
-
descriptor.colorFormats
|
|
1886
|
+
descriptor.colorFormats as readonly GPUTextureFormat[],
|
|
2111
1887
|
postProcessEntry,
|
|
2112
1888
|
);
|
|
2113
1889
|
if (pipeline !== null && pipeline !== undefined) {
|
|
@@ -2120,14 +1896,26 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
2120
1896
|
? err(makePreparedPipelinePendingError())
|
|
2121
1897
|
: ok(pipeline);
|
|
2122
1898
|
}
|
|
2123
|
-
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?.(
|
|
2124
1912
|
descriptor.shader,
|
|
2125
1913
|
descriptor.colorFormats[0] === 'rgba16float',
|
|
2126
1914
|
descriptor.renderState,
|
|
2127
1915
|
descriptor.topology,
|
|
2128
1916
|
descriptor.indexFormat,
|
|
2129
|
-
|
|
2130
|
-
|
|
1917
|
+
requestedVariantSet,
|
|
1918
|
+
preparedPassKind,
|
|
2131
1919
|
undefined,
|
|
2132
1920
|
descriptor.sampleCount ?? 1,
|
|
2133
1921
|
// Prepared graphics own their declared attachment format. Passing
|
|
@@ -2142,7 +1930,41 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
2142
1930
|
descriptor.vertexLayout,
|
|
2143
1931
|
undefined,
|
|
2144
1932
|
input.shaderModuleMode,
|
|
1933
|
+
undefined,
|
|
1934
|
+
undefined,
|
|
1935
|
+
undefined,
|
|
1936
|
+
undefined,
|
|
1937
|
+
undefined,
|
|
1938
|
+
descriptor.particleInputLanes,
|
|
2145
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);
|
|
2146
1968
|
// A requested material shader is an exact pipeline contract. During
|
|
2147
1969
|
// async shader warmup, substituting the generic unlit pipeline can
|
|
2148
1970
|
// mismatch vertex layouts and HDR attachment formats, turning a
|
|
@@ -2159,7 +1981,12 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
2159
1981
|
preparedRenderMaterialPipelines.add(pipeline as object);
|
|
2160
1982
|
}
|
|
2161
1983
|
}
|
|
2162
|
-
return pipeline === null
|
|
1984
|
+
return pipeline === null
|
|
1985
|
+
? err(makePreparedPipelinePendingError())
|
|
1986
|
+
: ok({
|
|
1987
|
+
handle: pipeline,
|
|
1988
|
+
standardLighting: preparedPipelineEntry?.group2Contract === 'cluster',
|
|
1989
|
+
});
|
|
2163
1990
|
},
|
|
2164
1991
|
resolveBindings: (descriptor, pipeline) => {
|
|
2165
1992
|
const materialShaderId = preparedMaterialPipelineShaders.get(pipeline as object);
|
|
@@ -2175,6 +2002,14 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
2175
2002
|
if (bindingContract === 'view-and-scene-depth') {
|
|
2176
2003
|
return ok(undefined);
|
|
2177
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
|
+
}
|
|
2178
2013
|
if (preparedGroup0Pipelines.has(pipeline as object)) {
|
|
2179
2014
|
const layout =
|
|
2180
2015
|
(materialShaderId === undefined
|
|
@@ -2228,6 +2063,7 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
2228
2063
|
material.world,
|
|
2229
2064
|
material.guid,
|
|
2230
2065
|
layout,
|
|
2066
|
+
preparedFeatureSkylightResources,
|
|
2231
2067
|
);
|
|
2232
2068
|
}
|
|
2233
2069
|
return layout === undefined
|
|
@@ -2311,16 +2147,21 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
2311
2147
|
createPreparedResolverCaches,
|
|
2312
2148
|
});
|
|
2313
2149
|
return {
|
|
2150
|
+
instances: instanceCollections,
|
|
2151
|
+
initializeSsr: ensureSsrFormatProbe,
|
|
2314
2152
|
get instanceCollectionsInspection(): readonly InstanceCollectionInspection[] {
|
|
2315
|
-
return instanceCollections._inspections(
|
|
2316
|
-
frameState.instanceResidency,
|
|
2317
|
-
frameState.frameNumber - 1,
|
|
2318
|
-
);
|
|
2153
|
+
return instanceCollections._inspections();
|
|
2319
2154
|
},
|
|
2320
2155
|
releaseProfilerCatalog(): void {
|
|
2321
2156
|
releaseProfilerCatalog?.();
|
|
2322
2157
|
releaseProfilerCatalog = undefined;
|
|
2323
2158
|
},
|
|
2159
|
+
invalidateGeometryHistory(): void {
|
|
2160
|
+
resetDynamicGeometryTemporalHistory(frameState);
|
|
2161
|
+
},
|
|
2162
|
+
bounds(world, entity) {
|
|
2163
|
+
return persistentRenderScene.bounds(world, entity);
|
|
2164
|
+
},
|
|
2324
2165
|
get renderScene(): RenderSceneInspection {
|
|
2325
2166
|
return {
|
|
2326
2167
|
...persistentRenderScene.inspect(),
|
|
@@ -2334,32 +2175,46 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
2334
2175
|
return reflectionProbeOwner.inspect();
|
|
2335
2176
|
},
|
|
2336
2177
|
get ssrDependencies(): SsrDependenciesInspection {
|
|
2337
|
-
|
|
2338
|
-
|
|
2339
|
-
|
|
2340
|
-
const
|
|
2341
|
-
|
|
2342
|
-
|
|
2343
|
-
frameState.
|
|
2344
|
-
|
|
2345
|
-
|
|
2346
|
-
|
|
2347
|
-
|
|
2348
|
-
|
|
2349
|
-
|
|
2350
|
-
|
|
2351
|
-
|
|
2352
|
-
|
|
2353
|
-
|
|
2354
|
-
|
|
2355
|
-
|
|
2356
|
-
|
|
2357
|
-
|
|
2358
|
-
|
|
2359
|
-
|
|
2360
|
-
|
|
2361
|
-
|
|
2362
|
-
|
|
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 }),
|
|
2363
2218
|
});
|
|
2364
2219
|
},
|
|
2365
2220
|
get reflectionFallbackCompletion(): Promise<void> | undefined {
|
|
@@ -2371,6 +2226,27 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
2371
2226
|
get environment(): EnvironmentInspection {
|
|
2372
2227
|
return environmentLifecycle.inspect();
|
|
2373
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
|
+
},
|
|
2374
2250
|
get temporal(): TemporalInspection {
|
|
2375
2251
|
return inspectTemporal(frameState.lastSuccessfulTemporalView, undefined, {
|
|
2376
2252
|
...(frameState.activeTemporalGpuState === undefined
|
|
@@ -2510,6 +2386,14 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
2510
2386
|
return persistentRenderScene.pointsLinesSnapshots();
|
|
2511
2387
|
},
|
|
2512
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
|
+
}
|
|
2513
2397
|
persistentRenderScene.detach(world);
|
|
2514
2398
|
},
|
|
2515
2399
|
draw(
|
|
@@ -2525,6 +2409,9 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
2525
2409
|
const profileSession = internals.profiler?.activeSession();
|
|
2526
2410
|
let ownsProfileFrame = false;
|
|
2527
2411
|
let submitted = false;
|
|
2412
|
+
// A failed draw must never leave a previous frame eligible to publish a
|
|
2413
|
+
// newly accepted dynamic-geometry candidate.
|
|
2414
|
+
dynamicGeometryFrames.begin();
|
|
2528
2415
|
if (profileSession !== undefined && opts.profileFrame === undefined) {
|
|
2529
2416
|
try {
|
|
2530
2417
|
ownsProfileFrame = profileSession.beginFrame(++directFrameId).ok;
|
|
@@ -2537,7 +2424,7 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
2537
2424
|
// cameraOwner drives the surfaced cameras + frustum
|
|
2538
2425
|
// cull; resourceOwner drives skylight/skybox/postProcess + per-world
|
|
2539
2426
|
// record config.
|
|
2540
|
-
const { cameraOwner, resourceOwner } = composition.owners;
|
|
2427
|
+
const { cameraOwner, resourceOwner, cameraEntityKey } = composition.owners;
|
|
2541
2428
|
// Keep the compiled graph as last-known-good until the candidate topology
|
|
2542
2429
|
// compiles. The failed candidate frame does not execute it; successful
|
|
2543
2430
|
// replacement retires it atomically in ensureCompiledFrameGraph.
|
|
@@ -2551,37 +2438,20 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
2551
2438
|
}
|
|
2552
2439
|
dispatchCounts.unlit = 0;
|
|
2553
2440
|
|
|
2554
|
-
// feat-20260708-composited-multi-world-rendering M3 / D-2 / m3-i2:
|
|
2555
|
-
// extractFrames merges per-world snapshots (renderables + lights from
|
|
2556
|
-
// every world, cameras + singleton resources from the owner world),
|
|
2557
|
-
// runs read-only extractFrame per world over the already-updated World,
|
|
2558
|
-
// resets frame state once, and isolates
|
|
2559
|
-
// per-world errors (AC-09).
|
|
2560
|
-
// Single-world draw([world], { cameraOwner: 0, resourceOwner: 0 }) is the identity path
|
|
2561
|
-
// (worldId=0), byte-for-byte equivalent to the pre-M3 direct
|
|
2562
|
-
// extractFrame path (AC-03 regression guarantee).
|
|
2563
|
-
//
|
|
2564
|
-
// Entry validation (empty worlds / owner out of range) is enforced by
|
|
2565
|
-
// the public renderer.draw facade (createRenderer.ts, D-5) before this
|
|
2566
|
-
// internal method is reached; the owner world is guaranteed present.
|
|
2567
|
-
//
|
|
2568
|
-
// feat-20260709-editor-world-partition M1 / w5+w6 (D-3): per-world
|
|
2569
|
-
// record configuration (transparent-sort mode, fold buckets, skybox /
|
|
2570
|
-
// asset resolution) is read from the resource-owner world — the world
|
|
2571
|
-
// that owns skylight / skybox / postProcessParams. w6 sources it from
|
|
2572
|
-
// the dedicated resourceOwner index. The variable is named
|
|
2573
|
-
// `resourceWorld` so the record-stage reads are self-describing (they
|
|
2574
|
-
// are resource-owner reads, not camera reads).
|
|
2575
2441
|
const resourceWorld = compositionWorlds[resourceOwner] as World;
|
|
2576
2442
|
const frame = runProfiledRenderPhase(profileSession, 'extract', () => {
|
|
2577
2443
|
return persistentRenderScene.extractComposition(
|
|
2578
2444
|
compositionWorlds,
|
|
2579
2445
|
{ cameraOwner, resourceOwner },
|
|
2580
2446
|
internals.assets.catalogEpoch,
|
|
2581
|
-
(
|
|
2447
|
+
(renderables) =>
|
|
2582
2448
|
extractFrames(
|
|
2583
2449
|
compositionWorlds,
|
|
2584
|
-
{
|
|
2450
|
+
{
|
|
2451
|
+
cameraOwner,
|
|
2452
|
+
resourceOwner,
|
|
2453
|
+
...(cameraEntityKey === undefined ? {} : { cameraEntityKey }),
|
|
2454
|
+
},
|
|
2585
2455
|
internals.assets,
|
|
2586
2456
|
internals.getPipelineState(),
|
|
2587
2457
|
persistentRenderScene.materialSnapshotCacheStore(),
|
|
@@ -2606,13 +2476,11 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
2606
2476
|
},
|
|
2607
2477
|
}),
|
|
2608
2478
|
cull: 'none',
|
|
2609
|
-
renderables: request === 'none' ? 'none' : 'full',
|
|
2610
|
-
...(request === 'none' || request === 'full'
|
|
2611
|
-
? {}
|
|
2612
|
-
: { renderableEntitiesByWorld: request.entitiesByWorld }),
|
|
2613
2479
|
retainHidden: true,
|
|
2480
|
+
renderables,
|
|
2614
2481
|
instanceCollections,
|
|
2615
|
-
...(internals.
|
|
2482
|
+
...(!internals.device.caps.storageBuffer ||
|
|
2483
|
+
internals.getMaterialShaderArtifact === undefined
|
|
2616
2484
|
? {}
|
|
2617
2485
|
: { getMaterialShaderArtifact: internals.getMaterialShaderArtifact }),
|
|
2618
2486
|
},
|
|
@@ -2621,7 +2489,7 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
2621
2489
|
);
|
|
2622
2490
|
});
|
|
2623
2491
|
const {
|
|
2624
|
-
cameras,
|
|
2492
|
+
cameras: extractedCameras,
|
|
2625
2493
|
cubeCameras,
|
|
2626
2494
|
lights,
|
|
2627
2495
|
environment,
|
|
@@ -2629,6 +2497,9 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
2629
2497
|
volumetricFog,
|
|
2630
2498
|
renderables,
|
|
2631
2499
|
dispatch,
|
|
2500
|
+
shadowCasterEntityKeys: extractedShadowCasterEntityKeys,
|
|
2501
|
+
shadowCasterDrawKeys: extractedShadowCasterDrawKeys,
|
|
2502
|
+
shadowCasterMembership: extractedShadowCasterMembership,
|
|
2632
2503
|
skylight,
|
|
2633
2504
|
skylightCount,
|
|
2634
2505
|
skybox,
|
|
@@ -2638,6 +2509,28 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
2638
2509
|
visibilityStats,
|
|
2639
2510
|
postProcessParams,
|
|
2640
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();
|
|
2641
2534
|
lastDirectionalShadowLights = lights;
|
|
2642
2535
|
lastDirectionalShadowCandidate = 'failed';
|
|
2643
2536
|
lastDirectionalShadowError = lights.directionalShadowError;
|
|
@@ -2649,6 +2542,26 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
2649
2542
|
skylight,
|
|
2650
2543
|
);
|
|
2651
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;
|
|
2652
2565
|
persistentRenderScene.updateVisibilityFacet(compositionWorlds, latestCamera, renderables);
|
|
2653
2566
|
let occlusionProjection:
|
|
2654
2567
|
| import('./scene/visibility/occlusion-runtime').OcclusionFrameProjection
|
|
@@ -2920,6 +2833,9 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
2920
2833
|
if (temporalDemanded) {
|
|
2921
2834
|
persistentRenderScene.prepareTemporalFrame(submissionRenderables);
|
|
2922
2835
|
}
|
|
2836
|
+
frameState.environmentFrame = environment as
|
|
2837
|
+
| import('./environment/frame').SelectedEnvironmentFrame
|
|
2838
|
+
| undefined;
|
|
2923
2839
|
environmentLifecycle.bindScope(internals.deviceScope);
|
|
2924
2840
|
if (fogFailure !== undefined) {
|
|
2925
2841
|
environmentLifecycle.recordSelectionFailure(fogFailure);
|
|
@@ -2950,8 +2866,8 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
2950
2866
|
updateTransmissionInspection(transmissionAntialias, false);
|
|
2951
2867
|
return false;
|
|
2952
2868
|
}
|
|
2953
|
-
if (
|
|
2954
|
-
|
|
2869
|
+
if (lastMeshMaterialBindingRenderables !== renderables) {
|
|
2870
|
+
lastMeshMaterialBindingRenderables = renderables;
|
|
2955
2871
|
lastMeshMaterialBindings = renderables.map((renderable) => {
|
|
2956
2872
|
const materialWorld = preparedWorlds[renderable.worldId];
|
|
2957
2873
|
return projectMeshMaterialBindingObservation({
|
|
@@ -3004,6 +2920,15 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
3004
2920
|
lastFrustumStats.culled = frustumStats.culled;
|
|
3005
2921
|
lastFrustumStats.total = frustumStats.total;
|
|
3006
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
|
+
}
|
|
3007
2932
|
const featureTargets =
|
|
3008
2933
|
preparedPipelineState === null || cameras[0] === undefined
|
|
3009
2934
|
? []
|
|
@@ -3014,6 +2939,11 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
3014
2939
|
storageBuffer: internals.device.caps.storageBuffer,
|
|
3015
2940
|
multisample: internals.device.caps.backendKind !== 'wgpu-webgl2',
|
|
3016
2941
|
});
|
|
2942
|
+
preparedFeatureSkylightResources =
|
|
2943
|
+
preparedPipelineState === null
|
|
2944
|
+
? undefined
|
|
2945
|
+
: resolveMaterialSkylight(internals, preparedPipelineState, skylight, skylightCount)
|
|
2946
|
+
.skylightResources;
|
|
3017
2947
|
let featureGraphCandidate: RenderFeatureGraphCandidate | undefined;
|
|
3018
2948
|
const preparedResourceBatches = runProfiledRenderPhase(profileSession, 'features', () => {
|
|
3019
2949
|
if (internals.featureHost === undefined) return [];
|
|
@@ -3029,6 +2959,28 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
3029
2959
|
...(internals.getMaterialShaderBindingContract === undefined
|
|
3030
2960
|
? {}
|
|
3031
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
|
+
}),
|
|
3032
2984
|
createPreparedGraphicsResolver: preparedResolverFactory,
|
|
3033
2985
|
gpuWork: featureGpuWork,
|
|
3034
2986
|
});
|
|
@@ -3052,10 +3004,11 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
3052
3004
|
featureGraphCandidate = {
|
|
3053
3005
|
plans: featureFrame.plans,
|
|
3054
3006
|
fullscreenEffects: featureFrame.fullscreenEffects,
|
|
3055
|
-
...(featureFrame.
|
|
3056
|
-
? {}
|
|
3057
|
-
: {
|
|
3007
|
+
...(featureFrame.requiresPreparedResourceKey
|
|
3008
|
+
? { preparedResourceKey: `frame-${frameState.frameNumber}` }
|
|
3009
|
+
: {}),
|
|
3058
3010
|
onRejected: () => {
|
|
3011
|
+
featureFrame.onAborted();
|
|
3059
3012
|
for (const batch of featureFrame.preparedResourceBatches) {
|
|
3060
3013
|
const released = batch.release();
|
|
3061
3014
|
if (!released.ok) {
|
|
@@ -3065,8 +3018,15 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
3065
3018
|
discardPostProcessParamsCandidate(postProcessParamsCandidate.value);
|
|
3066
3019
|
},
|
|
3067
3020
|
onAbandoned: () => {
|
|
3021
|
+
featureFrame.onAborted();
|
|
3068
3022
|
discardPostProcessParamsCandidate(postProcessParamsCandidate.value);
|
|
3069
3023
|
},
|
|
3024
|
+
onSubmitted: () => {
|
|
3025
|
+
featureFrame.onSubmitted();
|
|
3026
|
+
},
|
|
3027
|
+
onAborted: () => {
|
|
3028
|
+
featureFrame.onAborted();
|
|
3029
|
+
},
|
|
3070
3030
|
onAccepted: () => {
|
|
3071
3031
|
for (const [id, previous] of activeFeaturePostProcessEntries) {
|
|
3072
3032
|
const next = featureFrame.fullscreenEffects.get(id);
|
|
@@ -3087,6 +3047,7 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
3087
3047
|
activeFeaturePostProcessEntries = featureFrame.fullscreenEffects;
|
|
3088
3048
|
},
|
|
3089
3049
|
};
|
|
3050
|
+
recordRenderFeatureCandidate(internals, featureGraphCandidate);
|
|
3090
3051
|
return featureFrame.preparedResourceBatches;
|
|
3091
3052
|
});
|
|
3092
3053
|
|
|
@@ -3164,13 +3125,32 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
3164
3125
|
if (cameras[0]?.bloom === 'on') {
|
|
3165
3126
|
internals.getPipelineState()?.perPassResources.ensureBloomResources?.();
|
|
3166
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
|
+
}
|
|
3167
3147
|
submitted = runProfiledRenderPhase(profileSession, 'record', () =>
|
|
3168
3148
|
recordFrame(
|
|
3169
3149
|
internals,
|
|
3170
3150
|
resourceWorld,
|
|
3171
3151
|
cameras,
|
|
3172
3152
|
lights,
|
|
3173
|
-
|
|
3153
|
+
submissionRenderables,
|
|
3174
3154
|
orderedDispatch,
|
|
3175
3155
|
frameState,
|
|
3176
3156
|
dispatchCounts,
|
|
@@ -3206,18 +3186,20 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
3206
3186
|
environment?.fogSignature ?? '',
|
|
3207
3187
|
environmentReady && environment !== undefined,
|
|
3208
3188
|
persistentRenderScene.transmissionTopologyDemand(),
|
|
3189
|
+
shadowCasterEntityKeys,
|
|
3190
|
+
shadowCasterDrawKeys,
|
|
3209
3191
|
volumetricFog,
|
|
3210
3192
|
timingCapture,
|
|
3193
|
+
shadowCasterMembership,
|
|
3194
|
+
shadowCasterProjection,
|
|
3195
|
+
worldKeys,
|
|
3196
|
+
undefined,
|
|
3197
|
+
ssrDependencies,
|
|
3198
|
+
dynamicGeometryFrames.onRenderableDraw(compositionWorlds),
|
|
3211
3199
|
),
|
|
3212
3200
|
);
|
|
3213
|
-
|
|
3214
|
-
|
|
3215
|
-
internals.recoveryColdWorkGuard?.finish();
|
|
3216
|
-
} catch (cause) {
|
|
3217
|
-
submitted = false;
|
|
3218
|
-
throw cause;
|
|
3219
|
-
}
|
|
3220
|
-
}
|
|
3201
|
+
dynamicGeometryFrames.commit(submitted);
|
|
3202
|
+
if (!submitted) discardLiveFeatureState();
|
|
3221
3203
|
if (submitted && lastLodOcclusionInspection !== undefined) {
|
|
3222
3204
|
const query = ensureOcclusionRuntime().inspect();
|
|
3223
3205
|
lastLodOcclusionInspection = {
|
|
@@ -3312,6 +3294,7 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
3312
3294
|
}
|
|
3313
3295
|
}
|
|
3314
3296
|
} catch (err) {
|
|
3297
|
+
discardLiveFeatureState();
|
|
3315
3298
|
if (!submitted) {
|
|
3316
3299
|
internals.getPipelineState()?.perPassResources.discardBloomResources?.();
|
|
3317
3300
|
}
|
|
@@ -3325,7 +3308,11 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
3325
3308
|
}
|
|
3326
3309
|
: err instanceof RhiError
|
|
3327
3310
|
? err
|
|
3328
|
-
: {
|
|
3311
|
+
: {
|
|
3312
|
+
code: 'unknown' as const,
|
|
3313
|
+
message: String(err),
|
|
3314
|
+
name: (err as Error)?.name,
|
|
3315
|
+
};
|
|
3329
3316
|
internals.errorRegistry.fire(
|
|
3330
3317
|
new RhiError({
|
|
3331
3318
|
code: 'webgpu-runtime-error',
|
|
@@ -3345,6 +3332,8 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
3345
3332
|
}
|
|
3346
3333
|
return submitted;
|
|
3347
3334
|
},
|
|
3335
|
+
isDynamicGeometryConsumed: (world, entity, meshHandle) =>
|
|
3336
|
+
dynamicGeometryFrames.isConsumed(world, entity, meshHandle),
|
|
3348
3337
|
pipelineDispatchCounts: dispatchCounts,
|
|
3349
3338
|
observeCurrentFrame(options: FrameObservationOptions) {
|
|
3350
3339
|
const currentFrameId = frameState.frameNumber - 1;
|
|
@@ -3415,6 +3404,12 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
3415
3404
|
get perFrameGraphInfo(): CompiledRenderGraphInfo | undefined {
|
|
3416
3405
|
return frameState.compiledFrameGraph?.inspect();
|
|
3417
3406
|
},
|
|
3407
|
+
get featureGraphInspection(): import('./inspection-types').RenderFeatureGraphInspection {
|
|
3408
|
+
return getRenderFeatureGraphInspection(internals);
|
|
3409
|
+
},
|
|
3410
|
+
get materialTextureSources(): MaterialTextureSourceInspection {
|
|
3411
|
+
return lastMaterialTextureSources;
|
|
3412
|
+
},
|
|
3418
3413
|
get recoveryEvidence(): RecoveryProductionEvidence {
|
|
3419
3414
|
const graph = frameState.compiledFrameGraph?.inspect();
|
|
3420
3415
|
return Object.freeze({
|
|
@@ -3541,6 +3536,7 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
3541
3536
|
(internals as TimingSessionHost).gpuPassTimingSubmittedWork = undefined;
|
|
3542
3537
|
(internals as TimingSessionHost).gpuPassTimingFrameIdentity = undefined;
|
|
3543
3538
|
(internals as TimingSessionHost).gpuPassTimingBeginReason = undefined;
|
|
3539
|
+
internals.getPipelineState()?.skinPaletteAllocator?.dispose();
|
|
3544
3540
|
pointsLinesOwner.dispose();
|
|
3545
3541
|
persistentRenderScene.dispose();
|
|
3546
3542
|
instanceCollections.dispose();
|
|
@@ -3548,6 +3544,10 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
3548
3544
|
occlusionRuntime?.dispose();
|
|
3549
3545
|
disposeFeatureGpuWork();
|
|
3550
3546
|
reflectionProbeOwner.dispose();
|
|
3547
|
+
frameState.ssrHistoryOwner?.dispose();
|
|
3548
|
+
frameState.ssrHistoryOwner = undefined;
|
|
3549
|
+
frameState.ssrHistoryCandidate = undefined;
|
|
3550
|
+
frameState.ssrSpatialAdmission = undefined;
|
|
3551
3551
|
// Bloom generations are renderer-owned rather than graph-owned. Drain
|
|
3552
3552
|
// candidate, active, and fence-retiring bundles before the rest of the
|
|
3553
3553
|
// frame state is torn down; the owner callback is idempotent so the
|
|
@@ -3568,6 +3568,19 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
3568
3568
|
frameState.lastSuccessfulCameraAntialias = undefined;
|
|
3569
3569
|
frameState.currentDirectionalShadowView = null;
|
|
3570
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;
|
|
3571
3584
|
if (frameState.temporalGpuState !== undefined) {
|
|
3572
3585
|
retireTemporalGpuState(frameState.temporalGpuState);
|
|
3573
3586
|
frameState.temporalGpuState = undefined;
|
|
@@ -3613,7 +3626,6 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
3613
3626
|
// so destroy failures fire structured errors (unified per-frame +
|
|
3614
3627
|
// dispose error strategy).
|
|
3615
3628
|
disposeInstanceBuffers(frameState.instanceBuffers, internals.errorRegistry);
|
|
3616
|
-
frameState.instanceResidency?.clear();
|
|
3617
3629
|
if (frameState.instanceBufferChunks !== undefined) {
|
|
3618
3630
|
disposeInstanceBufferChunks(frameState.instanceBufferChunks, internals.errorRegistry);
|
|
3619
3631
|
}
|
|
@@ -3654,9 +3666,8 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
3654
3666
|
// their handles without invoking destroy on a device that can no longer
|
|
3655
3667
|
// service cleanup; the staged candidate owns the replacement buffers.
|
|
3656
3668
|
pointsLinesOwner.abandonForDeviceLoss();
|
|
3657
|
-
|
|
3658
|
-
|
|
3659
|
-
ssrFormatProbe = undefined;
|
|
3669
|
+
resetStandardOutputForDeviceLoss(frameState, internals.deviceScope.generation);
|
|
3670
|
+
ssrFormatReceipts.delete(internals.device);
|
|
3660
3671
|
ssrFallbackGeneration = undefined;
|
|
3661
3672
|
transmissionAdmission.markDeviceLost();
|
|
3662
3673
|
lastTransmissionKey = '';
|
|
@@ -3674,13 +3685,11 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
3674
3685
|
updateTransmissionInspection(lastTransmissionAntialias, false);
|
|
3675
3686
|
persistentRenderScene.resetGpuForRecover();
|
|
3676
3687
|
gpuDrivenProduction.dispose();
|
|
3677
|
-
|
|
3678
|
-
|
|
3679
|
-
// explicitly so the first published draw never routes through an owner
|
|
3680
|
-
// recreated against the old physical device.
|
|
3681
|
-
gpuDrivenProduction = GpuDrivenProduction.forDevice(
|
|
3688
|
+
gpuDrivenRecoveryCount += 1;
|
|
3689
|
+
gpuDrivenProduction = createGpuDrivenOwner(
|
|
3682
3690
|
replacementDevice ?? internals.device,
|
|
3683
3691
|
gpuDrivenShaderFactory,
|
|
3692
|
+
gpuDrivenRecoveryCount,
|
|
3684
3693
|
);
|
|
3685
3694
|
occlusionRuntime?.dispose();
|
|
3686
3695
|
// The replacement device is installed by the host after this hook. Do
|
|
@@ -3690,6 +3699,13 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
3690
3699
|
disposeFeatureGpuWork();
|
|
3691
3700
|
featureGpuWork = createFeatureGpuWorkOwner(internals);
|
|
3692
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;
|
|
3693
3709
|
// A recovered device cannot retain handles from the lost device. The
|
|
3694
3710
|
// Bloom owner abandons candidates and retires every committed generation
|
|
3695
3711
|
// before the new PipelineState is rebuilt.
|
|
@@ -3759,7 +3775,7 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
3759
3775
|
frameState.retiredCompiledFrameGraphs.clear();
|
|
3760
3776
|
frameState.instanceBuffers.clear();
|
|
3761
3777
|
frameState.instanceBufferChunks?.clear();
|
|
3762
|
-
|
|
3778
|
+
instanceCollections._resetResidency();
|
|
3763
3779
|
delete frameState.probeBlendRecordBuffer;
|
|
3764
3780
|
frameState.probeBlendRecordBufferCapacity = 0;
|
|
3765
3781
|
frameState.probeBlendBuffers.clear();
|
|
@@ -3802,124 +3818,9 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
3802
3818
|
publishRecoveryPostProcessResources(prepared.value);
|
|
3803
3819
|
},
|
|
3804
3820
|
prepareRecoveryRoots(runtime: RecoveryRootRuntime): RecoveryRootBundle {
|
|
3805
|
-
|
|
3806
|
-
|
|
3807
|
-
|
|
3808
|
-
const candidateEnvironmentLifecycle = environmentLifecycle.createRecoveryCandidate(
|
|
3809
|
-
runtime.scope,
|
|
3810
|
-
);
|
|
3811
|
-
const roots: LifecycleResourceSpec<unknown>[] = [];
|
|
3812
|
-
let candidateEnvironmentGeneration: EnvironmentGeneration | undefined;
|
|
3813
|
-
let environmentRootCleaned = false;
|
|
3814
|
-
let published = false;
|
|
3815
|
-
if (candidateEnvironmentLifecycle.hasRecoveryFrame()) {
|
|
3816
|
-
const environmentRoot = candidateEnvironmentLifecycle.createRecoveryRoot(runtime.scope);
|
|
3817
|
-
roots.push({
|
|
3818
|
-
...environmentRoot,
|
|
3819
|
-
create: async () => {
|
|
3820
|
-
const generation = (await environmentRoot.create()) as EnvironmentGeneration;
|
|
3821
|
-
candidateEnvironmentGeneration = generation;
|
|
3822
|
-
return generation;
|
|
3823
|
-
},
|
|
3824
|
-
cleanup: (value) => {
|
|
3825
|
-
if (environmentRootCleaned) return;
|
|
3826
|
-
environmentRootCleaned = true;
|
|
3827
|
-
if (candidateEnvironmentGeneration === value) {
|
|
3828
|
-
candidateEnvironmentGeneration = undefined;
|
|
3829
|
-
}
|
|
3830
|
-
if (published) {
|
|
3831
|
-
candidateEnvironmentLifecycle.retirePublishedGeneration(
|
|
3832
|
-
value as EnvironmentGeneration,
|
|
3833
|
-
);
|
|
3834
|
-
} else {
|
|
3835
|
-
environmentRoot.cleanup(value);
|
|
3836
|
-
}
|
|
3837
|
-
},
|
|
3838
|
-
});
|
|
3839
|
-
}
|
|
3840
|
-
const graphCandidate = runtime.graphCandidate;
|
|
3841
|
-
if (graphCandidate !== undefined) {
|
|
3842
|
-
const releaseGraphCandidate = (): void => graphCandidate.release();
|
|
3843
|
-
const compiledGraph = graphCandidate.frameState.compiledFrameGraph;
|
|
3844
|
-
if (compiledGraph !== null) {
|
|
3845
|
-
roots.push({
|
|
3846
|
-
kind: 'pipeline',
|
|
3847
|
-
create: () => {
|
|
3848
|
-
if (!runtime.scope.isAlive()) {
|
|
3849
|
-
throw new Error('Recovery graph candidate scope is not active.');
|
|
3850
|
-
}
|
|
3851
|
-
if (graphCandidate.frameState.compiledFrameGraph !== compiledGraph) {
|
|
3852
|
-
throw new Error('Recovery graph candidate was changed before aggregate assembly.');
|
|
3853
|
-
}
|
|
3854
|
-
return compiledGraph;
|
|
3855
|
-
},
|
|
3856
|
-
// All graph/feature/GPU-driven candidate resources share one
|
|
3857
|
-
// owner. The root is a real release seam, not a marker; the
|
|
3858
|
-
// candidate latch makes every root cleanup call harmless after
|
|
3859
|
-
// the first one.
|
|
3860
|
-
cleanup: releaseGraphCandidate,
|
|
3861
|
-
});
|
|
3862
|
-
}
|
|
3863
|
-
if (graphCandidate.featureHost !== undefined) {
|
|
3864
|
-
const featureRoot = graphCandidate.featureHost.createRecoveryRoot(runtime.scope);
|
|
3865
|
-
roots.push({ ...featureRoot, cleanup: releaseGraphCandidate });
|
|
3866
|
-
}
|
|
3867
|
-
if (graphCandidate.featureGpuWork !== undefined) {
|
|
3868
|
-
const featureWorkRoot = graphCandidate.featureGpuWork.createRecoveryRoot(runtime.scope);
|
|
3869
|
-
roots.push({ ...featureWorkRoot, cleanup: releaseGraphCandidate });
|
|
3870
|
-
}
|
|
3871
|
-
if (graphCandidate.gpuDrivenProduction !== undefined) {
|
|
3872
|
-
const productionRoot = graphCandidate.gpuDrivenProduction.createRecoveryRoot(
|
|
3873
|
-
runtime.scope,
|
|
3874
|
-
);
|
|
3875
|
-
roots.push({ ...productionRoot, cleanup: releaseGraphCandidate });
|
|
3876
|
-
}
|
|
3877
|
-
if (graphCandidate.gpuDrivenScene?.state !== undefined) {
|
|
3878
|
-
const sceneRoot = graphCandidate.gpuDrivenScene.createRecoveryRoot(runtime.scope);
|
|
3879
|
-
roots.push({ ...sceneRoot, cleanup: releaseGraphCandidate });
|
|
3880
|
-
}
|
|
3881
|
-
if (graphCandidate.pointsLines !== undefined) {
|
|
3882
|
-
const pointsLinesRoot = graphCandidate.pointsLines.createRecoveryRoot(runtime.scope);
|
|
3883
|
-
roots.push({ ...pointsLinesRoot, cleanup: releaseGraphCandidate });
|
|
3884
|
-
}
|
|
3885
|
-
if (runtime.gpuStore.recoveryResourceCount() > 0) {
|
|
3886
|
-
const gpuStoreRoot = runtime.gpuStore.createRecoveryRoot(runtime.scope);
|
|
3887
|
-
roots.push({ ...gpuStoreRoot, cleanup: releaseGraphCandidate });
|
|
3888
|
-
}
|
|
3889
|
-
}
|
|
3890
|
-
let discarded = false;
|
|
3891
|
-
return {
|
|
3892
|
-
roots: Object.freeze(roots),
|
|
3893
|
-
publish: () => {
|
|
3894
|
-
if (published || discarded) return;
|
|
3895
|
-
if (
|
|
3896
|
-
candidateEnvironmentGeneration !== undefined &&
|
|
3897
|
-
!candidateEnvironmentGeneration.retired
|
|
3898
|
-
) {
|
|
3899
|
-
environmentLifecycle.retireActiveForReplacement();
|
|
3900
|
-
candidateEnvironmentLifecycle.publish(candidateEnvironmentGeneration);
|
|
3901
|
-
}
|
|
3902
|
-
published = true;
|
|
3903
|
-
environmentLifecycle = candidateEnvironmentLifecycle;
|
|
3904
|
-
Object.assign(frameState, { environmentLifecycle });
|
|
3905
|
-
},
|
|
3906
|
-
discard: () => {
|
|
3907
|
-
if (published || discarded) return;
|
|
3908
|
-
discarded = true;
|
|
3909
|
-
if (candidateEnvironmentGeneration !== undefined) {
|
|
3910
|
-
candidateEnvironmentLifecycle.discard(candidateEnvironmentGeneration);
|
|
3911
|
-
candidateEnvironmentGeneration = undefined;
|
|
3912
|
-
}
|
|
3913
|
-
candidateEnvironmentLifecycle.discardRecoveryCandidates();
|
|
3914
|
-
// The transaction can fail before it reaches any graph root (for
|
|
3915
|
-
// example while the environment root is created). Keep the graph,
|
|
3916
|
-
// feature, GPU-driven, and residency resources on the same real
|
|
3917
|
-
// candidate owner in that case; later scope/factory cleanup is a
|
|
3918
|
-
// harmless repeat through the candidate latch.
|
|
3919
|
-
graphCandidate?.release();
|
|
3920
|
-
runtime.scope.abandon();
|
|
3921
|
-
},
|
|
3922
|
-
};
|
|
3821
|
+
return prepareRenderSystemRecoveryRoots(runtime, environmentLifecycle, frameState, (next) => {
|
|
3822
|
+
environmentLifecycle = next;
|
|
3823
|
+
});
|
|
3923
3824
|
},
|
|
3924
3825
|
};
|
|
3925
3826
|
}
|