@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
|
@@ -25,10 +25,19 @@ import { executeRendererFrameTransaction } from '../assembly/renderer-frame-tran
|
|
|
25
25
|
import { type RenderError, RenderFeatureStageFailedError } from '../errors/render';
|
|
26
26
|
import {
|
|
27
27
|
getRenderFeaturePlanExecutionProjection,
|
|
28
|
+
hasSubmissionSensitiveFeatures,
|
|
28
29
|
type RenderFeaturePlanExecution,
|
|
29
30
|
} from '../features/host';
|
|
30
|
-
import {
|
|
31
|
-
|
|
31
|
+
import {
|
|
32
|
+
type RenderFeaturePlannedFrame,
|
|
33
|
+
renderFeaturePlanSignature,
|
|
34
|
+
renderFeaturePlanSignatureEvidenceMatches,
|
|
35
|
+
} from '../features/plan';
|
|
36
|
+
import {
|
|
37
|
+
createRenderFeatureProjectionState,
|
|
38
|
+
projectRenderFeaturePlans as projectPlanExecutions,
|
|
39
|
+
projectRenderFeatureShadows,
|
|
40
|
+
} from '../features/render-graph-contribution';
|
|
32
41
|
import type {
|
|
33
42
|
RenderFeatureGraphBindingsResolution,
|
|
34
43
|
RenderFeatureGraphTargetResolver,
|
|
@@ -40,19 +49,32 @@ import {
|
|
|
40
49
|
createFullscreenBindGroup,
|
|
41
50
|
isTemporalFullscreenBinding,
|
|
42
51
|
postProcessShaderEntrySignature,
|
|
43
|
-
postProcessShaderModuleLabel,
|
|
44
52
|
} from '../fullscreen-post-process-pass';
|
|
45
53
|
import type { PreparedGpuDrivenFrame } from '../gpu-driven/production-raster';
|
|
46
54
|
import {
|
|
47
55
|
GPU_TEXTURE_USAGE_COPY_DST,
|
|
48
56
|
GPU_TEXTURE_USAGE_COPY_SRC,
|
|
49
57
|
GPU_TEXTURE_USAGE_RENDER_ATTACHMENT,
|
|
58
|
+
GPU_TEXTURE_USAGE_STORAGE_BINDING,
|
|
50
59
|
GPU_TEXTURE_USAGE_TEXTURE_BINDING,
|
|
51
60
|
} from '../gpu-texture-usage';
|
|
61
|
+
import { GPU_BUFFER_USAGE_COPY_DST, GPU_BUFFER_USAGE_UNIFORM } from '../gpu-usage';
|
|
62
|
+
import { createStandardSurfaceLightingBindGroup } from '../hdrp-buffers';
|
|
63
|
+
import type { RenderFeatureGraphInspection } from '../inspection-types';
|
|
52
64
|
import {
|
|
53
65
|
type StandardTopologyInputValue,
|
|
54
66
|
standardLightingTopologySignature,
|
|
55
67
|
} from '../pipeline/standard-lighting/topology';
|
|
68
|
+
import {
|
|
69
|
+
importAutoExposureGraphResources,
|
|
70
|
+
retireAutoExposureGpuResources,
|
|
71
|
+
} from '../pipeline/standard-output/auto-exposure/gpu';
|
|
72
|
+
import { commitAutoExposureSubmission } from '../pipeline/standard-output/auto-exposure/state';
|
|
73
|
+
import { retireStandardLutGpuResources } from '../pipeline/standard-output/lut-gpu';
|
|
74
|
+
import {
|
|
75
|
+
commitStandardLutCandidate,
|
|
76
|
+
resetStandardLutState,
|
|
77
|
+
} from '../pipeline/standard-output/lut-state';
|
|
56
78
|
import { resolveVolumetricFogProfile, STANDARD_PIPELINE_ID } from '../pipeline/standard-profile';
|
|
57
79
|
import type { CameraSnapshot } from '../render-contract';
|
|
58
80
|
import type {
|
|
@@ -62,7 +84,7 @@ import type {
|
|
|
62
84
|
} from '../render-pipeline';
|
|
63
85
|
import type { ExtractedLights, ExtractedVolumetricFog } from '../render-system-extract';
|
|
64
86
|
import { SHADOW_ATLAS_DEFAULT_FACE_SIZE, SHADOW_ATLAS_DEFAULT_LAYERS } from '../shadow-atlas';
|
|
65
|
-
import type { SsrAdmissionResult } from '../ssr/admission';
|
|
87
|
+
import type { SsrAdmissionResult, SsrSpatialAdmission } from '../ssr/admission';
|
|
66
88
|
import type { RenderTarget } from '../targets/contracts';
|
|
67
89
|
import type { RenderTargetPhysical } from '../targets/physical';
|
|
68
90
|
import {
|
|
@@ -72,6 +94,7 @@ import {
|
|
|
72
94
|
hasPendingTemporalGpuSubmit,
|
|
73
95
|
retireTemporalGpuState,
|
|
74
96
|
retireTemporalGpuStateAfterFence,
|
|
97
|
+
TEMPORAL_HISTORY_FORMATS,
|
|
75
98
|
temporalReadIndex,
|
|
76
99
|
temporalWriteIndex,
|
|
77
100
|
} from '../temporal/gpu';
|
|
@@ -80,7 +103,12 @@ import type { TransmissionDemand } from '../transmission/projection';
|
|
|
80
103
|
import { hasVolumetricFogCapability } from '../volume/capability';
|
|
81
104
|
import { deriveVolumetricFogExtent, deriveVolumetricFogResolvedExtent } from '../volume/resources';
|
|
82
105
|
import { buildPerFrameBindGroups } from './frame-lighting';
|
|
83
|
-
import {
|
|
106
|
+
import {
|
|
107
|
+
type GraphTargetPassReplayPrefixReceipt,
|
|
108
|
+
type GraphTargetPassReplayReceipt,
|
|
109
|
+
getTextureIdentity,
|
|
110
|
+
type RenderFrameState,
|
|
111
|
+
} from './frame-snapshot';
|
|
84
112
|
import type { GpuPassTimingPassIdentity } from './gpu-pass-timing/contract.js';
|
|
85
113
|
import type { GpuPassTimingCapture, GpuPassTimingSession } from './gpu-pass-timing/session.js';
|
|
86
114
|
import type { GpuTimingCapture } from './gpu-timing';
|
|
@@ -199,13 +227,14 @@ export function commitReflectionFallbackGraph(
|
|
|
199
227
|
function importTemporalHistoryTarget(
|
|
200
228
|
graph: RenderGraphBuilder<RenderPipelineFrame>,
|
|
201
229
|
label: string,
|
|
202
|
-
kind: 'color' | 'temporal',
|
|
230
|
+
kind: 'color' | 'temporal' | 'stability',
|
|
203
231
|
role: 'read' | 'write',
|
|
204
232
|
): import('../render-pipeline').RenderPipelineTarget {
|
|
233
|
+
const format = TEMPORAL_HISTORY_FORMATS[kind];
|
|
205
234
|
const texture = graph.importTexture(
|
|
206
235
|
label,
|
|
207
236
|
{
|
|
208
|
-
format
|
|
237
|
+
format,
|
|
209
238
|
size: 'surface',
|
|
210
239
|
usage:
|
|
211
240
|
GPU_TEXTURE_USAGE_COPY_SRC |
|
|
@@ -223,7 +252,7 @@ function importTemporalHistoryTarget(
|
|
|
223
252
|
frame.targetH,
|
|
224
253
|
);
|
|
225
254
|
const index = role === 'read' ? temporalReadIndex(state) : temporalWriteIndex(state);
|
|
226
|
-
return
|
|
255
|
+
return state[kind][index].texture;
|
|
227
256
|
},
|
|
228
257
|
);
|
|
229
258
|
if (!texture.ok) throw texture.error;
|
|
@@ -240,11 +269,11 @@ function importTemporalHistoryTarget(
|
|
|
240
269
|
frame.targetH,
|
|
241
270
|
);
|
|
242
271
|
const index = role === 'read' ? temporalReadIndex(state) : temporalWriteIndex(state);
|
|
243
|
-
return
|
|
272
|
+
return state[kind][index].view;
|
|
244
273
|
},
|
|
245
274
|
);
|
|
246
275
|
if (!view.ok) throw view.error;
|
|
247
|
-
return { texture: texture.value, view: view.value, format
|
|
276
|
+
return { texture: texture.value, view: view.value, format, sampleCount: 1 };
|
|
248
277
|
}
|
|
249
278
|
|
|
250
279
|
function importTemporalHistoryTargets(
|
|
@@ -254,6 +283,18 @@ function importTemporalHistoryTargets(
|
|
|
254
283
|
> {
|
|
255
284
|
return {
|
|
256
285
|
currentColor: importTemporalHistoryTarget(graph, 'taa-history-current-color', 'color', 'write'),
|
|
286
|
+
currentStability: importTemporalHistoryTarget(
|
|
287
|
+
graph,
|
|
288
|
+
'taa-history-current-stability',
|
|
289
|
+
'stability',
|
|
290
|
+
'write',
|
|
291
|
+
),
|
|
292
|
+
previousStability: importTemporalHistoryTarget(
|
|
293
|
+
graph,
|
|
294
|
+
'taa-history-previous-stability',
|
|
295
|
+
'stability',
|
|
296
|
+
'read',
|
|
297
|
+
),
|
|
257
298
|
previousColor: importTemporalHistoryTarget(
|
|
258
299
|
graph,
|
|
259
300
|
'taa-history-previous-color',
|
|
@@ -275,6 +316,110 @@ function importTemporalHistoryTargets(
|
|
|
275
316
|
};
|
|
276
317
|
}
|
|
277
318
|
|
|
319
|
+
function importSsrHistoryTarget(
|
|
320
|
+
graph: RenderGraphBuilder<RenderPipelineFrame>,
|
|
321
|
+
label: string,
|
|
322
|
+
role: 'read' | 'write',
|
|
323
|
+
surface = false,
|
|
324
|
+
): import('../render-pipeline').RenderPipelineTarget {
|
|
325
|
+
const texture = graph.importTexture(
|
|
326
|
+
label,
|
|
327
|
+
{
|
|
328
|
+
format: surface ? 'rgba8unorm' : 'rgba16float',
|
|
329
|
+
size: 'half-surface',
|
|
330
|
+
usage:
|
|
331
|
+
GPU_TEXTURE_USAGE_COPY_SRC |
|
|
332
|
+
GPU_TEXTURE_USAGE_COPY_DST |
|
|
333
|
+
GPU_TEXTURE_USAGE_RENDER_ATTACHMENT |
|
|
334
|
+
GPU_TEXTURE_USAGE_STORAGE_BINDING |
|
|
335
|
+
GPU_TEXTURE_USAGE_TEXTURE_BINDING,
|
|
336
|
+
domain: 'linear-hdr',
|
|
337
|
+
},
|
|
338
|
+
(frame) => {
|
|
339
|
+
const internal = frame as import('./render-context')._InternalRenderPipelineContext;
|
|
340
|
+
const owner = internal.frameState.ssrHistoryOwner;
|
|
341
|
+
const candidate = internal.frameState.ssrHistoryCandidate;
|
|
342
|
+
if (owner === undefined || candidate === undefined) {
|
|
343
|
+
throw new RhiError({
|
|
344
|
+
code: 'rhi-not-available',
|
|
345
|
+
expected: 'SSR history candidate to be staged before graph execution',
|
|
346
|
+
hint: 'begin the SSR history candidate before executing the admitted graph',
|
|
347
|
+
});
|
|
348
|
+
}
|
|
349
|
+
const slot =
|
|
350
|
+
role === 'read'
|
|
351
|
+
? (candidate.readSlot ?? (candidate.writeSlot === 0 ? 1 : 0))
|
|
352
|
+
: candidate.writeSlot;
|
|
353
|
+
return surface
|
|
354
|
+
? owner.resources.slots[slot].surfaceTexture
|
|
355
|
+
: owner.resources.slots[slot].texture;
|
|
356
|
+
},
|
|
357
|
+
);
|
|
358
|
+
if (!texture.ok) throw texture.error;
|
|
359
|
+
const view = graph.importView(
|
|
360
|
+
texture.value,
|
|
361
|
+
{ label: `${label}.view`, dimension: '2d' },
|
|
362
|
+
(frame) => {
|
|
363
|
+
const internal = frame as import('./render-context')._InternalRenderPipelineContext;
|
|
364
|
+
const owner = internal.frameState.ssrHistoryOwner;
|
|
365
|
+
const candidate = internal.frameState.ssrHistoryCandidate;
|
|
366
|
+
if (owner === undefined || candidate === undefined) {
|
|
367
|
+
throw new RhiError({
|
|
368
|
+
code: 'rhi-not-available',
|
|
369
|
+
expected: 'SSR history candidate to be staged before graph execution',
|
|
370
|
+
hint: 'begin the SSR history candidate before executing the admitted graph',
|
|
371
|
+
});
|
|
372
|
+
}
|
|
373
|
+
const slot =
|
|
374
|
+
role === 'read'
|
|
375
|
+
? (candidate.readSlot ?? (candidate.writeSlot === 0 ? 1 : 0))
|
|
376
|
+
: candidate.writeSlot;
|
|
377
|
+
return surface ? owner.resources.slots[slot].surfaceView : owner.resources.slots[slot].view;
|
|
378
|
+
},
|
|
379
|
+
);
|
|
380
|
+
if (!view.ok) throw view.error;
|
|
381
|
+
return {
|
|
382
|
+
texture: texture.value,
|
|
383
|
+
view: view.value,
|
|
384
|
+
format: surface ? 'rgba8unorm' : 'rgba16float',
|
|
385
|
+
sampleCount: 1,
|
|
386
|
+
domain: 'linear-hdr',
|
|
387
|
+
};
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
function importSsrHistoryTargets(
|
|
391
|
+
graph: RenderGraphBuilder<RenderPipelineFrame>,
|
|
392
|
+
): NonNullable<
|
|
393
|
+
import('../render-pipeline').RenderPipelineBuildContext<RenderPipelineFrame>['ssrHistory']
|
|
394
|
+
> {
|
|
395
|
+
return {
|
|
396
|
+
previous: importSsrHistoryTarget(graph, 'ssr-history-previous', 'read'),
|
|
397
|
+
output: importSsrHistoryTarget(graph, 'ssr-history-output', 'write'),
|
|
398
|
+
previousSurface: importSsrHistoryTarget(graph, 'ssr-history-previous-surface', 'read', true),
|
|
399
|
+
outputSurface: importSsrHistoryTarget(graph, 'ssr-history-output-surface', 'write', true),
|
|
400
|
+
params: (() => {
|
|
401
|
+
const imported = graph.importBuffer(
|
|
402
|
+
'ssr-history-params',
|
|
403
|
+
{ size: 32, usage: GPU_BUFFER_USAGE_UNIFORM | GPU_BUFFER_USAGE_COPY_DST },
|
|
404
|
+
(frame) => {
|
|
405
|
+
const internal = frame as import('./render-context')._InternalRenderPipelineContext;
|
|
406
|
+
const owner = internal.frameState.ssrHistoryOwner;
|
|
407
|
+
if (owner === undefined) {
|
|
408
|
+
throw new RhiError({
|
|
409
|
+
code: 'rhi-not-available',
|
|
410
|
+
expected: 'SSR history owner to be staged before graph execution',
|
|
411
|
+
hint: 'create the renderer-owned SSR history before executing the admitted graph',
|
|
412
|
+
});
|
|
413
|
+
}
|
|
414
|
+
return owner.resources.paramsBuffer;
|
|
415
|
+
},
|
|
416
|
+
);
|
|
417
|
+
if (!imported.ok) throw imported.error;
|
|
418
|
+
return imported.value;
|
|
419
|
+
})(),
|
|
420
|
+
};
|
|
421
|
+
}
|
|
422
|
+
|
|
278
423
|
export function shouldUseTemporalFrameTransaction(
|
|
279
424
|
antialias: CameraSnapshot['antialias'],
|
|
280
425
|
temporalDemand = false,
|
|
@@ -539,7 +684,6 @@ function addCubeCaptureGraphPasses(
|
|
|
539
684
|
const captureResolveView = captureResolve?.ok ? captureResolve.value : null;
|
|
540
685
|
const captureContext = {
|
|
541
686
|
...internal,
|
|
542
|
-
gpuDrivenEntityKeys: new Set<number>(),
|
|
543
687
|
camera: current().faceCamera,
|
|
544
688
|
// Cube faces are raw scene captures, not display-camera HDR output.
|
|
545
689
|
// Select the PSO against the actual target attachment so an LDR
|
|
@@ -788,6 +932,57 @@ export interface RenderFeatureGraphRuntimeState {
|
|
|
788
932
|
>;
|
|
789
933
|
}
|
|
790
934
|
|
|
935
|
+
/** The exact fields that define one validated feature-plan collection. */
|
|
936
|
+
export interface RenderFeaturePlanRevisionEntry {
|
|
937
|
+
readonly featureIdentity: string;
|
|
938
|
+
readonly generation: number;
|
|
939
|
+
readonly signature: string;
|
|
940
|
+
readonly order: number;
|
|
941
|
+
}
|
|
942
|
+
|
|
943
|
+
/** Compact graph-owner state for a completely validated feature-plan set. */
|
|
944
|
+
export interface RenderFeaturePlanRevisionState {
|
|
945
|
+
readonly revision: number;
|
|
946
|
+
readonly entries: readonly RenderFeaturePlanRevisionEntry[];
|
|
947
|
+
}
|
|
948
|
+
|
|
949
|
+
/**
|
|
950
|
+
* Advance the plan revision only when the complete canonical plan collection
|
|
951
|
+
* changes. Equality is an exact field comparison; the canonical signatures
|
|
952
|
+
* have already been recomputed by validation before this helper is called.
|
|
953
|
+
*/
|
|
954
|
+
export function updateRenderFeaturePlanRevision(
|
|
955
|
+
previous: RenderFeaturePlanRevisionState,
|
|
956
|
+
plans: readonly RenderFeaturePlannedFrame[],
|
|
957
|
+
executions: readonly RenderFeaturePlanExecution[],
|
|
958
|
+
): RenderFeaturePlanRevisionState {
|
|
959
|
+
if (
|
|
960
|
+
plans.length === previous.entries.length &&
|
|
961
|
+
plans.every((planned, index) => {
|
|
962
|
+
const prior = previous.entries[index];
|
|
963
|
+
return (
|
|
964
|
+
prior !== undefined &&
|
|
965
|
+
prior.featureIdentity === planned.featureIdentity &&
|
|
966
|
+
prior.generation === planned.generation &&
|
|
967
|
+
prior.signature === planned.signature &&
|
|
968
|
+
prior.order === (executions[index]?.order ?? -1)
|
|
969
|
+
);
|
|
970
|
+
})
|
|
971
|
+
) {
|
|
972
|
+
return previous;
|
|
973
|
+
}
|
|
974
|
+
const entries = plans.map((planned, index) => ({
|
|
975
|
+
featureIdentity: planned.featureIdentity,
|
|
976
|
+
generation: planned.generation,
|
|
977
|
+
signature: planned.signature,
|
|
978
|
+
order: executions[index]?.order ?? -1,
|
|
979
|
+
}));
|
|
980
|
+
return {
|
|
981
|
+
revision: previous.revision + 1,
|
|
982
|
+
entries: Object.freeze(entries),
|
|
983
|
+
};
|
|
984
|
+
}
|
|
985
|
+
|
|
791
986
|
/** A frame-local graph candidate that is committed only after compilation. */
|
|
792
987
|
export interface RenderFeatureGraphCandidate {
|
|
793
988
|
readonly plans: readonly RenderFeaturePlannedFrame[];
|
|
@@ -796,16 +991,22 @@ export interface RenderFeatureGraphCandidate {
|
|
|
796
991
|
import('../fullscreen-post-process-pass').PostProcessShaderEntry
|
|
797
992
|
>;
|
|
798
993
|
/**
|
|
799
|
-
* Physical
|
|
800
|
-
*
|
|
801
|
-
* signature is unchanged; otherwise queue retirement
|
|
802
|
-
* still referenced by the memoized graph.
|
|
994
|
+
* Physical transient graphics resources are imported into the compiled
|
|
995
|
+
* graph. Their lease therefore needs a new graph even when the declarative
|
|
996
|
+
* plan signature is unchanged; otherwise queue retirement could destroy a
|
|
997
|
+
* buffer still referenced by the memoized graph. Retired GPU-work leases are
|
|
998
|
+
* kept in the completion batch but are not imported by this candidate and do
|
|
999
|
+
* not require a graph revision on their own.
|
|
803
1000
|
*/
|
|
804
1001
|
readonly preparedResourceKey?: string;
|
|
805
1002
|
/** Release candidate-owned prepared resources when graph promotion fails. */
|
|
806
1003
|
readonly onRejected?: () => void;
|
|
807
1004
|
/** Publish candidate-owned runtime declarations only after graph promotion. */
|
|
808
1005
|
readonly onAccepted?: () => void;
|
|
1006
|
+
/** Consume producer frame state only after the command buffer is submitted. */
|
|
1007
|
+
readonly onSubmitted?: () => void;
|
|
1008
|
+
/** Discard producer frame state after graph execution/submission aborts. */
|
|
1009
|
+
readonly onAborted?: () => void;
|
|
809
1010
|
/** Discard candidate-only resources when a base graph is kept as fallback. */
|
|
810
1011
|
readonly onAbandoned?: () => void;
|
|
811
1012
|
}
|
|
@@ -813,6 +1014,139 @@ export interface RenderFeatureGraphCandidate {
|
|
|
813
1014
|
const featureGraphStates = new WeakMap<RenderSystemInternals, RenderFeatureGraphRuntimeState>();
|
|
814
1015
|
const graphDeviceGenerations = new WeakMap<object, number>();
|
|
815
1016
|
|
|
1017
|
+
interface MutableRenderFeatureGraphInspection {
|
|
1018
|
+
planRevisionState: RenderFeaturePlanRevisionState;
|
|
1019
|
+
signatureValidationCalls: number;
|
|
1020
|
+
signatureValidationBytes: number;
|
|
1021
|
+
signatureValidationChars: number;
|
|
1022
|
+
signatureValidationCpuMs: number;
|
|
1023
|
+
signatureValidationCacheHits: number;
|
|
1024
|
+
signatureValidationCacheMisses: number;
|
|
1025
|
+
ensureCalls: number;
|
|
1026
|
+
reuseHits: number;
|
|
1027
|
+
rebuildAttempts: number;
|
|
1028
|
+
compileAttempts: number;
|
|
1029
|
+
compileSuccesses: number;
|
|
1030
|
+
compileFailures: number;
|
|
1031
|
+
validationFailures: number;
|
|
1032
|
+
buildFailures: number;
|
|
1033
|
+
compileCpuMs: number;
|
|
1034
|
+
candidatesWithPreparedBatches: number;
|
|
1035
|
+
preparedKeyChanges: number;
|
|
1036
|
+
accepted: number;
|
|
1037
|
+
rejected: number;
|
|
1038
|
+
abandoned: number;
|
|
1039
|
+
lastPlanSignature: string;
|
|
1040
|
+
lastTopologyKey: string | undefined;
|
|
1041
|
+
lastPreparedResourceKey: string | undefined;
|
|
1042
|
+
preparedKeyObserved: boolean;
|
|
1043
|
+
}
|
|
1044
|
+
|
|
1045
|
+
const featureGraphInspections = new WeakMap<
|
|
1046
|
+
RenderSystemInternals,
|
|
1047
|
+
MutableRenderFeatureGraphInspection
|
|
1048
|
+
>();
|
|
1049
|
+
|
|
1050
|
+
function mutableFeatureGraphInspection(
|
|
1051
|
+
internals: RenderSystemInternals,
|
|
1052
|
+
): MutableRenderFeatureGraphInspection {
|
|
1053
|
+
const existing = featureGraphInspections.get(internals);
|
|
1054
|
+
if (existing !== undefined) return existing;
|
|
1055
|
+
const created: MutableRenderFeatureGraphInspection = {
|
|
1056
|
+
planRevisionState: { revision: 0, entries: [] },
|
|
1057
|
+
signatureValidationCalls: 0,
|
|
1058
|
+
signatureValidationBytes: 0,
|
|
1059
|
+
signatureValidationChars: 0,
|
|
1060
|
+
signatureValidationCpuMs: 0,
|
|
1061
|
+
signatureValidationCacheHits: 0,
|
|
1062
|
+
signatureValidationCacheMisses: 0,
|
|
1063
|
+
ensureCalls: 0,
|
|
1064
|
+
reuseHits: 0,
|
|
1065
|
+
rebuildAttempts: 0,
|
|
1066
|
+
compileAttempts: 0,
|
|
1067
|
+
compileSuccesses: 0,
|
|
1068
|
+
compileFailures: 0,
|
|
1069
|
+
validationFailures: 0,
|
|
1070
|
+
buildFailures: 0,
|
|
1071
|
+
compileCpuMs: 0,
|
|
1072
|
+
candidatesWithPreparedBatches: 0,
|
|
1073
|
+
preparedKeyChanges: 0,
|
|
1074
|
+
accepted: 0,
|
|
1075
|
+
rejected: 0,
|
|
1076
|
+
abandoned: 0,
|
|
1077
|
+
lastPlanSignature: '',
|
|
1078
|
+
lastTopologyKey: undefined,
|
|
1079
|
+
lastPreparedResourceKey: undefined,
|
|
1080
|
+
preparedKeyObserved: false,
|
|
1081
|
+
};
|
|
1082
|
+
featureGraphInspections.set(internals, created);
|
|
1083
|
+
return created;
|
|
1084
|
+
}
|
|
1085
|
+
|
|
1086
|
+
export function getRenderFeatureGraphInspection(
|
|
1087
|
+
internals: RenderSystemInternals,
|
|
1088
|
+
): RenderFeatureGraphInspection {
|
|
1089
|
+
const metrics = mutableFeatureGraphInspection(internals);
|
|
1090
|
+
return Object.freeze({
|
|
1091
|
+
planRevision: metrics.planRevisionState.revision,
|
|
1092
|
+
signatureValidationCalls: metrics.signatureValidationCalls,
|
|
1093
|
+
signatureValidationBytes: metrics.signatureValidationBytes,
|
|
1094
|
+
signatureValidationChars: metrics.signatureValidationChars,
|
|
1095
|
+
signatureValidationCpuMs: metrics.signatureValidationCpuMs,
|
|
1096
|
+
signatureValidationCacheHits: metrics.signatureValidationCacheHits,
|
|
1097
|
+
signatureValidationCacheMisses: metrics.signatureValidationCacheMisses,
|
|
1098
|
+
ensureCalls: metrics.ensureCalls,
|
|
1099
|
+
reuseHits: metrics.reuseHits,
|
|
1100
|
+
rebuildAttempts: metrics.rebuildAttempts,
|
|
1101
|
+
compileAttempts: metrics.compileAttempts,
|
|
1102
|
+
compileSuccesses: metrics.compileSuccesses,
|
|
1103
|
+
compileFailures: metrics.compileFailures,
|
|
1104
|
+
validationFailures: metrics.validationFailures,
|
|
1105
|
+
buildFailures: metrics.buildFailures,
|
|
1106
|
+
compileCpuMs: metrics.compileCpuMs,
|
|
1107
|
+
candidatesWithPreparedBatches: metrics.candidatesWithPreparedBatches,
|
|
1108
|
+
preparedKeyChanges: metrics.preparedKeyChanges,
|
|
1109
|
+
accepted: metrics.accepted,
|
|
1110
|
+
rejected: metrics.rejected,
|
|
1111
|
+
abandoned: metrics.abandoned,
|
|
1112
|
+
last: Object.freeze({
|
|
1113
|
+
planSignature: metrics.lastPlanSignature,
|
|
1114
|
+
topologyKey: metrics.lastTopologyKey,
|
|
1115
|
+
preparedResourceKey: metrics.lastPreparedResourceKey,
|
|
1116
|
+
}),
|
|
1117
|
+
});
|
|
1118
|
+
}
|
|
1119
|
+
|
|
1120
|
+
export function recordRenderFeatureCandidate(
|
|
1121
|
+
internals: RenderSystemInternals,
|
|
1122
|
+
candidate: RenderFeatureGraphCandidate,
|
|
1123
|
+
): void {
|
|
1124
|
+
const metrics = mutableFeatureGraphInspection(internals);
|
|
1125
|
+
if (
|
|
1126
|
+
metrics.preparedKeyObserved &&
|
|
1127
|
+
metrics.lastPreparedResourceKey !== candidate.preparedResourceKey
|
|
1128
|
+
) {
|
|
1129
|
+
metrics.preparedKeyChanges += 1;
|
|
1130
|
+
}
|
|
1131
|
+
metrics.preparedKeyObserved = true;
|
|
1132
|
+
metrics.lastPreparedResourceKey = candidate.preparedResourceKey;
|
|
1133
|
+
if (candidate.preparedResourceKey !== undefined) {
|
|
1134
|
+
metrics.candidatesWithPreparedBatches += 1;
|
|
1135
|
+
}
|
|
1136
|
+
}
|
|
1137
|
+
|
|
1138
|
+
function recordRenderFeatureCandidateEvent(
|
|
1139
|
+
internals: RenderSystemInternals,
|
|
1140
|
+
candidate: RenderFeatureGraphCandidate,
|
|
1141
|
+
event: 'accepted' | 'rejected' | 'abandoned',
|
|
1142
|
+
): void {
|
|
1143
|
+
const metrics = mutableFeatureGraphInspection(internals);
|
|
1144
|
+
metrics[event] += 1;
|
|
1145
|
+
if (event === 'accepted') candidate.onAccepted?.();
|
|
1146
|
+
else if (event === 'rejected') candidate.onRejected?.();
|
|
1147
|
+
else candidate.onAbandoned?.();
|
|
1148
|
+
}
|
|
1149
|
+
|
|
816
1150
|
interface TimingInstrumentationState {
|
|
817
1151
|
readonly instrumentation: RenderGraphPassInstrumentation<RenderPipelineFrame>;
|
|
818
1152
|
setCapture(capture: GpuPassTimingCapture | undefined): void;
|
|
@@ -831,6 +1165,11 @@ type CompiledGraphTargetAccess = CompiledRenderGraph<RenderPipelineFrame> & {
|
|
|
831
1165
|
readonly getColorTargetTexture: (name: string) => Texture | undefined;
|
|
832
1166
|
};
|
|
833
1167
|
|
|
1168
|
+
type ResolvedDepthPassExecution =
|
|
1169
|
+
import('@forgeax/engine-render-graph').RenderGraphPassExecution & {
|
|
1170
|
+
readonly resolvedDepthStencilAttachmentView?: TextureView;
|
|
1171
|
+
};
|
|
1172
|
+
|
|
834
1173
|
export function getRenderFeatureGraphState(
|
|
835
1174
|
internals: RenderSystemInternals,
|
|
836
1175
|
): RenderFeatureGraphRuntimeState {
|
|
@@ -900,15 +1239,46 @@ export function resolvePostProcessChainAdmission(
|
|
|
900
1239
|
|
|
901
1240
|
function validateRenderFeaturePlans(
|
|
902
1241
|
plans: readonly RenderFeaturePlannedFrame[],
|
|
1242
|
+
metrics?: MutableRenderFeatureGraphInspection,
|
|
903
1243
|
): Result<readonly RenderFeaturePlanExecution[], RenderError> {
|
|
904
1244
|
const identities = new Set<string>();
|
|
905
1245
|
const projected: RenderFeaturePlanExecution[] = [];
|
|
906
1246
|
let previousOrder = -1;
|
|
907
1247
|
for (const [order, planned] of plans.entries()) {
|
|
908
1248
|
const execution = getRenderFeaturePlanExecutionProjection(planned);
|
|
1249
|
+
const signatureMetrics =
|
|
1250
|
+
metrics === undefined ? undefined : { calls: 0, typedArrayBytes: 0, outputChars: 0 };
|
|
1251
|
+
const started =
|
|
1252
|
+
metrics === undefined
|
|
1253
|
+
? 0
|
|
1254
|
+
: typeof performance === 'undefined'
|
|
1255
|
+
? Date.now()
|
|
1256
|
+
: performance.now();
|
|
1257
|
+
// The host records detached structural evidence, but graph admission must
|
|
1258
|
+
// check it again so a mutation between the two synchronous stages cannot
|
|
1259
|
+
// smuggle a stale plan into the compiled graph. Only candidates without
|
|
1260
|
+
// evidence fall back to the canonical serializer.
|
|
1261
|
+
const signatureCacheHit = renderFeaturePlanSignatureEvidenceMatches(
|
|
1262
|
+
planned.plan,
|
|
1263
|
+
planned.signature,
|
|
1264
|
+
);
|
|
1265
|
+
if (metrics !== undefined) {
|
|
1266
|
+
if (signatureCacheHit) metrics.signatureValidationCacheHits += 1;
|
|
1267
|
+
else metrics.signatureValidationCacheMisses += 1;
|
|
1268
|
+
}
|
|
1269
|
+
const recomputedSignature = signatureCacheHit
|
|
1270
|
+
? planned.signature
|
|
1271
|
+
: renderFeaturePlanSignature(planned.plan, signatureMetrics);
|
|
1272
|
+
if (metrics !== undefined) {
|
|
1273
|
+
const now = typeof performance === 'undefined' ? Date.now() : performance.now();
|
|
1274
|
+
metrics.signatureValidationCalls += signatureMetrics?.calls ?? 0;
|
|
1275
|
+
metrics.signatureValidationBytes += signatureMetrics?.typedArrayBytes ?? 0;
|
|
1276
|
+
metrics.signatureValidationChars += signatureMetrics?.outputChars ?? 0;
|
|
1277
|
+
metrics.signatureValidationCpuMs += now - started;
|
|
1278
|
+
}
|
|
909
1279
|
if (
|
|
910
1280
|
identities.has(planned.featureIdentity) ||
|
|
911
|
-
planned.signature !==
|
|
1281
|
+
planned.signature !== recomputedSignature ||
|
|
912
1282
|
execution === undefined ||
|
|
913
1283
|
execution.featureIdentity !== planned.featureIdentity ||
|
|
914
1284
|
execution.order <= previousOrder
|
|
@@ -931,7 +1301,7 @@ function commitFeatureCandidate(
|
|
|
931
1301
|
// Publish renderer-owned declarations only after their device resources have
|
|
932
1302
|
// been admitted. If the acceptance hook throws, the previously accepted
|
|
933
1303
|
// graph/state pair remains visible to the caller.
|
|
934
|
-
candidate
|
|
1304
|
+
recordRenderFeatureCandidateEvent(internals, candidate, 'accepted');
|
|
935
1305
|
const state = getRenderFeatureGraphState(internals);
|
|
936
1306
|
state.plans = candidate.plans;
|
|
937
1307
|
state.fullscreenEffects = candidate.fullscreenEffects;
|
|
@@ -949,10 +1319,12 @@ function topologyOf(
|
|
|
949
1319
|
shadowMapSize: number | undefined,
|
|
950
1320
|
gpuDriven: PreparedGpuDrivenFrame | undefined,
|
|
951
1321
|
featureGraphCandidate: RenderFeatureGraphCandidate | undefined,
|
|
1322
|
+
featurePlanRevision: number,
|
|
952
1323
|
cubeCaptureState: CubeCaptureGraphState | undefined,
|
|
953
1324
|
transmissionDemand: TransmissionDemand | undefined,
|
|
954
1325
|
volumetricFog: ExtractedVolumetricFog | undefined,
|
|
955
1326
|
standardLighting: StandardTopologyInputValue | undefined,
|
|
1327
|
+
ssr: SsrSpatialAdmission | undefined,
|
|
956
1328
|
): Result<RenderPipelineTopology, RhiError> {
|
|
957
1329
|
const cascadeCount = Math.max(1, Math.min(4, Math.round(lights.cascadeCount ?? 1))) as
|
|
958
1330
|
| 1
|
|
@@ -1008,12 +1380,15 @@ function topologyOf(
|
|
|
1008
1380
|
: volumetricFog?.lightKind === undefined
|
|
1009
1381
|
? lights.directional
|
|
1010
1382
|
: undefined;
|
|
1383
|
+
const preparedLut =
|
|
1384
|
+
frameState.pendingStandardLutGpuResources ?? frameState.standardLutGpuResources;
|
|
1011
1385
|
return ok({
|
|
1012
1386
|
pipelineId: STANDARD_PIPELINE_ID,
|
|
1013
1387
|
standardProfile: internals.standardProfile,
|
|
1014
1388
|
config,
|
|
1015
1389
|
clearOnly,
|
|
1016
1390
|
reflectionFallback: { enabled: frameState.reflectionFallbackDemand === true },
|
|
1391
|
+
ssr,
|
|
1017
1392
|
surface: {
|
|
1018
1393
|
width,
|
|
1019
1394
|
height,
|
|
@@ -1026,6 +1401,27 @@ function topologyOf(
|
|
|
1026
1401
|
antialias: camera.antialias,
|
|
1027
1402
|
bloom: camera.bloom,
|
|
1028
1403
|
},
|
|
1404
|
+
atmosphere: !clearOnly && frameState.environmentFrame?.source.kind === 'atmosphere',
|
|
1405
|
+
output: {
|
|
1406
|
+
autoExposure:
|
|
1407
|
+
!clearOnly &&
|
|
1408
|
+
camera.output?.exposure.kind === 'auto' &&
|
|
1409
|
+
(frameState.pendingAutoExposureGpuResources ?? frameState.autoExposureGpuResources) !==
|
|
1410
|
+
undefined,
|
|
1411
|
+
whiteBalance:
|
|
1412
|
+
!clearOnly &&
|
|
1413
|
+
camera.output !== undefined &&
|
|
1414
|
+
(camera.output.temperature !== 6504 || camera.output.tint !== 0),
|
|
1415
|
+
temperature: camera.output?.temperature ?? 6504,
|
|
1416
|
+
tint: camera.output?.tint ?? 0,
|
|
1417
|
+
colorLut:
|
|
1418
|
+
!clearOnly &&
|
|
1419
|
+
(camera.output?.colorLutStrength ?? 0) > 0 &&
|
|
1420
|
+
(frameState.pendingStandardLutGpuResources ?? frameState.standardLutGpuResources) !==
|
|
1421
|
+
undefined,
|
|
1422
|
+
colorLutStrength: camera.output?.colorLutStrength ?? 0,
|
|
1423
|
+
...(preparedLut === undefined ? {} : { lutSourceKey: preparedLut.sourceKey }),
|
|
1424
|
+
},
|
|
1029
1425
|
temporal: {
|
|
1030
1426
|
taa: camera.antialias === 'taa',
|
|
1031
1427
|
motionBlur: isMotionBlurTemporalDemand(camera.motionBlur),
|
|
@@ -1093,9 +1489,7 @@ function topologyOf(
|
|
|
1093
1489
|
maxColorAttachments: internals.device.caps.maxColorAttachments,
|
|
1094
1490
|
},
|
|
1095
1491
|
featureTopologySignature: JSON.stringify({
|
|
1096
|
-
|
|
1097
|
-
featureGraphCandidate?.plans ?? getRenderFeatureGraphState(internals).plans,
|
|
1098
|
-
),
|
|
1492
|
+
planRevision: featurePlanRevision,
|
|
1099
1493
|
fullscreenEffects: featurePostEffectDeclarations,
|
|
1100
1494
|
preparedResourceKey: featureGraphCandidate?.preparedResourceKey ?? '',
|
|
1101
1495
|
cubeCaptureSlots: cubeCaptureState?.work.length ?? 0,
|
|
@@ -1264,7 +1658,9 @@ function resolveTargetBindings(
|
|
|
1264
1658
|
frame.runtime as RenderSystemInternals,
|
|
1265
1659
|
frame.frameState,
|
|
1266
1660
|
frame.pipelineState,
|
|
1267
|
-
|
|
1661
|
+
// This callback is reached only for an actual feature draw. A scene
|
|
1662
|
+
// containing only particles still needs the pipeline's View/light ABI.
|
|
1663
|
+
true,
|
|
1268
1664
|
frame.bindGroupCounts,
|
|
1269
1665
|
{
|
|
1270
1666
|
directionalShadow: frame.frameState.currentDirectionalShadowView ?? undefined,
|
|
@@ -1351,23 +1747,41 @@ export function ensureCompiledFrameGraph(
|
|
|
1351
1747
|
volumeTopologyCandidate = false,
|
|
1352
1748
|
standardLighting?: StandardTopologyInputValue,
|
|
1353
1749
|
onRecoveryError?: (error: unknown) => void,
|
|
1750
|
+
ssr?: SsrSpatialAdmission,
|
|
1354
1751
|
): CompiledRenderGraph<RenderPipelineFrame> | null {
|
|
1752
|
+
const featureMetrics = mutableFeatureGraphInspection(internals);
|
|
1753
|
+
featureMetrics.ensureCalls += 1;
|
|
1355
1754
|
const requestedStandardLightingSignature = standardLightingTopologySignature(standardLighting);
|
|
1356
1755
|
const lastKnownGood = (): CompiledRenderGraph<RenderPipelineFrame> | null =>
|
|
1357
1756
|
frameState.compiledFrameGraph !== null &&
|
|
1757
|
+
!hasSubmissionSensitiveFeatures(getRenderFeatureGraphState(internals).plans) &&
|
|
1358
1758
|
frameState.standardLightingGraphSignature === requestedStandardLightingSignature
|
|
1359
1759
|
? frameState.compiledFrameGraph
|
|
1360
1760
|
: null;
|
|
1361
1761
|
const surfaceWidth = Math.max(1, width);
|
|
1362
1762
|
const surfaceHeight = Math.max(1, height);
|
|
1363
1763
|
const featurePlans = featureGraphCandidate?.plans ?? getRenderFeatureGraphState(internals).plans;
|
|
1364
|
-
const projectedFeaturePlans = validateRenderFeaturePlans(featurePlans);
|
|
1764
|
+
const projectedFeaturePlans = validateRenderFeaturePlans(featurePlans, featureMetrics);
|
|
1365
1765
|
if (!projectedFeaturePlans.ok) {
|
|
1766
|
+
featureMetrics.validationFailures += 1;
|
|
1366
1767
|
onRecoveryError?.(projectedFeaturePlans.error);
|
|
1367
1768
|
reportRenderFeatureGraphError(internals, projectedFeaturePlans.error);
|
|
1368
|
-
featureGraphCandidate
|
|
1769
|
+
if (featureGraphCandidate !== undefined) {
|
|
1770
|
+
recordRenderFeatureCandidateEvent(internals, featureGraphCandidate, 'rejected');
|
|
1771
|
+
}
|
|
1369
1772
|
return volumeTopologyCandidate ? null : lastKnownGood();
|
|
1370
1773
|
}
|
|
1774
|
+
const nextPlanRevision = updateRenderFeaturePlanRevision(
|
|
1775
|
+
featureMetrics.planRevisionState,
|
|
1776
|
+
featurePlans,
|
|
1777
|
+
projectedFeaturePlans.value,
|
|
1778
|
+
);
|
|
1779
|
+
if (nextPlanRevision !== featureMetrics.planRevisionState) {
|
|
1780
|
+
featureMetrics.lastPlanSignature = nextPlanRevision.entries
|
|
1781
|
+
.map((entry) => `${entry.featureIdentity}:${entry.signature}`)
|
|
1782
|
+
.join('|');
|
|
1783
|
+
featureMetrics.planRevisionState = nextPlanRevision;
|
|
1784
|
+
}
|
|
1371
1785
|
const topologyResult = topologyOf(
|
|
1372
1786
|
internals,
|
|
1373
1787
|
frameState,
|
|
@@ -1380,15 +1794,20 @@ export function ensureCompiledFrameGraph(
|
|
|
1380
1794
|
shadowMapSize,
|
|
1381
1795
|
gpuDriven,
|
|
1382
1796
|
featureGraphCandidate,
|
|
1797
|
+
featureMetrics.planRevisionState.revision,
|
|
1383
1798
|
cubeCaptureState,
|
|
1384
1799
|
transmissionDemand,
|
|
1385
1800
|
volumetricFog,
|
|
1386
1801
|
standardLighting,
|
|
1802
|
+
ssr,
|
|
1387
1803
|
);
|
|
1388
1804
|
if (!topologyResult.ok) {
|
|
1805
|
+
featureMetrics.buildFailures += 1;
|
|
1389
1806
|
onRecoveryError?.(topologyResult.error);
|
|
1390
1807
|
internals.errorRegistry.fire(topologyResult.error);
|
|
1391
|
-
featureGraphCandidate
|
|
1808
|
+
if (featureGraphCandidate !== undefined) {
|
|
1809
|
+
recordRenderFeatureCandidateEvent(internals, featureGraphCandidate, 'rejected');
|
|
1810
|
+
}
|
|
1392
1811
|
return volumeTopologyCandidate ? null : lastKnownGood();
|
|
1393
1812
|
}
|
|
1394
1813
|
const requestedPostEffects = topologyResult.value.config?.postEffects ?? [];
|
|
@@ -1417,7 +1836,7 @@ export function ensureCompiledFrameGraph(
|
|
|
1417
1836
|
getPipeline(
|
|
1418
1837
|
identity,
|
|
1419
1838
|
built.bindGroupLayout,
|
|
1420
|
-
topologyResult.value.surface.storageFormat as GPUTextureFormat,
|
|
1839
|
+
[topologyResult.value.surface.storageFormat as GPUTextureFormat],
|
|
1421
1840
|
entry,
|
|
1422
1841
|
) !== null
|
|
1423
1842
|
);
|
|
@@ -1428,7 +1847,9 @@ export function ensureCompiledFrameGraph(
|
|
|
1428
1847
|
// Do not publish a candidate whose fullscreen chain is only partially
|
|
1429
1848
|
// ready. Keep the accepted graph (including its prior post-effect chain)
|
|
1430
1849
|
// and retry the same feature candidate on the next frame.
|
|
1431
|
-
featureGraphCandidate
|
|
1850
|
+
if (featureGraphCandidate !== undefined) {
|
|
1851
|
+
recordRenderFeatureCandidateEvent(internals, featureGraphCandidate, 'rejected');
|
|
1852
|
+
}
|
|
1432
1853
|
return acceptedLkg;
|
|
1433
1854
|
}
|
|
1434
1855
|
const topology = postProcessAdmission.pending
|
|
@@ -1442,6 +1863,12 @@ export function ensureCompiledFrameGraph(
|
|
|
1442
1863
|
: topologyResult.value;
|
|
1443
1864
|
const key = JSON.stringify({
|
|
1444
1865
|
topology,
|
|
1866
|
+
// Observation domains are an explicit per-frame graph demand. They are
|
|
1867
|
+
// part of the cache identity so a request made after the ordinary graph
|
|
1868
|
+
// was compiled can admit the matching tone/output capture boundaries on
|
|
1869
|
+
// that receipt without forcing every unobserved frame onto the split
|
|
1870
|
+
// output path.
|
|
1871
|
+
observationCaptureDomains: [...(internals.observationCaptureDomains ?? [])].sort(),
|
|
1445
1872
|
// GPU-driven residency can become available after the first record pass
|
|
1446
1873
|
// (custom mesh handles are resolved into the per-frame projection). The
|
|
1447
1874
|
// topology signature alone is intentionally stable across that lifecycle,
|
|
@@ -1462,11 +1889,13 @@ export function ensureCompiledFrameGraph(
|
|
|
1462
1889
|
]),
|
|
1463
1890
|
});
|
|
1464
1891
|
if (frameState.compiledFrameGraph !== null && frameState.compiledFrameGraphTopologyKey === key) {
|
|
1892
|
+
featureMetrics.reuseHits += 1;
|
|
1893
|
+
featureMetrics.lastTopologyKey = key;
|
|
1465
1894
|
frameState.standardLightingGraphSignature = requestedStandardLightingSignature;
|
|
1466
1895
|
if (featureGraphCandidate !== undefined && !postProcessAdmission.pending) {
|
|
1467
1896
|
commitFeatureCandidate(internals, featureGraphCandidate);
|
|
1468
1897
|
} else if (featureGraphCandidate !== undefined) {
|
|
1469
|
-
featureGraphCandidate
|
|
1898
|
+
recordRenderFeatureCandidateEvent(internals, featureGraphCandidate, 'abandoned');
|
|
1470
1899
|
}
|
|
1471
1900
|
// A candidate flag only describes a possible topology replacement. When
|
|
1472
1901
|
// the derived key is unchanged there is no replacement to stage: reuse the
|
|
@@ -1475,17 +1904,109 @@ export function ensureCompiledFrameGraph(
|
|
|
1475
1904
|
return frameState.compiledFrameGraph;
|
|
1476
1905
|
}
|
|
1477
1906
|
|
|
1907
|
+
featureMetrics.rebuildAttempts += 1;
|
|
1908
|
+
featureMetrics.lastTopologyKey = key;
|
|
1909
|
+
const discardPendingStandardOutput = (): void => {
|
|
1910
|
+
if (frameState.pendingAutoExposureGpuResources !== undefined) {
|
|
1911
|
+
retireAutoExposureGpuResources(frameState.pendingAutoExposureGpuResources);
|
|
1912
|
+
frameState.pendingAutoExposureGpuResources = undefined;
|
|
1913
|
+
}
|
|
1914
|
+
if (frameState.pendingStandardLutGpuResources !== undefined) {
|
|
1915
|
+
retireStandardLutGpuResources(frameState.pendingStandardLutGpuResources);
|
|
1916
|
+
frameState.pendingStandardLutGpuResources = undefined;
|
|
1917
|
+
}
|
|
1918
|
+
};
|
|
1478
1919
|
const builder = new RenderGraphBuilder<RenderPipelineFrame>();
|
|
1920
|
+
const autoExposureResources =
|
|
1921
|
+
topology.output?.autoExposure === true ? importAutoExposureGraphResources(builder) : undefined;
|
|
1922
|
+
if (autoExposureResources !== undefined && !autoExposureResources.ok) {
|
|
1923
|
+
internals.errorRegistry.fire(autoExposureResources.error);
|
|
1924
|
+
featureGraphCandidate?.onRejected?.();
|
|
1925
|
+
discardPendingStandardOutput();
|
|
1926
|
+
return lastKnownGood();
|
|
1927
|
+
}
|
|
1928
|
+
const lutResources =
|
|
1929
|
+
topology.output?.colorLut === true
|
|
1930
|
+
? (() => {
|
|
1931
|
+
const prepared =
|
|
1932
|
+
frameState.pendingStandardLutGpuResources ?? frameState.standardLutGpuResources;
|
|
1933
|
+
if (prepared === undefined) return undefined;
|
|
1934
|
+
const texture = builder.importTexture(
|
|
1935
|
+
'standard-color-lut-source',
|
|
1936
|
+
{
|
|
1937
|
+
format: 'rgba16float',
|
|
1938
|
+
size: {
|
|
1939
|
+
width: prepared.size,
|
|
1940
|
+
height: prepared.size,
|
|
1941
|
+
depthOrArrayLayers: prepared.size,
|
|
1942
|
+
},
|
|
1943
|
+
dimension: '3d',
|
|
1944
|
+
usage: GPU_TEXTURE_USAGE_TEXTURE_BINDING,
|
|
1945
|
+
},
|
|
1946
|
+
(frame) =>
|
|
1947
|
+
(
|
|
1948
|
+
(frame as _InternalRenderPipelineContext).frameState
|
|
1949
|
+
.pendingStandardLutGpuResources ??
|
|
1950
|
+
(frame as _InternalRenderPipelineContext).frameState.standardLutGpuResources
|
|
1951
|
+
)?.texture ?? prepared.texture,
|
|
1952
|
+
);
|
|
1953
|
+
if (!texture.ok) return texture;
|
|
1954
|
+
const view = builder.importView(
|
|
1955
|
+
texture.value,
|
|
1956
|
+
{ label: 'standard-color-lut-source.view', dimension: '3d' },
|
|
1957
|
+
(frame) =>
|
|
1958
|
+
(
|
|
1959
|
+
(frame as _InternalRenderPipelineContext).frameState
|
|
1960
|
+
.pendingStandardLutGpuResources ??
|
|
1961
|
+
(frame as _InternalRenderPipelineContext).frameState.standardLutGpuResources
|
|
1962
|
+
)?.view ?? prepared.view,
|
|
1963
|
+
);
|
|
1964
|
+
if (!view.ok) return view;
|
|
1965
|
+
return ok({ texture: texture.value, view: view.value, prepared });
|
|
1966
|
+
})()
|
|
1967
|
+
: undefined;
|
|
1968
|
+
if (lutResources !== undefined && !lutResources.ok) {
|
|
1969
|
+
internals.errorRegistry.fire(lutResources.error);
|
|
1970
|
+
featureGraphCandidate?.onRejected?.();
|
|
1971
|
+
discardPendingStandardOutput();
|
|
1972
|
+
return lastKnownGood();
|
|
1973
|
+
}
|
|
1479
1974
|
const taaHistory = camera.antialias === 'taa' ? importTemporalHistoryTargets(builder) : undefined;
|
|
1975
|
+
const ssrHistory = ssr?.status === 'admitted' ? importSsrHistoryTargets(builder) : undefined;
|
|
1480
1976
|
let projectedFeatures = false;
|
|
1977
|
+
const featureProjection = createRenderFeatureProjectionState();
|
|
1978
|
+
let featureShadows:
|
|
1979
|
+
| ReturnType<typeof projectRenderFeatureShadows<RenderPipelineFrame>>
|
|
1980
|
+
| undefined;
|
|
1481
1981
|
let projectedGpuDriven = false;
|
|
1482
1982
|
const built = frameState.activePipeline.build(
|
|
1483
1983
|
{
|
|
1484
1984
|
graph: builder,
|
|
1985
|
+
observationCaptureDomains: internals.observationCaptureDomains,
|
|
1986
|
+
...(autoExposureResources?.ok === true
|
|
1987
|
+
? { standardOutput: { autoExposure: autoExposureResources.value } }
|
|
1988
|
+
: {}),
|
|
1989
|
+
...(lutResources?.ok === true
|
|
1990
|
+
? {
|
|
1991
|
+
standardOutput: {
|
|
1992
|
+
...(autoExposureResources?.ok === true
|
|
1993
|
+
? { autoExposure: autoExposureResources.value }
|
|
1994
|
+
: {}),
|
|
1995
|
+
colorLut: {
|
|
1996
|
+
view: lutResources.value.view,
|
|
1997
|
+
sampler: lutResources.value.prepared.sampler,
|
|
1998
|
+
strength: lutResources.value.prepared.strength,
|
|
1999
|
+
bindGroupLayout: lutResources.value.prepared.bindGroupLayout,
|
|
2000
|
+
bindGroup: lutResources.value.prepared.bindGroup,
|
|
2001
|
+
},
|
|
2002
|
+
},
|
|
2003
|
+
}
|
|
2004
|
+
: {}),
|
|
1485
2005
|
...(standardLighting === undefined ? {} : { standardLighting }),
|
|
1486
2006
|
capabilities: { rgba16floatRenderable: internals.device.caps.rgba16floatRenderable },
|
|
1487
2007
|
...(occlusion === undefined ? {} : { occlusion }),
|
|
1488
2008
|
...(taaHistory === undefined ? {} : { taaHistory }),
|
|
2009
|
+
...(ssrHistory === undefined ? {} : { ssrHistory }),
|
|
1489
2010
|
encodeTransmissionMip: ({ pass, resources, source }) => {
|
|
1490
2011
|
const sourceView = resources.textureView(source);
|
|
1491
2012
|
if (!sourceView.ok) throw sourceView.error;
|
|
@@ -1497,14 +2018,53 @@ export function ensureCompiledFrameGraph(
|
|
|
1497
2018
|
projectedGpuDriven = true;
|
|
1498
2019
|
return gpuDriven.project(builder, target.format, target.sampleCount);
|
|
1499
2020
|
},
|
|
1500
|
-
|
|
2021
|
+
...(gpuDriven?.projectShadow === undefined
|
|
2022
|
+
? {}
|
|
2023
|
+
: {
|
|
2024
|
+
projectGpuDrivenShadow: (identity) =>
|
|
2025
|
+
gpuDriven.projectShadow?.(builder, identity) ?? ok(undefined),
|
|
2026
|
+
}),
|
|
2027
|
+
contributeShadowFeatures: () =>
|
|
2028
|
+
(featureShadows ??= projectRenderFeatureShadows(
|
|
2029
|
+
builder,
|
|
2030
|
+
projectedFeaturePlans.value,
|
|
2031
|
+
featureProjection,
|
|
2032
|
+
)),
|
|
2033
|
+
contributeFeatures: (
|
|
2034
|
+
targets,
|
|
2035
|
+
semanticTargets = [],
|
|
2036
|
+
namedTargets = {},
|
|
2037
|
+
standardSurfaceAccesses = [],
|
|
2038
|
+
) => {
|
|
1501
2039
|
if (projectedFeatures) return ok(undefined);
|
|
1502
2040
|
projectedFeatures = true;
|
|
1503
2041
|
if (projectedFeaturePlans.value.length === 0) return ok(undefined);
|
|
1504
2042
|
const resolveTarget = targetResolver(targets, semanticTargets, namedTargets);
|
|
1505
2043
|
const projected = projectPlanExecutions(builder, projectedFeaturePlans.value, {
|
|
2044
|
+
state: featureProjection,
|
|
1506
2045
|
resolveTarget,
|
|
2046
|
+
standardSurfaceAccesses,
|
|
1507
2047
|
resolveBindings: (input) => resolveTargetBindings(input, featurePostProcessEntries),
|
|
2048
|
+
resolveStandardLighting: (frame, pipeline) => {
|
|
2049
|
+
const context = frame as import('./render-context')._InternalRenderPipelineContext;
|
|
2050
|
+
if (context.standardLighting?.kind !== 'clustered') return undefined;
|
|
2051
|
+
const layout = (
|
|
2052
|
+
pipeline as RenderPipeline & {
|
|
2053
|
+
getBindGroupLayout?: (index: number) => BindGroupLayout;
|
|
2054
|
+
}
|
|
2055
|
+
).getBindGroupLayout?.(2);
|
|
2056
|
+
if (layout === undefined) return undefined;
|
|
2057
|
+
return (
|
|
2058
|
+
createStandardSurfaceLightingBindGroup(
|
|
2059
|
+
context.runtime,
|
|
2060
|
+
layout,
|
|
2061
|
+
context.standardLighting.prepared.layout.grid,
|
|
2062
|
+
context.hdrpSsaoBlurredView === undefined
|
|
2063
|
+
? { enabled: false }
|
|
2064
|
+
: { enabled: true, ssaoBlurredView: context.hdrpSsaoBlurredView },
|
|
2065
|
+
) ?? undefined
|
|
2066
|
+
);
|
|
2067
|
+
},
|
|
1508
2068
|
reportError: (error) => reportRenderFeatureGraphError(internals, error),
|
|
1509
2069
|
});
|
|
1510
2070
|
return projected.ok ? ok(undefined) : projected;
|
|
@@ -1525,19 +2085,33 @@ export function ensureCompiledFrameGraph(
|
|
|
1525
2085
|
topology,
|
|
1526
2086
|
);
|
|
1527
2087
|
if (!built.ok) {
|
|
2088
|
+
featureMetrics.buildFailures += 1;
|
|
1528
2089
|
onRecoveryError?.(built.error);
|
|
1529
2090
|
internals.errorRegistry.fire(built.error);
|
|
1530
2091
|
featureGraphCandidate?.onRejected?.();
|
|
2092
|
+
discardPendingStandardOutput();
|
|
2093
|
+
if (featureGraphCandidate !== undefined) {
|
|
2094
|
+
recordRenderFeatureCandidateEvent(internals, featureGraphCandidate, 'rejected');
|
|
2095
|
+
}
|
|
1531
2096
|
return volumeTopologyCandidate ? null : lastKnownGood();
|
|
1532
2097
|
}
|
|
2098
|
+
featureMetrics.compileAttempts += 1;
|
|
2099
|
+
const compileStarted = typeof performance === 'undefined' ? Date.now() : performance.now();
|
|
1533
2100
|
const compiled = builder.compile({
|
|
1534
2101
|
device: internals.device,
|
|
1535
2102
|
surfaceSize: { width: surfaceWidth, height: surfaceHeight },
|
|
1536
2103
|
});
|
|
2104
|
+
featureMetrics.compileCpuMs +=
|
|
2105
|
+
(typeof performance === 'undefined' ? Date.now() : performance.now()) - compileStarted;
|
|
1537
2106
|
if (!compiled.ok) {
|
|
2107
|
+
featureMetrics.compileFailures += 1;
|
|
1538
2108
|
onRecoveryError?.(compiled.error);
|
|
1539
2109
|
internals.errorRegistry.fire(compiled.error);
|
|
1540
2110
|
featureGraphCandidate?.onRejected?.();
|
|
2111
|
+
discardPendingStandardOutput();
|
|
2112
|
+
if (featureGraphCandidate !== undefined) {
|
|
2113
|
+
recordRenderFeatureCandidateEvent(internals, featureGraphCandidate, 'rejected');
|
|
2114
|
+
}
|
|
1541
2115
|
return lastKnownGood();
|
|
1542
2116
|
}
|
|
1543
2117
|
const previous = frameState.compiledFrameGraph;
|
|
@@ -1552,21 +2126,31 @@ export function ensureCompiledFrameGraph(
|
|
|
1552
2126
|
frameState.compiledFrameGraphGeneration += 1;
|
|
1553
2127
|
const compiledTargets = compiled.value as CompiledGraphTargetAccess;
|
|
1554
2128
|
frameState.graphGeneration += 1;
|
|
2129
|
+
featureMetrics.compileSuccesses += 1;
|
|
1555
2130
|
frameState.perFrameGraph = {
|
|
1556
2131
|
getColorTargetDescriptor: (name) => compiledTargets.getColorTargetDescriptor(name),
|
|
1557
2132
|
getColorTargetView: (name) => compiledTargets.getColorTargetView(name),
|
|
1558
2133
|
getColorTargetTexture: (name) => compiledTargets.getColorTargetTexture(name),
|
|
1559
2134
|
graphGeneration: frameState.graphGeneration,
|
|
1560
2135
|
};
|
|
2136
|
+
// View buffer replacement is safe to retire once the compiled graph owns
|
|
2137
|
+
// the new imports. Shadow cache publication remains submit-transactional
|
|
2138
|
+
// and is committed only by executeCompiledFrameGraph's onSubmitted hook.
|
|
2139
|
+
if (gpuDriven?._commitGpuResourceReplacement !== undefined) {
|
|
2140
|
+
gpuDriven._commitGpuResourceReplacement();
|
|
2141
|
+
} else {
|
|
2142
|
+
// Synthetic/internal prepared projections predating the split own no
|
|
2143
|
+
// shadow cache; retain their original graph-promotion callback.
|
|
2144
|
+
gpuDriven?._commitResourceReplacement();
|
|
2145
|
+
}
|
|
1561
2146
|
const deviceGeneration = internals.deviceScope?.generation;
|
|
1562
2147
|
if (deviceGeneration !== undefined) {
|
|
1563
2148
|
graphDeviceGenerations.set(compiled.value, deviceGeneration);
|
|
1564
2149
|
}
|
|
1565
|
-
gpuDriven?._commitResourceReplacement();
|
|
1566
2150
|
if (featureGraphCandidate !== undefined && !postProcessAdmission.pending) {
|
|
1567
2151
|
commitFeatureCandidate(internals, featureGraphCandidate);
|
|
1568
2152
|
} else if (featureGraphCandidate !== undefined) {
|
|
1569
|
-
featureGraphCandidate
|
|
2153
|
+
recordRenderFeatureCandidateEvent(internals, featureGraphCandidate, 'abandoned');
|
|
1570
2154
|
}
|
|
1571
2155
|
if (!volumeTopologyCandidate && previous !== null) retire(frameState, previous);
|
|
1572
2156
|
return compiled.value;
|
|
@@ -1578,22 +2162,22 @@ export function executeCompiledFrameGraph(
|
|
|
1578
2162
|
frame: RenderPipelineFrame,
|
|
1579
2163
|
encoder: RhiCommandEncoder,
|
|
1580
2164
|
runPass?: import('@forgeax/engine-render-graph').RenderGraphPassRunner,
|
|
1581
|
-
frameHooks?:
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
2165
|
+
frameHooks?:
|
|
2166
|
+
| {
|
|
2167
|
+
readonly afterGraphExecute?: () => Result<void, RhiError>;
|
|
2168
|
+
readonly onSubmitted?: () => void;
|
|
2169
|
+
readonly onAborted?: () => void;
|
|
2170
|
+
}
|
|
2171
|
+
// Keep the pre-submit-hook shape accepted for internal callers that have
|
|
2172
|
+
// not yet migrated to the typed frame hooks object.
|
|
2173
|
+
| (() => void),
|
|
1586
2174
|
readbackFaces?: readonly number[],
|
|
1587
2175
|
onSubmitted?: (completed: Promise<unknown>) => void,
|
|
1588
2176
|
timingCapture?: GpuTimingCapture,
|
|
1589
2177
|
): boolean {
|
|
2178
|
+
const legacySubmitCommit = typeof frameHooks === 'function' ? frameHooks : undefined;
|
|
2179
|
+
const resolvedFrameHooks = typeof frameHooks === 'function' ? undefined : frameHooks;
|
|
1590
2180
|
const graph = frameState.compiledFrameGraph;
|
|
1591
|
-
const invalidatePostProcessModule = (id: string): void => {
|
|
1592
|
-
const entry = internals.lookupPostProcess?.(id);
|
|
1593
|
-
if (entry !== undefined) {
|
|
1594
|
-
internals.invalidateShaderModule?.(postProcessShaderModuleLabel(id, entry.source));
|
|
1595
|
-
}
|
|
1596
|
-
};
|
|
1597
2181
|
const rejectTemporalFrame = (): void => {
|
|
1598
2182
|
if (frameState.temporalFrameInput === undefined) return;
|
|
1599
2183
|
frameState.temporalFrameTransaction.commit({ accepted: false });
|
|
@@ -1601,6 +2185,8 @@ export function executeCompiledFrameGraph(
|
|
|
1601
2185
|
};
|
|
1602
2186
|
if (graph === null) {
|
|
1603
2187
|
timingCapture?.discard();
|
|
2188
|
+
frameState.pendingAutoExposureState = undefined;
|
|
2189
|
+
frameState.pendingStandardLutState = undefined;
|
|
1604
2190
|
settleVolumetricFogGraphCandidate(frameState, false);
|
|
1605
2191
|
rejectTemporalFrame();
|
|
1606
2192
|
return false;
|
|
@@ -1671,14 +2257,327 @@ export function executeCompiledFrameGraph(
|
|
|
1671
2257
|
const transaction = executeRendererFrameTransaction<PreparedCommand>({
|
|
1672
2258
|
build: () => ({ ok: true, value: { command: undefined as never } }),
|
|
1673
2259
|
execute: () => {
|
|
1674
|
-
const
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
2260
|
+
const graphCapture = frameState.graphTargetCapture;
|
|
2261
|
+
const replayPassNames = graphCapture?.replayPassNames;
|
|
2262
|
+
const unsupportedCaptureKind =
|
|
2263
|
+
graphCapture !== undefined &&
|
|
2264
|
+
graphCapture.kind !== undefined &&
|
|
2265
|
+
graphCapture.kind !== 'target-copy' &&
|
|
2266
|
+
graphCapture.kind !== 'pass-replay';
|
|
2267
|
+
if (unsupportedCaptureKind || replayPassNames !== undefined) {
|
|
2268
|
+
if (graphCapture === undefined) {
|
|
2269
|
+
return { ok: false, stage: 'execute' };
|
|
2270
|
+
}
|
|
2271
|
+
const passNames = graph.inspect().passes.map((pass) => pass.name);
|
|
2272
|
+
const passNameCounts = new Map<string, number>();
|
|
2273
|
+
for (const passName of passNames) {
|
|
2274
|
+
passNameCounts.set(passName, (passNameCounts.get(passName) ?? 0) + 1);
|
|
2275
|
+
}
|
|
2276
|
+
const passNameSet = new Set(passNames);
|
|
2277
|
+
const selectedReplayPassNames = replayPassNames ?? [];
|
|
2278
|
+
const requestedPassNames = new Set(selectedReplayPassNames);
|
|
2279
|
+
const passReplayCapture = graphCapture.kind === 'pass-replay' ? graphCapture : undefined;
|
|
2280
|
+
const onPassEncoded = passReplayCapture?.onPassEncoded;
|
|
2281
|
+
const onPrefixEncoded = passReplayCapture?.onPrefixEncoded;
|
|
2282
|
+
const depthAttachmentPassName = passReplayCapture?.depthAttachmentPassName;
|
|
2283
|
+
const observeAfterPassName = passReplayCapture?.observeAfterPassName;
|
|
2284
|
+
let replayValidationFailed = false;
|
|
2285
|
+
const duplicatePassName = selectedReplayPassNames.find(
|
|
2286
|
+
(passName, index) => selectedReplayPassNames.indexOf(passName) !== index,
|
|
2287
|
+
);
|
|
2288
|
+
const invalidPassName = selectedReplayPassNames.find(
|
|
2289
|
+
(passName) => !passNameSet.has(passName),
|
|
2290
|
+
);
|
|
2291
|
+
const nonUniquePassName = selectedReplayPassNames.find(
|
|
2292
|
+
(passName) => passNameCounts.get(passName) !== 1,
|
|
2293
|
+
);
|
|
2294
|
+
const replayFailure = (reason: string): void => {
|
|
2295
|
+
replayValidationFailed = true;
|
|
2296
|
+
internals.errorRegistry.fire(
|
|
2297
|
+
new RhiError({
|
|
2298
|
+
code: 'webgpu-runtime-error',
|
|
2299
|
+
expected:
|
|
2300
|
+
'the requested graph target replay pass selection is valid and executes once',
|
|
2301
|
+
hint: 'inspect replayPassNames against the compiled graph pass roster',
|
|
2302
|
+
detail: {
|
|
2303
|
+
error: {
|
|
2304
|
+
code: 'graph-target-capture-failed',
|
|
2305
|
+
message: JSON.stringify({
|
|
2306
|
+
target: graphCapture.kind === 'pass-replay' ? undefined : graphCapture.name,
|
|
2307
|
+
replayPassNames,
|
|
2308
|
+
availablePassNames: passNames,
|
|
2309
|
+
reason,
|
|
2310
|
+
}),
|
|
2311
|
+
},
|
|
2312
|
+
},
|
|
2313
|
+
}),
|
|
2314
|
+
);
|
|
2315
|
+
};
|
|
2316
|
+
if (unsupportedCaptureKind) {
|
|
2317
|
+
replayFailure('capture-kind-unknown');
|
|
2318
|
+
return { ok: false, stage: 'execute' };
|
|
2319
|
+
}
|
|
2320
|
+
if (replayPassNames === undefined) {
|
|
2321
|
+
replayFailure('replay-pass-selection-missing');
|
|
2322
|
+
return { ok: false, stage: 'execute' };
|
|
2323
|
+
}
|
|
2324
|
+
if (replayPassNames.length === 0) {
|
|
2325
|
+
replayFailure('replay-pass-selection-empty');
|
|
2326
|
+
return { ok: false, stage: 'execute' };
|
|
2327
|
+
}
|
|
2328
|
+
if (duplicatePassName !== undefined) {
|
|
2329
|
+
replayFailure(`replay-pass-selection-duplicate:${duplicatePassName}`);
|
|
2330
|
+
return { ok: false, stage: 'execute' };
|
|
2331
|
+
}
|
|
2332
|
+
if (invalidPassName !== undefined) {
|
|
2333
|
+
replayFailure(`replay-pass-selection-unknown:${invalidPassName}`);
|
|
2334
|
+
return { ok: false, stage: 'execute' };
|
|
2335
|
+
}
|
|
2336
|
+
if (nonUniquePassName !== undefined) {
|
|
2337
|
+
replayFailure(`replay-pass-selection-non-unique:${nonUniquePassName}`);
|
|
2338
|
+
return { ok: false, stage: 'execute' };
|
|
2339
|
+
}
|
|
2340
|
+
|
|
2341
|
+
if (onPrefixEncoded !== undefined) {
|
|
2342
|
+
if (onPassEncoded !== undefined) {
|
|
2343
|
+
replayFailure('pass-replay-prefix-callback-conflict');
|
|
2344
|
+
return { ok: false, stage: 'execute' };
|
|
2345
|
+
}
|
|
2346
|
+
if (depthAttachmentPassName === undefined) {
|
|
2347
|
+
replayFailure('pass-replay-depth-attachment-name-missing');
|
|
2348
|
+
return { ok: false, stage: 'execute' };
|
|
2349
|
+
}
|
|
2350
|
+
if (observeAfterPassName === undefined) {
|
|
2351
|
+
replayFailure('pass-replay-observe-boundary-name-missing');
|
|
2352
|
+
return { ok: false, stage: 'execute' };
|
|
2353
|
+
}
|
|
2354
|
+
const firstNonPrefixPass = selectedReplayPassNames.find(
|
|
2355
|
+
(passName, index) => passName !== passNames[index],
|
|
2356
|
+
);
|
|
2357
|
+
if (
|
|
2358
|
+
firstNonPrefixPass !== undefined ||
|
|
2359
|
+
selectedReplayPassNames.length > passNames.length
|
|
2360
|
+
) {
|
|
2361
|
+
replayFailure('pass-replay-selection-not-prefix');
|
|
2362
|
+
return { ok: false, stage: 'execute' };
|
|
2363
|
+
}
|
|
2364
|
+
if (selectedReplayPassNames.at(-1) !== observeAfterPassName) {
|
|
2365
|
+
replayFailure('pass-replay-observe-boundary-not-last');
|
|
2366
|
+
return { ok: false, stage: 'execute' };
|
|
2367
|
+
}
|
|
2368
|
+
const anchorIndex = selectedReplayPassNames.indexOf(depthAttachmentPassName);
|
|
2369
|
+
if (anchorIndex < 0 || anchorIndex > selectedReplayPassNames.length - 1) {
|
|
2370
|
+
replayFailure('pass-replay-depth-attachment-not-in-prefix');
|
|
2371
|
+
return { ok: false, stage: 'execute' };
|
|
2372
|
+
}
|
|
2373
|
+
}
|
|
2374
|
+
|
|
2375
|
+
let replayTarget:
|
|
2376
|
+
| {
|
|
2377
|
+
readonly name: string;
|
|
2378
|
+
readonly view: TextureView;
|
|
2379
|
+
readonly texture: Texture;
|
|
2380
|
+
readonly textureIdentity: number;
|
|
2381
|
+
readonly graphGeneration: number;
|
|
2382
|
+
}
|
|
2383
|
+
| undefined;
|
|
2384
|
+
if (onPassEncoded !== undefined || onPrefixEncoded !== undefined) {
|
|
2385
|
+
const targetName = passReplayCapture?.targetName;
|
|
2386
|
+
const graphAccess = frameState.perFrameGraph;
|
|
2387
|
+
const targetView =
|
|
2388
|
+
targetName === undefined ? undefined : graphAccess?.getColorTargetView(targetName);
|
|
2389
|
+
const targetTexture =
|
|
2390
|
+
targetName === undefined ? undefined : graphAccess?.getColorTargetTexture(targetName);
|
|
2391
|
+
const targetDescriptor =
|
|
2392
|
+
targetName === undefined
|
|
2393
|
+
? undefined
|
|
2394
|
+
: graphAccess?.getColorTargetDescriptor(targetName);
|
|
2395
|
+
if (targetName === undefined) {
|
|
2396
|
+
replayFailure('pass-replay-target-name-missing');
|
|
2397
|
+
return { ok: false, stage: 'execute' };
|
|
2398
|
+
}
|
|
2399
|
+
if (graphAccess === undefined || graphAccess === null) {
|
|
2400
|
+
replayFailure(`pass-replay-target-missing:${targetName}`);
|
|
2401
|
+
return { ok: false, stage: 'execute' };
|
|
2402
|
+
}
|
|
2403
|
+
if (targetView === undefined || targetTexture === undefined) {
|
|
2404
|
+
replayFailure(`pass-replay-target-missing:${targetName}`);
|
|
2405
|
+
return { ok: false, stage: 'execute' };
|
|
2406
|
+
}
|
|
2407
|
+
if (targetDescriptor !== undefined && targetDescriptor.texture !== targetTexture) {
|
|
2408
|
+
replayFailure(`pass-replay-target-identity-mismatch:${targetName}`);
|
|
2409
|
+
return { ok: false, stage: 'execute' };
|
|
2410
|
+
}
|
|
2411
|
+
replayTarget = {
|
|
2412
|
+
name: targetName,
|
|
2413
|
+
view: targetView,
|
|
2414
|
+
texture: targetTexture,
|
|
2415
|
+
textureIdentity: getTextureIdentity(targetTexture),
|
|
2416
|
+
graphGeneration: graphAccess.graphGeneration,
|
|
2417
|
+
};
|
|
2418
|
+
}
|
|
2419
|
+
|
|
2420
|
+
const executed = graph.execute(frame, runPass, graphInstrumentation);
|
|
2421
|
+
if (!executed.ok) {
|
|
2422
|
+
passTimingCapture?.abort({ code: executed.error.code });
|
|
2423
|
+
internals.errorRegistry.fire(executed.error);
|
|
2424
|
+
return { ok: false, stage: 'execute' };
|
|
2425
|
+
}
|
|
2426
|
+
const replayedPassNames = new Set<string>();
|
|
2427
|
+
let prefixCallbackCount = 0;
|
|
2428
|
+
let depthAnchorReceipt:
|
|
2429
|
+
| {
|
|
2430
|
+
readonly pass: { name: string; executionIndex: number };
|
|
2431
|
+
readonly view: TextureView;
|
|
2432
|
+
}
|
|
2433
|
+
| undefined;
|
|
2434
|
+
const replayRunPass: import('@forgeax/engine-render-graph').RenderGraphPassRunner = (
|
|
2435
|
+
pass,
|
|
2436
|
+
encode,
|
|
2437
|
+
) => {
|
|
2438
|
+
if (!requestedPassNames.has(pass.name)) return;
|
|
2439
|
+
if (replayedPassNames.has(pass.name)) {
|
|
2440
|
+
replayFailure(`replay-pass-selection-multiple-hit:${pass.name}`);
|
|
2441
|
+
return;
|
|
2442
|
+
}
|
|
2443
|
+
replayedPassNames.add(pass.name);
|
|
2444
|
+
const depthView = (pass as ResolvedDepthPassExecution).resolvedDepthStencilAttachmentView;
|
|
2445
|
+
if (onPrefixEncoded !== undefined) {
|
|
2446
|
+
if (pass.name === depthAttachmentPassName) {
|
|
2447
|
+
if (depthView === undefined) {
|
|
2448
|
+
replayFailure(`pass-replay-depth-attachment-missing:${pass.name}`);
|
|
2449
|
+
return;
|
|
2450
|
+
}
|
|
2451
|
+
const target = replayTarget;
|
|
2452
|
+
if (target === undefined || depthView !== target.view) {
|
|
2453
|
+
replayFailure(`pass-replay-attachment-target-mismatch:${pass.name}`);
|
|
2454
|
+
return;
|
|
2455
|
+
}
|
|
2456
|
+
if (depthAnchorReceipt !== undefined) {
|
|
2457
|
+
replayFailure(`pass-replay-depth-attachment-multiple-hit:${pass.name}`);
|
|
2458
|
+
return;
|
|
2459
|
+
}
|
|
2460
|
+
depthAnchorReceipt = {
|
|
2461
|
+
pass: { name: pass.name, executionIndex: pass.executionIndex },
|
|
2462
|
+
view: depthView,
|
|
2463
|
+
};
|
|
2464
|
+
}
|
|
2465
|
+
let encoded = false;
|
|
2466
|
+
const encodePrefix = () => {
|
|
2467
|
+
if (encoded) {
|
|
2468
|
+
replayFailure(`pass-replay-encode-multiple-hit:${pass.name}`);
|
|
2469
|
+
return;
|
|
2470
|
+
}
|
|
2471
|
+
encode();
|
|
2472
|
+
encoded = true;
|
|
2473
|
+
if (replayValidationFailed || pass.name !== observeAfterPassName) return;
|
|
2474
|
+
const target = replayTarget;
|
|
2475
|
+
const anchor = depthAnchorReceipt;
|
|
2476
|
+
if (target === undefined || anchor === undefined) {
|
|
2477
|
+
replayFailure('pass-replay-depth-attachment-anchor-missing-at-boundary');
|
|
2478
|
+
return;
|
|
2479
|
+
}
|
|
2480
|
+
const receipt: GraphTargetPassReplayPrefixReceipt = {
|
|
2481
|
+
passName: pass.name,
|
|
2482
|
+
executionIndex: pass.executionIndex,
|
|
2483
|
+
resolvedDepthStencilAttachmentView: anchor.view,
|
|
2484
|
+
graphGeneration: target.graphGeneration,
|
|
2485
|
+
targetName: target.name,
|
|
2486
|
+
targetView: target.view,
|
|
2487
|
+
targetTexture: target.texture,
|
|
2488
|
+
targetTextureIdentity: target.textureIdentity,
|
|
2489
|
+
replayPassNames: [...selectedReplayPassNames],
|
|
2490
|
+
depthAttachmentPassName: anchor.pass.name,
|
|
2491
|
+
observeAfterPassName: pass.name,
|
|
2492
|
+
depthAttachmentExecutionIndex: anchor.pass.executionIndex,
|
|
2493
|
+
};
|
|
2494
|
+
try {
|
|
2495
|
+
onPrefixEncoded(receipt);
|
|
2496
|
+
prefixCallbackCount += 1;
|
|
2497
|
+
} catch (cause) {
|
|
2498
|
+
replayFailure(
|
|
2499
|
+
`pass-replay-prefix-callback-threw:${pass.name}:${cause instanceof Error ? cause.message : String(cause)}`,
|
|
2500
|
+
);
|
|
2501
|
+
}
|
|
2502
|
+
};
|
|
2503
|
+
if (runPass === undefined) encodePrefix();
|
|
2504
|
+
else runPass(pass, encodePrefix);
|
|
2505
|
+
if (!encoded && !replayValidationFailed) {
|
|
2506
|
+
replayFailure(`pass-replay-encode-not-called:${pass.name}`);
|
|
2507
|
+
}
|
|
2508
|
+
return;
|
|
2509
|
+
}
|
|
2510
|
+
if (onPassEncoded === undefined) {
|
|
2511
|
+
if (runPass === undefined) encode();
|
|
2512
|
+
else runPass(pass, encode);
|
|
2513
|
+
return;
|
|
2514
|
+
}
|
|
2515
|
+
const target = replayTarget;
|
|
2516
|
+
if (target === undefined || depthView === undefined) {
|
|
2517
|
+
replayFailure(`pass-replay-depth-attachment-missing:${pass.name}`);
|
|
2518
|
+
return;
|
|
2519
|
+
}
|
|
2520
|
+
if (depthView !== target.view) {
|
|
2521
|
+
replayFailure(`pass-replay-attachment-target-mismatch:${pass.name}`);
|
|
2522
|
+
return;
|
|
2523
|
+
}
|
|
2524
|
+
let encoded = false;
|
|
2525
|
+
const encodeAndObserve = () => {
|
|
2526
|
+
if (encoded) {
|
|
2527
|
+
replayFailure(`pass-replay-encode-multiple-hit:${pass.name}`);
|
|
2528
|
+
return;
|
|
2529
|
+
}
|
|
2530
|
+
encode();
|
|
2531
|
+
encoded = true;
|
|
2532
|
+
if (replayValidationFailed) return;
|
|
2533
|
+
const receipt: GraphTargetPassReplayReceipt = {
|
|
2534
|
+
passName: pass.name,
|
|
2535
|
+
executionIndex: pass.executionIndex,
|
|
2536
|
+
resolvedDepthStencilAttachmentView: depthView,
|
|
2537
|
+
graphGeneration: target.graphGeneration,
|
|
2538
|
+
targetName: target.name,
|
|
2539
|
+
targetView: target.view,
|
|
2540
|
+
targetTexture: target.texture,
|
|
2541
|
+
targetTextureIdentity: target.textureIdentity,
|
|
2542
|
+
};
|
|
2543
|
+
try {
|
|
2544
|
+
onPassEncoded(receipt);
|
|
2545
|
+
} catch (cause) {
|
|
2546
|
+
replayFailure(
|
|
2547
|
+
`pass-replay-callback-threw:${pass.name}:${cause instanceof Error ? cause.message : String(cause)}`,
|
|
2548
|
+
);
|
|
2549
|
+
}
|
|
2550
|
+
};
|
|
2551
|
+
if (runPass === undefined) encodeAndObserve();
|
|
2552
|
+
else runPass(pass, encodeAndObserve);
|
|
2553
|
+
if (!encoded && !replayValidationFailed) {
|
|
2554
|
+
replayFailure(`pass-replay-encode-not-called:${pass.name}`);
|
|
2555
|
+
}
|
|
2556
|
+
};
|
|
2557
|
+
const replayed = graph.execute(frame, replayRunPass);
|
|
2558
|
+
if (!replayed.ok) {
|
|
2559
|
+
internals.errorRegistry.fire(replayed.error);
|
|
2560
|
+
return { ok: false, stage: 'execute' };
|
|
2561
|
+
}
|
|
2562
|
+
if (replayValidationFailed) return { ok: false, stage: 'execute' };
|
|
2563
|
+
if (replayedPassNames.size !== requestedPassNames.size) {
|
|
2564
|
+
replayFailure('replay-pass-selection-zero-hit');
|
|
2565
|
+
return { ok: false, stage: 'execute' };
|
|
2566
|
+
}
|
|
2567
|
+
if (onPrefixEncoded !== undefined && prefixCallbackCount !== 1) {
|
|
2568
|
+
replayFailure('pass-replay-prefix-callback-count-invalid');
|
|
2569
|
+
return { ok: false, stage: 'execute' };
|
|
2570
|
+
}
|
|
2571
|
+
} else {
|
|
2572
|
+
const executed = graph.execute(frame, runPass, graphInstrumentation);
|
|
2573
|
+
if (!executed.ok) {
|
|
2574
|
+
passTimingCapture?.abort({ code: executed.error.code });
|
|
2575
|
+
internals.errorRegistry.fire(executed.error);
|
|
2576
|
+
return { ok: false, stage: 'execute' };
|
|
2577
|
+
}
|
|
1680
2578
|
}
|
|
1681
|
-
|
|
2579
|
+
timingInstrumentationState?.setCapture(undefined);
|
|
2580
|
+
const afterGraphExecute = resolvedFrameHooks?.afterGraphExecute;
|
|
1682
2581
|
if (afterGraphExecute !== undefined) {
|
|
1683
2582
|
const recorded = afterGraphExecute();
|
|
1684
2583
|
if (!recorded.ok) {
|
|
@@ -1691,7 +2590,7 @@ export function executeCompiledFrameGraph(
|
|
|
1691
2590
|
finish: () => {
|
|
1692
2591
|
const graphCapture = frameState.graphTargetCapture;
|
|
1693
2592
|
frameState.graphTargetCapture = undefined;
|
|
1694
|
-
if (graphCapture !== undefined) {
|
|
2593
|
+
if (graphCapture !== undefined && graphCapture.kind !== 'pass-replay') {
|
|
1695
2594
|
const graphAccess = frameState.perFrameGraph;
|
|
1696
2595
|
const graphTexture = graphAccess?.getColorTargetTexture(graphCapture.name);
|
|
1697
2596
|
const descriptor = graphAccess?.getColorTargetDescriptor(graphCapture.name);
|
|
@@ -1910,7 +2809,8 @@ export function executeCompiledFrameGraph(
|
|
|
1910
2809
|
},
|
|
1911
2810
|
}),
|
|
1912
2811
|
commit: () => {
|
|
1913
|
-
|
|
2812
|
+
resolvedFrameHooks?.onSubmitted?.();
|
|
2813
|
+
legacySubmitCommit?.();
|
|
1914
2814
|
if (frameState.temporalFrameInput !== undefined) {
|
|
1915
2815
|
const temporal = frameState.temporalFrameTransaction.commit({ accepted: true });
|
|
1916
2816
|
if (temporal.ok) {
|
|
@@ -1938,6 +2838,46 @@ export function executeCompiledFrameGraph(
|
|
|
1938
2838
|
?.perPassResources.commitBloomFrameReceipts?.(frameState.bloomFrameReceipts);
|
|
1939
2839
|
frameState.bloomFrameReceipts = undefined;
|
|
1940
2840
|
}
|
|
2841
|
+
const pendingAuto = frameState.pendingAutoExposureGpuResources;
|
|
2842
|
+
if (pendingAuto !== undefined) {
|
|
2843
|
+
const previousAuto = frameState.autoExposureGpuResources;
|
|
2844
|
+
frameState.autoExposureGpuResources = pendingAuto;
|
|
2845
|
+
frameState.pendingAutoExposureGpuResources = undefined;
|
|
2846
|
+
if (previousAuto !== undefined && previousAuto !== pendingAuto) {
|
|
2847
|
+
internals.device.queue
|
|
2848
|
+
.onSubmittedWorkDone()
|
|
2849
|
+
.then(() => retireAutoExposureGpuResources(previousAuto))
|
|
2850
|
+
.catch(() => undefined);
|
|
2851
|
+
}
|
|
2852
|
+
}
|
|
2853
|
+
const pendingAutoState = frameState.pendingAutoExposureState;
|
|
2854
|
+
if (pendingAutoState !== undefined) {
|
|
2855
|
+
frameState.autoExposureState = commitAutoExposureSubmission(
|
|
2856
|
+
pendingAutoState.state,
|
|
2857
|
+
pendingAutoState,
|
|
2858
|
+
);
|
|
2859
|
+
frameState.pendingAutoExposureState = undefined;
|
|
2860
|
+
}
|
|
2861
|
+
const pendingLut = frameState.pendingStandardLutGpuResources;
|
|
2862
|
+
if (pendingLut !== undefined) {
|
|
2863
|
+
const previousLut = frameState.standardLutGpuResources;
|
|
2864
|
+
frameState.standardLutGpuResources = pendingLut;
|
|
2865
|
+
frameState.pendingStandardLutGpuResources = undefined;
|
|
2866
|
+
if (previousLut !== undefined && previousLut !== pendingLut) {
|
|
2867
|
+
retireStandardLutGpuResources(previousLut);
|
|
2868
|
+
}
|
|
2869
|
+
}
|
|
2870
|
+
const pendingLutState = frameState.pendingStandardLutState;
|
|
2871
|
+
if (pendingLutState !== undefined) {
|
|
2872
|
+
frameState.standardLutState =
|
|
2873
|
+
pendingLutState.remove || pendingLutState.candidate === undefined
|
|
2874
|
+
? resetStandardLutState(pendingLutState.state, 'resource-removed', {
|
|
2875
|
+
targetGeneration: pendingLutState.targetGeneration,
|
|
2876
|
+
deviceEpoch: pendingLutState.deviceEpoch,
|
|
2877
|
+
})
|
|
2878
|
+
: commitStandardLutCandidate(pendingLutState.state, pendingLutState.candidate);
|
|
2879
|
+
frameState.pendingStandardLutState = undefined;
|
|
2880
|
+
}
|
|
1941
2881
|
const stagedGpuState = frameState.temporalGpuState;
|
|
1942
2882
|
if (stagedGpuState !== undefined) {
|
|
1943
2883
|
if (commitTemporalGpuSubmit(stagedGpuState)) {
|
|
@@ -1945,7 +2885,6 @@ export function executeCompiledFrameGraph(
|
|
|
1945
2885
|
frameState.activeTemporalGpuState = stagedGpuState;
|
|
1946
2886
|
if (previousGpuState !== undefined && previousGpuState !== stagedGpuState) {
|
|
1947
2887
|
internals.clearPostProcessPipelineCache?.('forgeax.taa-resolve');
|
|
1948
|
-
invalidatePostProcessModule('forgeax.taa-resolve');
|
|
1949
2888
|
retireTemporalGpuStateAfterFence(
|
|
1950
2889
|
previousGpuState,
|
|
1951
2890
|
internals.device.queue,
|
|
@@ -1975,7 +2914,8 @@ export function executeCompiledFrameGraph(
|
|
|
1975
2914
|
}
|
|
1976
2915
|
if (stagedTemporalCommit.kind === 'off') {
|
|
1977
2916
|
internals.clearPostProcessPipelineCache?.('forgeax.taa-resolve');
|
|
1978
|
-
|
|
2917
|
+
// Retire frame-sized resources, not the device-owned prewarmed
|
|
2918
|
+
// shader. The next TAA frame must not start an async cold compile.
|
|
1979
2919
|
const activeGpuState = frameState.activeTemporalGpuState;
|
|
1980
2920
|
if (activeGpuState !== undefined) {
|
|
1981
2921
|
retireTemporalGpuStateAfterFence(
|
|
@@ -2000,15 +2940,28 @@ export function executeCompiledFrameGraph(
|
|
|
2000
2940
|
frameState.environmentLifecycle?.publish(frameState.environmentGeneration);
|
|
2001
2941
|
frameState.environmentGeneration = undefined;
|
|
2002
2942
|
}
|
|
2943
|
+
frameState.pendingAtmospherePublish?.();
|
|
2944
|
+
frameState.pendingAtmospherePublish = undefined;
|
|
2003
2945
|
onSubmitted?.(internals.device.queue.onSubmittedWorkDone());
|
|
2004
2946
|
},
|
|
2005
2947
|
abort: (failure) => {
|
|
2006
|
-
|
|
2948
|
+
frameState.pendingAtmospherePublish = undefined;
|
|
2949
|
+
resolvedFrameHooks?.onAborted?.();
|
|
2007
2950
|
passTimingCapture?.abort({ code: failure.stage });
|
|
2008
2951
|
timingHost.gpuPassTimingCapture = undefined;
|
|
2009
2952
|
timingHost.gpuPassTimingSubmittedWork = undefined;
|
|
2010
2953
|
timingCapture?.discard();
|
|
2011
2954
|
frameState.bloomFrameReceipts = undefined;
|
|
2955
|
+
frameState.pendingAutoExposureState = undefined;
|
|
2956
|
+
frameState.pendingStandardLutState = undefined;
|
|
2957
|
+
if (frameState.pendingAutoExposureGpuResources !== undefined) {
|
|
2958
|
+
retireAutoExposureGpuResources(frameState.pendingAutoExposureGpuResources);
|
|
2959
|
+
frameState.pendingAutoExposureGpuResources = undefined;
|
|
2960
|
+
}
|
|
2961
|
+
if (frameState.pendingStandardLutGpuResources !== undefined) {
|
|
2962
|
+
retireStandardLutGpuResources(frameState.pendingStandardLutGpuResources);
|
|
2963
|
+
frameState.pendingStandardLutGpuResources = undefined;
|
|
2964
|
+
}
|
|
2012
2965
|
if (frameState.environmentGeneration !== undefined) {
|
|
2013
2966
|
frameState.environmentLifecycle?.recordStageFailure(
|
|
2014
2967
|
failure.stage,
|