@forgeax/engine-render 0.1.32 → 0.1.34
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 +1374 -142
- package/dist/assembly/analytic-fog-registration.d.ts +3 -0
- package/dist/assembly/analytic-fog-registration.d.ts.map +1 -0
- package/dist/assembly/backend-contract.d.ts +2 -0
- package/dist/assembly/backend-contract.d.ts.map +1 -1
- package/dist/assembly/barrel-distortion-inspection.d.ts +3 -0
- package/dist/assembly/barrel-distortion-inspection.d.ts.map +1 -0
- package/dist/assembly/canvas-draw-guard.d.ts +3 -0
- package/dist/assembly/canvas-draw-guard.d.ts.map +1 -0
- package/dist/assembly/cloud-shadow-entry.d.ts +4 -0
- package/dist/assembly/cloud-shadow-entry.d.ts.map +1 -0
- package/dist/assembly/dynamic-geometry-host.d.ts +4 -1
- package/dist/assembly/dynamic-geometry-host.d.ts.map +1 -1
- package/dist/assembly/dynamic-geometry-runtime.d.ts +1 -1
- package/dist/assembly/dynamic-geometry-runtime.d.ts.map +1 -1
- package/dist/assembly/factory.d.ts +1 -1
- package/dist/assembly/factory.d.ts.map +1 -1
- package/dist/assembly/fxaa-registration.d.ts +4 -0
- package/dist/assembly/fxaa-registration.d.ts.map +1 -0
- package/dist/assembly/host-contract.d.ts +3 -3
- package/dist/assembly/host-contract.d.ts.map +1 -1
- package/dist/assembly/lod-observation.d.ts +4 -0
- package/dist/assembly/lod-observation.d.ts.map +1 -0
- package/dist/assembly/material/assembly.d.ts.map +1 -1
- package/dist/assembly/material/pipeline-helpers.d.ts +5 -0
- package/dist/assembly/material/pipeline-helpers.d.ts.map +1 -1
- package/dist/assembly/material-shader-policy.d.ts +16 -2
- package/dist/assembly/material-shader-policy.d.ts.map +1 -1
- package/dist/assembly/material-shader-prewarm.d.ts.map +1 -1
- package/dist/assembly/motion-blur-registration.d.ts +3 -0
- package/dist/assembly/motion-blur-registration.d.ts.map +1 -0
- package/dist/assembly/recovery/device-loss-fanout.d.ts.map +1 -1
- package/dist/assembly/recovery/renderer-recover.d.ts +2 -0
- package/dist/assembly/recovery/renderer-recover.d.ts.map +1 -1
- package/dist/assembly/render-feature-post-processes.d.ts +6 -0
- package/dist/assembly/render-feature-post-processes.d.ts.map +1 -0
- package/dist/assembly/renderer-facade.d.ts.map +1 -1
- package/dist/assembly/renderer-feature-inspection.d.ts +1 -1
- package/dist/assembly/renderer-feature-inspection.d.ts.map +1 -1
- package/dist/assembly/renderer-frame-transaction.d.ts +12 -0
- package/dist/assembly/renderer-frame-transaction.d.ts.map +1 -1
- package/dist/assembly/renderer-inspection.d.ts +11 -0
- package/dist/assembly/renderer-inspection.d.ts.map +1 -1
- package/dist/assembly/temporal-post-process-prewarm.d.ts +13 -0
- package/dist/assembly/temporal-post-process-prewarm.d.ts.map +1 -0
- package/dist/assembly/webgpu-pbr-ready.d.ts +1 -0
- package/dist/assembly/webgpu-pbr-ready.d.ts.map +1 -1
- package/dist/assembly/webgpu-ready-contract.d.ts +4 -3
- package/dist/assembly/webgpu-ready-contract.d.ts.map +1 -1
- package/dist/assembly/webgpu-ready-per-pass.d.ts +39 -0
- package/dist/assembly/webgpu-ready-per-pass.d.ts.map +1 -0
- package/dist/assembly/webgpu-ready.d.ts +2 -2
- package/dist/assembly/webgpu-ready.d.ts.map +1 -1
- package/dist/assembly/webgpu-renderer-bootstrap.d.ts.map +1 -1
- package/dist/assembly/webgpu-renderer-observation-owner.d.ts +35 -0
- package/dist/assembly/webgpu-renderer-observation-owner.d.ts.map +1 -0
- package/dist/assembly/webgpu-renderer.d.ts +1 -1
- package/dist/assembly/webgpu-renderer.d.ts.map +1 -1
- package/dist/authoring.mjs +1 -1
- package/dist/barrel-distortion.d.ts +47 -0
- package/dist/barrel-distortion.d.ts.map +1 -0
- package/dist/bloom-admission.d.ts +13 -0
- package/dist/bloom-admission.d.ts.map +1 -0
- package/dist/{chunk-PA5DRJNI.mjs → chunk-ELJFJ2BU.mjs} +2 -2
- package/dist/chunk-ELJFJ2BU.mjs.map +1 -0
- package/dist/{chunk-JCIRYQ4V.mjs → chunk-HEB564WF.mjs} +10 -4
- package/dist/chunk-HEB564WF.mjs.map +1 -0
- package/dist/{chunk-JRIPCMYC.mjs → chunk-MKDIT2EM.mjs} +1584 -375
- package/dist/chunk-MKDIT2EM.mjs.map +1 -0
- package/dist/{chunk-S665NJNF.mjs → chunk-OCDLEI6I.mjs} +3 -3
- package/dist/{chunk-S665NJNF.mjs.map → chunk-OCDLEI6I.mjs.map} +1 -1
- package/dist/chunk-ODZWR6JQ.mjs +4927 -0
- package/dist/chunk-ODZWR6JQ.mjs.map +1 -0
- package/dist/{chunk-DRR7D3KX.mjs → chunk-SHFUFJ5N.mjs} +192 -18
- package/dist/chunk-SHFUFJ5N.mjs.map +1 -0
- package/dist/{chunk-4NNZQCL3.mjs → chunk-UI5SFODX.mjs} +223 -277
- package/dist/chunk-UI5SFODX.mjs.map +1 -0
- package/dist/{chunk-GWCEMDVR.mjs → chunk-UINHLCZA.mjs} +787 -80
- package/dist/chunk-UINHLCZA.mjs.map +1 -0
- package/dist/{chunk-6TFBXLRJ.mjs → chunk-WEX45HKH.mjs} +222 -337
- package/dist/chunk-WEX45HKH.mjs.map +1 -0
- package/dist/cloud/density.d.ts +55 -0
- package/dist/cloud/density.d.ts.map +1 -0
- package/dist/cloud/extract.d.ts +25 -0
- package/dist/cloud/extract.d.ts.map +1 -0
- package/dist/cloud/feature.d.ts +57 -0
- package/dist/cloud/feature.d.ts.map +1 -0
- package/dist/cloud/frame-context.d.ts +8 -0
- package/dist/cloud/frame-context.d.ts.map +1 -0
- package/dist/cloud/inspection.d.ts +59 -0
- package/dist/cloud/inspection.d.ts.map +1 -0
- package/dist/cloud/optics.d.ts +56 -0
- package/dist/cloud/optics.d.ts.map +1 -0
- package/dist/cloud/parameters.d.ts +73 -0
- package/dist/cloud/parameters.d.ts.map +1 -0
- package/dist/cloud/resources.d.ts +60 -0
- package/dist/cloud/resources.d.ts.map +1 -0
- package/dist/cloud/shadow.d.ts +42 -0
- package/dist/cloud/shadow.d.ts.map +1 -0
- package/dist/cloud/temporal.d.ts +74 -0
- package/dist/cloud/temporal.d.ts.map +1 -0
- package/dist/components/atmosphere.d.ts +2 -0
- package/dist/components/atmosphere.d.ts.map +1 -1
- package/dist/components/barrel-distortion.d.ts +13 -0
- package/dist/components/barrel-distortion.d.ts.map +1 -0
- package/dist/components/camera.d.ts +20 -4
- package/dist/components/camera.d.ts.map +1 -1
- package/dist/components/cloud-layer.d.ts +29 -0
- package/dist/components/cloud-layer.d.ts.map +1 -0
- package/dist/components/index.d.ts +2 -0
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/instances.d.ts +20 -6
- package/dist/components/instances.d.ts.map +1 -1
- package/dist/components/mesh-filter.d.ts +6 -5
- package/dist/components/mesh-filter.d.ts.map +1 -1
- package/dist/components/motion-blur.d.ts +1 -0
- package/dist/components/motion-blur.d.ts.map +1 -1
- package/dist/construct-renderer.d.ts +1 -1
- package/dist/construct-renderer.d.ts.map +1 -1
- package/dist/construct-renderer.mjs +9751 -3528
- package/dist/construct-renderer.mjs.map +1 -1
- package/dist/device/gpu-residency.d.ts +6 -0
- package/dist/device/gpu-residency.d.ts.map +1 -1
- package/dist/dynamic-geometry.d.ts +5 -1
- package/dist/dynamic-geometry.d.ts.map +1 -1
- package/dist/environment/analytic-fog.d.ts +6 -0
- package/dist/environment/analytic-fog.d.ts.map +1 -0
- package/dist/errors/cloud.d.ts +59 -0
- package/dist/errors/cloud.d.ts.map +1 -0
- package/dist/errors/render.d.ts +23 -5
- package/dist/errors/render.d.ts.map +1 -1
- package/dist/examples/single-layer-medium-surface.d.ts +47 -0
- package/dist/examples/single-layer-medium-surface.d.ts.map +1 -0
- package/dist/extract/camera.d.ts.map +1 -1
- package/dist/extract/contracts.d.ts +12 -1
- package/dist/extract/contracts.d.ts.map +1 -1
- package/dist/extract/environment.d.ts +2 -0
- package/dist/extract/environment.d.ts.map +1 -1
- package/dist/features/barrel-distortion.d.ts +29 -0
- package/dist/features/barrel-distortion.d.ts.map +1 -0
- package/dist/features/error-reporting.d.ts +17 -0
- package/dist/features/error-reporting.d.ts.map +1 -0
- package/dist/features/host.d.ts +15 -0
- package/dist/features/host.d.ts.map +1 -1
- package/dist/features/motion-blur/motion-blur-feature.d.ts +20 -2
- package/dist/features/motion-blur/motion-blur-feature.d.ts.map +1 -1
- package/dist/features/motion-blur/motion-blur-params.d.ts +21 -0
- package/dist/features/motion-blur/motion-blur-params.d.ts.map +1 -1
- package/dist/features/motion-blur/motion-blur-runtime.d.ts +54 -0
- package/dist/features/motion-blur/motion-blur-runtime.d.ts.map +1 -0
- package/dist/features/plan.d.ts +15 -4
- package/dist/features/plan.d.ts.map +1 -1
- package/dist/features/prepared-gpu-work.d.ts +9 -5
- package/dist/features/prepared-gpu-work.d.ts.map +1 -1
- package/dist/features/render-graph-compute.d.ts.map +1 -1
- package/dist/features/render-graph-contribution.d.ts +5 -0
- package/dist/features/render-graph-contribution.d.ts.map +1 -1
- package/dist/features/render-graph-raster.d.ts +1 -0
- package/dist/features/render-graph-raster.d.ts.map +1 -1
- package/dist/features/targets.d.ts +2 -0
- package/dist/features/targets.d.ts.map +1 -1
- package/dist/features/types.d.ts +44 -0
- package/dist/features/types.d.ts.map +1 -1
- package/dist/fullscreen-post-process-pass.d.ts +15 -7
- package/dist/fullscreen-post-process-pass.d.ts.map +1 -1
- package/dist/gpu-dirty-ranges.d.ts +11 -0
- package/dist/gpu-dirty-ranges.d.ts.map +1 -0
- package/dist/gpu-driven/batch-topology.d.ts +17 -0
- package/dist/gpu-driven/batch-topology.d.ts.map +1 -1
- package/dist/gpu-driven/material-artifacts.d.ts +6 -0
- package/dist/gpu-driven/material-artifacts.d.ts.map +1 -1
- package/dist/gpu-driven/prepared-draw.d.ts +7 -0
- package/dist/gpu-driven/prepared-draw.d.ts.map +1 -1
- package/dist/gpu-driven/production-raster-material.d.ts +178 -0
- package/dist/gpu-driven/production-raster-material.d.ts.map +1 -0
- package/dist/gpu-driven/production-raster.d.ts +50 -4
- package/dist/gpu-driven/production-raster.d.ts.map +1 -1
- package/dist/gpu-driven/resource-allocation.d.ts +31 -0
- package/dist/gpu-driven/resource-allocation.d.ts.map +1 -0
- package/dist/gpu-driven/shadow-ownership.d.ts +14 -0
- package/dist/gpu-driven/shadow-ownership.d.ts.map +1 -0
- package/dist/gpu-driven/view-gpu.d.ts +35 -2
- package/dist/gpu-driven/view-gpu.d.ts.map +1 -1
- package/dist/gpu-scene.d.ts +11 -1
- package/dist/gpu-scene.d.ts.map +1 -1
- package/dist/hdrp-buffers.d.ts +2 -2
- package/dist/hdrp-buffers.d.ts.map +1 -1
- package/dist/ibl/skylight-bind-group.d.ts +10 -1
- package/dist/ibl/skylight-bind-group.d.ts.map +1 -1
- package/dist/index.d.ts +31 -8
- package/dist/index.d.ts.map +1 -1
- package/dist/index.mjs +258 -8
- package/dist/index.mjs.map +1 -1
- package/dist/inspection-types.d.ts +178 -3
- package/dist/inspection-types.d.ts.map +1 -1
- package/dist/instance-buffer-cache.d.ts +4 -4
- package/dist/instance-buffer-cache.d.ts.map +1 -1
- package/dist/instances.d.ts +49 -94
- package/dist/instances.d.ts.map +1 -1
- package/dist/internal.mjs +7 -7
- package/dist/pbr-pipeline.d.ts +19 -1
- package/dist/pbr-pipeline.d.ts.map +1 -1
- package/dist/pipeline/single-layer-medium-passes.d.ts +73 -0
- package/dist/pipeline/single-layer-medium-passes.d.ts.map +1 -0
- package/dist/pipeline/standard-forward-lane.d.ts.map +1 -1
- package/dist/pipeline/standard-output/graph.d.ts.map +1 -1
- package/dist/pipeline/standard-output/types.d.ts +4 -2
- package/dist/pipeline/standard-output/types.d.ts.map +1 -1
- package/dist/pipeline/standard-pipeline.d.ts.map +1 -1
- package/dist/pipeline/standard-post.d.ts +28 -19
- package/dist/pipeline/standard-post.d.ts.map +1 -1
- package/dist/pipeline-builder.d.ts +1 -1
- package/dist/pipeline-builder.d.ts.map +1 -1
- package/dist/pipeline-spec.d.ts +2 -2
- package/dist/plugin.d.ts.map +1 -1
- package/dist/prepare/prepared-graphics-resolver.d.ts +2 -0
- package/dist/prepare/prepared-graphics-resolver.d.ts.map +1 -1
- package/dist/record/barrel-distortion-frame.d.ts +15 -0
- package/dist/record/barrel-distortion-frame.d.ts.map +1 -0
- package/dist/record/dynamic-geometry-consumption.d.ts +10 -2
- package/dist/record/dynamic-geometry-consumption.d.ts.map +1 -1
- package/dist/record/fold-buckets.d.ts +95 -0
- package/dist/record/fold-buckets.d.ts.map +1 -0
- package/dist/record/fold-instance-buffer.d.ts +6 -0
- package/dist/record/fold-instance-buffer.d.ts.map +1 -0
- package/dist/record/frame-lighting.d.ts +1 -0
- package/dist/record/frame-lighting.d.ts.map +1 -1
- package/dist/record/frame-snapshot.d.ts +40 -3
- 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 +14 -62
- package/dist/record/frame.d.ts.map +1 -1
- package/dist/record/gpu-draw-receipts.d.ts +11 -0
- package/dist/record/gpu-draw-receipts.d.ts.map +1 -0
- package/dist/record/gpu-timing.d.ts +8 -0
- package/dist/record/gpu-timing.d.ts.map +1 -1
- package/dist/record/main-pass-geometry.d.ts +21 -5
- package/dist/record/main-pass-geometry.d.ts.map +1 -1
- package/dist/record/main-pass-material.d.ts +7 -1
- package/dist/record/main-pass-material.d.ts.map +1 -1
- package/dist/record/main-pass-sprite-draws.d.ts.map +1 -1
- package/dist/record/main-pass.d.ts +13 -2
- package/dist/record/main-pass.d.ts.map +1 -1
- package/dist/record/mesh-ssbo.d.ts +6 -5
- package/dist/record/mesh-ssbo.d.ts.map +1 -1
- package/dist/record/motion-blur-receipt.d.ts +11 -0
- package/dist/record/motion-blur-receipt.d.ts.map +1 -0
- package/dist/record/probe-blend-buffer.d.ts +16 -0
- package/dist/record/probe-blend-buffer.d.ts.map +1 -0
- package/dist/record/recovery-pipeline.d.ts.map +1 -1
- package/dist/record/render-context.d.ts +34 -31
- package/dist/record/render-context.d.ts.map +1 -1
- package/dist/record/shadow-pass.d.ts +2 -0
- package/dist/record/shadow-pass.d.ts.map +1 -1
- package/dist/record/skybox-post-pass.d.ts +6 -4
- package/dist/record/skybox-post-pass.d.ts.map +1 -1
- package/dist/record/typed-frame-graph.d.ts +22 -2
- package/dist/record/typed-frame-graph.d.ts.map +1 -1
- package/dist/record/view-ubo.d.ts +11 -3
- package/dist/record/view-ubo.d.ts.map +1 -1
- package/dist/record/volume-params.d.ts +9 -0
- package/dist/record/volume-params.d.ts.map +1 -0
- package/dist/recovery/render-system-candidate.d.ts +10 -0
- package/dist/recovery/render-system-candidate.d.ts.map +1 -1
- package/dist/reflection/record-owner.d.ts.map +1 -1
- package/dist/render-contract.d.ts +66 -8
- package/dist/render-contract.d.ts.map +1 -1
- package/dist/render-graph-primitives.d.ts.map +1 -1
- package/dist/render-pipeline.d.ts +106 -3
- package/dist/render-pipeline.d.ts.map +1 -1
- package/dist/render-system-extract-tail.d.ts +3 -2
- package/dist/render-system-extract-tail.d.ts.map +1 -1
- package/dist/render-system-extract.d.ts +24 -10
- package/dist/render-system-extract.d.ts.map +1 -1
- package/dist/render-system-presentation.d.ts +23 -0
- package/dist/render-system-presentation.d.ts.map +1 -0
- package/dist/render-system-producer-roots.d.ts +10 -0
- package/dist/render-system-producer-roots.d.ts.map +1 -0
- package/dist/render-system-residency.d.ts +12 -0
- package/dist/render-system-residency.d.ts.map +1 -0
- package/dist/render-system.d.ts +26 -15
- package/dist/render-system.d.ts.map +1 -1
- package/dist/scene/probe-blend.d.ts +27 -0
- package/dist/scene/probe-blend.d.ts.map +1 -1
- package/dist/scene/render-scene.d.ts +14 -5
- package/dist/scene/render-scene.d.ts.map +1 -1
- package/dist/ssao-buffers.d.ts +9 -0
- package/dist/ssao-buffers.d.ts.map +1 -1
- package/dist/surface/dynamic-input.d.ts +133 -0
- package/dist/surface/dynamic-input.d.ts.map +1 -0
- package/dist/surface/gpu-driven.d.ts +41 -0
- package/dist/surface/gpu-driven.d.ts.map +1 -0
- package/dist/surface/submission-observation.d.ts +136 -0
- package/dist/surface/submission-observation.d.ts.map +1 -0
- package/dist/systems/skin-palette-allocator.d.ts.map +1 -1
- package/dist/temporal/frame-coordinator.d.ts.map +1 -1
- package/dist/temporal/frame.d.ts +7 -0
- package/dist/temporal/frame.d.ts.map +1 -1
- package/dist/temporal/gpu.d.ts +13 -1
- package/dist/temporal/gpu.d.ts.map +1 -1
- package/dist/temporal/index.mjs +5 -5
- package/dist/temporal/inspection.d.ts.map +1 -1
- package/dist/temporal/standard-scene-data.d.ts.map +1 -1
- package/dist/temporal/target-coverage-attachment.d.ts.map +1 -1
- package/dist/temporal/view.d.ts +6 -1
- package/dist/temporal/view.d.ts.map +1 -1
- package/dist/transmission/single-layer-medium.d.ts +89 -0
- package/dist/transmission/single-layer-medium.d.ts.map +1 -0
- package/dist/typed-render-graph-primitives.d.ts +24 -9
- package/dist/typed-render-graph-primitives.d.ts.map +1 -1
- package/dist/volume/component.d.ts +9 -5
- package/dist/volume/component.d.ts.map +1 -1
- package/dist/volume/extract.d.ts +1 -1
- package/dist/volume/extract.d.ts.map +1 -1
- package/dist/volume/inspection.d.ts +2 -0
- package/dist/volume/inspection.d.ts.map +1 -1
- package/dist/volume/passes.d.ts +4 -1
- package/dist/volume/passes.d.ts.map +1 -1
- package/dist/volume/resources.d.ts.map +1 -1
- package/dist/volume/temporal.d.ts +3 -1
- package/dist/volume/temporal.d.ts.map +1 -1
- package/package.json +22 -21
- package/src/__tests__/analytic-fog-graph.unit.test.ts +199 -0
- package/src/__tests__/analytic-fog-optics.unit.test.ts +38 -0
- package/src/__tests__/atmosphere-daylight.dawn.test.ts +72 -0
- package/src/__tests__/barrel-distortion-lkg.integration.test.ts +353 -0
- package/src/__tests__/barrel-distortion.dawn.test.ts +41 -0
- package/src/__tests__/barrel-distortion.unit.test.ts +364 -0
- package/src/__tests__/bloom-exact-zero.unit.test.ts +112 -18
- package/src/__tests__/bloom-lifecycle.integration.test.ts +17 -4
- package/src/__tests__/construct-renderer-identity.unit.test.ts +49 -0
- package/src/__tests__/detached-recovery-graph.unit.test.ts +277 -0
- package/src/__tests__/device-loss-fanout.unit.test.ts +36 -1
- package/src/__tests__/docs-gate-green.unit.test.ts +112 -1
- package/src/__tests__/dynamic-resolution-plugin.integration.test.ts +20 -0
- package/src/__tests__/environment-fog-lanes.integration.test.ts +14 -0
- package/src/__tests__/environment-selection.unit.test.ts +12 -0
- package/src/__tests__/factory-contract.integration.test.ts +626 -113
- package/src/__tests__/feature-depth-input.dawn.test.ts +129 -2
- package/src/__tests__/frame-camera-selection.unit.test.ts +39 -1
- package/src/__tests__/frame-plan-contract.unit.test.ts +2 -0
- package/src/__tests__/fullscreen-feature-plan.unit.test.ts +14 -3
- package/src/__tests__/gpu-dirty-ranges.unit.test.ts +22 -0
- package/src/__tests__/gpu-driven-baseline.characterization.test.ts +16 -3
- package/src/__tests__/gpu-driven-batch-topology-pbr.unit.test.ts +12 -0
- package/src/__tests__/gpu-driven-indirect-raster-evidence.ts +2 -1
- package/src/__tests__/gpu-driven-material-artifacts.unit.test.ts +143 -0
- package/src/__tests__/gpu-driven-pbr.dawn.test.ts +2 -2
- package/src/__tests__/gpu-driven-production.integration.test.ts +482 -3
- package/src/__tests__/gpu-driven-shadow-views.dawn.test.ts +7 -6
- package/src/__tests__/gpu-driven-shadow-views.integration.test.ts +1 -1
- package/src/__tests__/gpu-driven-view-gpu-evidence.ts +103 -4
- package/src/__tests__/gpu-driven-view-graph.integration.test.ts +18 -2
- package/src/__tests__/gpu-driven-view.browser.test.ts +5 -8
- package/src/__tests__/gpu-driven-view.dawn.test.ts +6 -2
- package/src/__tests__/gpu-driven-view.unit.test.ts +1 -1
- package/src/__tests__/gpu-pass-timing-lifecycle.integration.test.ts +1 -0
- package/src/__tests__/gpu-pass-timing.browser.test.ts +6 -4
- package/src/__tests__/gpu-pass-timing.rhi-null.unit.test.ts +1 -0
- package/src/__tests__/gpu-resource-store-stride.unit.test.ts +12 -0
- package/src/__tests__/gpu-scene.unit.test.ts +210 -9
- package/src/__tests__/instance-allocation-failure.unit.test.ts +57 -0
- package/src/__tests__/instances-culling.integration.test.ts +10 -36
- package/src/__tests__/instances-store.unit.test.ts +105 -238
- package/src/__tests__/instances-world-ownership.integration.test.ts +62 -0
- package/src/__tests__/main-pass-material-medium-selection.unit.test.ts +146 -0
- package/src/__tests__/material-shader-prewarm.unit.test.ts +59 -0
- package/src/__tests__/material-snapshot-mutation.integration.test.ts +39 -1
- package/src/__tests__/mesh-submission-lifetime.unit.test.ts +31 -0
- package/src/__tests__/morph-culling-reentry.dawn.test.ts +5 -5
- package/src/__tests__/morph-visual-evidence.integration.test.ts +8 -7
- package/src/__tests__/motion-blur-compute.dawn.test.ts +589 -0
- package/src/__tests__/motion-blur.pixel.integration.test.ts +2 -2
- package/src/__tests__/nineslice-handle-surface.unit.test.ts +4 -4
- package/src/__tests__/pbr-view-layout.unit.test.ts +9 -0
- package/src/__tests__/physical-clearcoat.integration.test.ts +58 -0
- package/src/__tests__/prepared-gpu-driven-pbr.integration.test.ts +21 -0
- package/src/__tests__/prepared-graphics-capability.unit.test.ts +66 -2
- package/src/__tests__/prepared-graphics-lifecycle.unit.test.ts +86 -0
- package/src/__tests__/probe-bindings.unit.test.ts +582 -1
- package/src/__tests__/probe-scene-dirty.integration.test.ts +28 -1
- package/src/__tests__/public-surface.test-d.ts +8 -0
- package/src/__tests__/receipt-observation-retirement.unit.test.ts +65 -0
- package/src/__tests__/recovery-candidate-prepare.contract.test.ts +69 -0
- package/src/__tests__/render-error-code-owner.test-d.ts +9 -0
- package/src/__tests__/render-feature-diagnostics.unit.test.ts +15 -2
- package/src/__tests__/render-feature-error-reporting.unit.test.ts +44 -0
- package/src/__tests__/render-feature-prepared-diagnostics.unit.test.ts +10 -1
- package/src/__tests__/render-feature-retry.unit.test.ts +12 -1
- package/src/__tests__/render-feature-stage-fault-recovery.unit.test.ts +23 -0
- package/src/__tests__/render-scene-mixed-updates.integration.test.ts +145 -19
- package/src/__tests__/render-scene-projection.unit.test.ts +36 -11
- package/src/__tests__/render-scene-temporal-retry.unit.test.ts +37 -6
- package/src/__tests__/render-target-probe-soak.perf.test.ts +2 -2
- package/src/__tests__/render-temporal-environment-consumer.browser.test.ts +3 -3
- package/src/__tests__/render-temporal-environment-consumer.dawn.test.ts +5 -2
- package/src/__tests__/renderer-factory-material-contract.unit.test.ts +41 -7
- package/src/__tests__/renderer-frame-generation-fence.integration.test.ts +16 -0
- package/src/__tests__/renderer-frame-transaction.integration.test.ts +33 -11
- package/src/__tests__/resource-allocation.unit.test.ts +123 -0
- package/src/__tests__/shader-manifest-fixture.ts +4 -4
- package/src/__tests__/single-layer-medium-passes.unit.test.ts +275 -0
- package/src/__tests__/skin-motion-regression.unit.test.ts +70 -1
- package/src/__tests__/skin-palette-recycling.dawn.test.ts +97 -0
- package/src/__tests__/skinned-shadow-caster.test.ts +17 -0
- package/src/__tests__/ssr-carrier-public-contract.unit.test.ts +21 -0
- package/src/__tests__/ssr-gpu-dispatch.browser.test.ts +4 -4
- package/src/__tests__/ssr-gpu-dispatch.dawn.test.ts +2 -2
- package/src/__tests__/ssr-gpu-dispatch.ts +1 -1
- package/src/__tests__/ssr-receiver-coverage.dawn.test.ts +6 -2
- package/src/__tests__/standard-lighting-write.unit.test.ts +2 -1
- package/src/__tests__/standard-output-chain-contract.unit.test.ts +28 -0
- package/src/__tests__/standard-pbr-artifact-assembly.unit.test.ts +46 -1
- package/src/__tests__/standard-pipeline.dawn.test.ts +1 -1
- package/src/__tests__/standard-pipeline.integration.test.ts +200 -9
- package/src/__tests__/surface-dynamic-buffer-lifecycle.unit.test.ts +506 -0
- package/src/__tests__/surface-submission-observation.unit.test.ts +812 -0
- package/src/__tests__/temporal-history-lifecycle.unit.test.ts +32 -0
- package/src/__tests__/temporal-performance.integration.test.ts +3 -3
- package/src/__tests__/temporal-reset-matrix.unit.test.ts +10 -0
- package/src/__tests__/temporal-view.unit.test.ts +2 -1
- package/src/__tests__/typed-pipeline-topology.unit.test.ts +20 -4
- package/src/__tests__/visibility-instances.integration.test.ts +7 -19
- package/src/__tests__/visibility-producer-matrix.integration.test.ts +9 -20
- package/src/__tests__/volume-optics-oracle.unit.test.ts +7 -3
- package/src/__tests__/volumetric-fog-budget-recovery.integration.test.ts +189 -15
- package/src/__tests__/volumetric-fog-errors.unit.test.ts +4 -3
- package/src/__tests__/volumetric-fog-multiple.unit.test.ts +55 -0
- package/src/__tests__/volumetric-fog-spot-frame-optics.integration.test.ts +1 -1
- package/src/__tests__/volumetric-fog-stage-readback.dawn.test.ts +558 -68
- package/src/__tests__/volumetric-fog-temporal.unit.test.ts +27 -0
- package/src/__tests__/volumetric-fog-topology.unit.test.ts +23 -5
- package/src/assembly/analytic-fog-registration.ts +14 -0
- package/src/assembly/backend-contract.ts +30 -0
- package/src/assembly/barrel-distortion-inspection.ts +22 -0
- package/src/assembly/canvas-draw-guard.ts +11 -0
- package/src/assembly/cloud-shadow-entry.ts +22 -0
- package/src/assembly/dynamic-geometry-host.ts +65 -37
- package/src/assembly/dynamic-geometry-runtime.ts +7 -1
- package/src/assembly/factory.ts +2 -30
- package/src/assembly/fxaa-registration.ts +17 -0
- package/src/assembly/host-contract.ts +3 -3
- package/src/assembly/lod-observation.ts +12 -0
- package/src/assembly/material/assembly.ts +25 -13
- package/src/assembly/material/pipeline-helpers.ts +53 -12
- package/src/assembly/material-shader-policy.ts +55 -0
- package/src/assembly/material-shader-prewarm.ts +21 -10
- package/src/assembly/motion-blur-registration.ts +17 -0
- package/src/assembly/recovery/device-loss-fanout.ts +13 -0
- package/src/assembly/recovery/renderer-recover.ts +41 -18
- package/src/assembly/render-feature-post-processes.ts +54 -0
- package/src/assembly/renderer-facade.ts +6 -1
- package/src/assembly/renderer-feature-inspection.ts +8 -2
- package/src/assembly/renderer-frame-transaction.ts +23 -0
- package/src/assembly/renderer-inspection.ts +28 -0
- package/src/assembly/skin-palette-owner.ts +1 -1
- package/src/assembly/temporal-post-process-prewarm.ts +40 -0
- package/src/assembly/webgpu-pbr-ready.ts +9 -1
- package/src/assembly/webgpu-ready-contract.ts +8 -3
- package/src/assembly/webgpu-ready-per-pass.ts +104 -0
- package/src/assembly/webgpu-ready.ts +296 -306
- package/src/assembly/webgpu-renderer-bootstrap.ts +0 -12
- package/src/assembly/webgpu-renderer-observation-owner.ts +222 -0
- package/src/assembly/webgpu-renderer.ts +228 -281
- package/src/assembly/webgpu-vertex-layouts.ts +1 -1
- package/src/barrel-distortion.ts +247 -0
- package/src/bloom-admission.ts +21 -0
- package/src/cloud/__tests__/cloud-density-parity.dawn.test.ts +173 -0
- package/src/cloud/__tests__/cloud-layer-framebuffer-y.dawn.test.ts +265 -0
- package/src/cloud/__tests__/cloud-layer.browser.test.ts +432 -0
- package/src/cloud/__tests__/cloud-layer.unit.test.ts +634 -0
- package/src/cloud/density.ts +600 -0
- package/src/cloud/extract.ts +110 -0
- package/src/cloud/feature.ts +1810 -0
- package/src/cloud/frame-context.ts +42 -0
- package/src/cloud/inspection.ts +130 -0
- package/src/cloud/optics.ts +285 -0
- package/src/cloud/parameters.ts +255 -0
- package/src/cloud/resources.ts +122 -0
- package/src/cloud/shadow.ts +167 -0
- package/src/cloud/temporal.ts +226 -0
- package/src/components/__tests__/motion-blur.unit.test.ts +1 -0
- package/src/components/atmosphere.ts +4 -0
- package/src/components/barrel-distortion.ts +46 -0
- package/src/components/camera.ts +66 -10
- package/src/components/cloud-layer.ts +47 -0
- package/src/components/index.ts +2 -0
- package/src/components/instances.ts +18 -45
- package/src/components/mesh-filter.ts +11 -9
- package/src/components/motion-blur.ts +1 -0
- package/src/components/sprite-instances.ts +1 -1
- package/src/construct-renderer.ts +1 -1
- package/src/device/gpu-residency.ts +56 -12
- package/src/dynamic-geometry.ts +12 -1
- package/src/environment/analytic-fog.ts +44 -0
- package/src/environment/background.ts +2 -2
- package/src/errors/cloud.ts +103 -0
- package/src/errors/render.ts +58 -8
- package/src/examples/single-layer-medium-surface.ts +59 -0
- package/src/extract/camera.ts +35 -8
- package/src/extract/contracts.ts +12 -0
- package/src/extract/environment.ts +4 -0
- package/src/features/barrel-distortion.ts +172 -0
- package/src/features/error-reporting.ts +98 -0
- package/src/features/host.ts +138 -24
- package/src/features/motion-blur/__tests__/motion-blur-feature.unit.test.ts +111 -1
- package/src/features/motion-blur/__tests__/motion-blur-params.unit.test.ts +58 -3
- package/src/features/motion-blur/motion-blur-feature.ts +1519 -15
- package/src/features/motion-blur/motion-blur-params.ts +70 -2
- package/src/features/motion-blur/motion-blur-runtime.ts +176 -0
- package/src/features/plan.ts +33 -8
- package/src/features/prepared-gpu-work.ts +86 -35
- package/src/features/render-graph-compute.ts +13 -5
- package/src/features/render-graph-contribution.ts +11 -0
- package/src/features/render-graph-raster.ts +45 -3
- package/src/features/targets.ts +66 -0
- package/src/features/types.ts +47 -0
- package/src/fullscreen-post-process-pass.ts +41 -9
- package/src/gpu-dirty-ranges.ts +48 -0
- package/src/gpu-driven/batch-topology.ts +53 -0
- package/src/gpu-driven/material-artifacts.ts +35 -32
- package/src/gpu-driven/prepared-draw.ts +27 -14
- package/src/gpu-driven/production-raster-material.ts +1894 -0
- package/src/gpu-driven/production-raster.ts +904 -787
- package/src/gpu-driven/resource-allocation.ts +142 -0
- package/src/gpu-driven/shadow-ownership.ts +71 -0
- package/src/gpu-driven/view-gpu.ts +181 -10
- package/src/gpu-scene.ts +259 -101
- package/src/hdrp-buffers.ts +4 -3
- package/src/ibl/skylight-bind-group.ts +49 -7
- package/src/index.ts +228 -9
- package/src/inspection-types.ts +222 -2
- package/src/instance-buffer-cache.ts +4 -4
- package/src/instances.ts +151 -492
- package/src/pbr-pipeline.ts +219 -13
- package/src/pipeline/single-layer-medium-passes.ts +267 -0
- package/src/pipeline/standard-forward-lane.ts +313 -57
- package/src/pipeline/standard-output/graph.ts +8 -2
- package/src/pipeline/standard-output/types.ts +12 -1
- package/src/pipeline/standard-pipeline.ts +291 -18
- package/src/pipeline/standard-post.ts +397 -102
- package/src/pipeline-builder.ts +1 -1
- package/src/pipeline-spec.ts +5 -5
- package/src/plugin.ts +4 -0
- package/src/points-lines/__tests__/points-lines.bench.ts +17 -8
- package/src/points-lines/__tests__/view-ubo.unit.test.ts +2 -1
- package/src/prepare/prepared-graphics-resolver.ts +2 -0
- package/src/record/__tests__/main-pass-geometry.unit.test.ts +30 -0
- package/src/record/__tests__/sprite-material-abi.unit.test.ts +1 -1
- package/src/record/__tests__/temporal-payload.unit.test.ts +3 -2
- package/src/record/__tests__/transparent-group2-selection.unit.test.ts +11 -0
- package/src/record/__tests__/typed-frame-graph-plan.unit.test.ts +1 -0
- package/src/record/__tests__/view-ubo-layout.unit.test.ts +4 -3
- package/src/record/barrel-distortion-frame.ts +110 -0
- package/src/record/dynamic-geometry-consumption.ts +39 -9
- package/src/record/fold-buckets.ts +852 -0
- package/src/record/fold-instance-buffer.ts +51 -0
- package/src/record/frame-lighting.ts +36 -2
- package/src/record/frame-snapshot.ts +44 -4
- package/src/record/frame-targets.ts +10 -6
- package/src/record/frame.ts +373 -1099
- package/src/record/gpu-draw-receipts.ts +38 -0
- package/src/record/gpu-timing.ts +48 -5
- package/src/record/main-pass-geometry.ts +281 -83
- package/src/record/main-pass-material.ts +66 -4
- package/src/record/main-pass-sprite-draws.ts +13 -66
- package/src/record/main-pass.ts +156 -20
- package/src/record/mesh-ssbo.ts +43 -6
- package/src/record/motion-blur-receipt.ts +91 -0
- package/src/record/probe-blend-buffer.ts +180 -0
- package/src/record/recovery-pipeline.ts +35 -3
- package/src/record/render-context.ts +51 -31
- package/src/record/shadow-pass.ts +36 -2
- package/src/record/skybox-post-pass.ts +150 -200
- package/src/record/typed-frame-graph.ts +824 -44
- package/src/record/view-ubo.ts +26 -3
- package/src/record/volume-params.ts +225 -0
- package/src/recovery/render-system-candidate.ts +257 -52
- package/src/reflection/record-owner.ts +7 -3
- package/src/render-contract.ts +71 -8
- package/src/render-graph-primitives.ts +7 -1
- package/src/render-pipeline.ts +136 -1
- package/src/render-system-extract-tail.ts +72 -60
- package/src/render-system-extract.ts +117 -87
- package/src/render-system-presentation.ts +56 -0
- package/src/render-system-producer-roots.ts +96 -0
- package/src/render-system-residency.ts +159 -0
- package/src/render-system.ts +601 -482
- package/src/scene/probe-blend.ts +96 -4
- package/src/scene/render-scene.ts +431 -281
- package/src/ssao-buffers.ts +95 -2
- package/src/surface/__tests__/dynamic-input.unit.test.ts +374 -0
- package/src/surface/__tests__/gpu-driven.unit.test.ts +87 -0
- package/src/surface/dynamic-input.ts +658 -0
- package/src/surface/gpu-driven.ts +147 -0
- package/src/surface/submission-observation.ts +517 -0
- package/src/systems/skin-palette-allocator.ts +4 -1
- package/src/temporal/__tests__/temporal-frame-transaction.unit.test.ts +36 -0
- package/src/temporal/frame-coordinator.ts +8 -1
- package/src/temporal/frame.ts +20 -0
- package/src/temporal/gpu.ts +101 -17
- package/src/temporal/inspection.ts +7 -1
- package/src/temporal/standard-scene-data.ts +5 -0
- package/src/temporal/target-coverage-attachment.ts +4 -0
- package/src/temporal/view.ts +13 -2
- package/src/transmission/__tests__/single-layer-medium.unit.test.ts +149 -0
- package/src/transmission/__tests__/standard-transmission.dawn.test.ts +12 -11
- package/src/transmission/single-layer-medium.ts +322 -0
- package/src/typed-render-graph-primitives.ts +191 -50
- package/src/volume/component.ts +10 -10
- package/src/volume/extract.ts +11 -5
- package/src/volume/inspection.ts +3 -0
- package/src/volume/passes.ts +95 -8
- package/src/volume/resources.ts +2 -1
- package/src/volume/temporal.ts +11 -0
- package/dist/chunk-4NNZQCL3.mjs.map +0 -1
- package/dist/chunk-6TFBXLRJ.mjs.map +0 -1
- package/dist/chunk-DRR7D3KX.mjs.map +0 -1
- package/dist/chunk-GWCEMDVR.mjs.map +0 -1
- package/dist/chunk-JCIRYQ4V.mjs.map +0 -1
- package/dist/chunk-JRIPCMYC.mjs.map +0 -1
- package/dist/chunk-LULCA3OF.mjs +0 -1713
- package/dist/chunk-LULCA3OF.mjs.map +0 -1
- package/dist/chunk-PA5DRJNI.mjs.map +0 -1
|
@@ -4,8 +4,11 @@ import {
|
|
|
4
4
|
type GraphResourceResolver,
|
|
5
5
|
RenderGraphBuilder,
|
|
6
6
|
RenderGraphError,
|
|
7
|
+
type RenderGraphGenerationAllocationEntry,
|
|
8
|
+
type RenderGraphGenerationAllocationInspection,
|
|
7
9
|
type RenderGraphPassInstrumentation,
|
|
8
10
|
type RenderGraphPassInstrumentationScope,
|
|
11
|
+
type RenderGraphResourceAllocationInspection,
|
|
9
12
|
} from '@forgeax/engine-render-graph';
|
|
10
13
|
import type {
|
|
11
14
|
BindGroup,
|
|
@@ -22,6 +25,8 @@ import type {
|
|
|
22
25
|
import { RhiError } from '@forgeax/engine-rhi';
|
|
23
26
|
import { err, ok, type Result } from '@forgeax/engine-types';
|
|
24
27
|
import { executeRendererFrameTransaction } from '../assembly/renderer-frame-transaction';
|
|
28
|
+
import { standardBloomAdmitted } from '../bloom-admission';
|
|
29
|
+
import { CLOUD_LAYER_FEATURE_IDENTITY } from '../cloud/feature';
|
|
25
30
|
import { type RenderError, RenderFeatureStageFailedError } from '../errors/render';
|
|
26
31
|
import { depthOfFieldTopology } from '../features/depth-of-field/depth-of-field-feature';
|
|
27
32
|
import { resolveDepthOfFieldFrameParams } from '../features/depth-of-field/depth-of-field-params';
|
|
@@ -30,6 +35,7 @@ import {
|
|
|
30
35
|
hasSubmissionSensitiveFeatures,
|
|
31
36
|
type RenderFeaturePlanExecution,
|
|
32
37
|
} from '../features/host';
|
|
38
|
+
import { motionBlurTemporalDemand } from '../features/motion-blur/motion-blur-params';
|
|
33
39
|
import {
|
|
34
40
|
type RenderFeaturePlannedFrame,
|
|
35
41
|
renderFeaturePlanSignature,
|
|
@@ -93,11 +99,13 @@ import type { RenderTarget } from '../targets/contracts';
|
|
|
93
99
|
import type { RenderTargetPhysical } from '../targets/physical';
|
|
94
100
|
import {
|
|
95
101
|
abortTemporalGpuSubmit,
|
|
102
|
+
CLOUD_HISTORY_FORMATS,
|
|
96
103
|
commitTemporalGpuSubmit,
|
|
97
104
|
getTemporalGpuState,
|
|
98
105
|
hasPendingTemporalGpuSubmit,
|
|
99
106
|
retireTemporalGpuState,
|
|
100
107
|
retireTemporalGpuStateAfterFence,
|
|
108
|
+
stageTemporalGpuSubmit,
|
|
101
109
|
TEMPORAL_HISTORY_FORMATS,
|
|
102
110
|
temporalReadIndex,
|
|
103
111
|
temporalWriteIndex,
|
|
@@ -118,6 +126,7 @@ import type { GpuPassTimingPassIdentity } from './gpu-pass-timing/contract.js';
|
|
|
118
126
|
import type { GpuPassTimingCapture, GpuPassTimingSession } from './gpu-pass-timing/session.js';
|
|
119
127
|
import type { GpuTimingCapture } from './gpu-timing';
|
|
120
128
|
import { encodeMainPass } from './main-pass';
|
|
129
|
+
import { deriveMotionBlurExecutionReceipt } from './motion-blur-receipt';
|
|
121
130
|
import type {
|
|
122
131
|
_InternalRenderPipelineContext,
|
|
123
132
|
PipelineState,
|
|
@@ -321,6 +330,125 @@ function importTemporalHistoryTargets(
|
|
|
321
330
|
};
|
|
322
331
|
}
|
|
323
332
|
|
|
333
|
+
type CloudHistoryKind = keyof typeof CLOUD_HISTORY_FORMATS;
|
|
334
|
+
|
|
335
|
+
function cloudHistorySurface(
|
|
336
|
+
state: import('../temporal/gpu').TemporalGpuState,
|
|
337
|
+
kind: CloudHistoryKind,
|
|
338
|
+
index: 0 | 1,
|
|
339
|
+
): { readonly texture: Texture; readonly view: TextureView } {
|
|
340
|
+
if (!state.cloudHistoryEnabled) {
|
|
341
|
+
throw new Error('cloud history target resolved without a cloud-enabled temporal state');
|
|
342
|
+
}
|
|
343
|
+
switch (kind) {
|
|
344
|
+
case 'radiance':
|
|
345
|
+
if (state.cloudRadiance === undefined)
|
|
346
|
+
throw new Error('cloud radiance history is unavailable');
|
|
347
|
+
return state.cloudRadiance[index];
|
|
348
|
+
case 'transmittance':
|
|
349
|
+
if (state.cloudTransmittance === undefined)
|
|
350
|
+
throw new Error('cloud transmittance history is unavailable');
|
|
351
|
+
return state.cloudTransmittance[index];
|
|
352
|
+
case 'depth':
|
|
353
|
+
if (state.cloudDepth === undefined) throw new Error('cloud depth history is unavailable');
|
|
354
|
+
return state.cloudDepth[index];
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
/** Import one renderer-owned cloud history attachment into the typed graph. */
|
|
359
|
+
function importCloudHistoryTarget(
|
|
360
|
+
graph: RenderGraphBuilder<RenderPipelineFrame>,
|
|
361
|
+
label: string,
|
|
362
|
+
kind: CloudHistoryKind,
|
|
363
|
+
role: 'read' | 'write',
|
|
364
|
+
): import('../render-pipeline').RenderPipelineTarget {
|
|
365
|
+
const format = CLOUD_HISTORY_FORMATS[kind];
|
|
366
|
+
const texture = graph.importTexture(
|
|
367
|
+
label,
|
|
368
|
+
{
|
|
369
|
+
format,
|
|
370
|
+
// Cloud transport/history is intentionally half-resolution. The
|
|
371
|
+
// renderer-owned temporal state allocates the same ceil(width/2) extent
|
|
372
|
+
// and the full-resolution resolve reconstructs scene colour from it.
|
|
373
|
+
size: 'half-surface',
|
|
374
|
+
usage:
|
|
375
|
+
GPU_TEXTURE_USAGE_COPY_SRC |
|
|
376
|
+
GPU_TEXTURE_USAGE_COPY_DST |
|
|
377
|
+
GPU_TEXTURE_USAGE_RENDER_ATTACHMENT |
|
|
378
|
+
GPU_TEXTURE_USAGE_TEXTURE_BINDING,
|
|
379
|
+
domain: 'linear-hdr',
|
|
380
|
+
},
|
|
381
|
+
(frame) => {
|
|
382
|
+
const internal = frame as _InternalRenderPipelineContext;
|
|
383
|
+
const state = getTemporalGpuState(
|
|
384
|
+
internal.frameState,
|
|
385
|
+
internal.runtime.device,
|
|
386
|
+
internal.runtime.deviceScope,
|
|
387
|
+
frame.targetW,
|
|
388
|
+
frame.targetH,
|
|
389
|
+
true,
|
|
390
|
+
);
|
|
391
|
+
const index = role === 'read' ? temporalReadIndex(state) : temporalWriteIndex(state);
|
|
392
|
+
return cloudHistorySurface(state, kind, index).texture;
|
|
393
|
+
},
|
|
394
|
+
);
|
|
395
|
+
if (!texture.ok) throw texture.error;
|
|
396
|
+
const view = graph.importView(
|
|
397
|
+
texture.value,
|
|
398
|
+
{ label: `${label}.view`, dimension: '2d' },
|
|
399
|
+
(frame) => {
|
|
400
|
+
const internal = frame as _InternalRenderPipelineContext;
|
|
401
|
+
const state = getTemporalGpuState(
|
|
402
|
+
internal.frameState,
|
|
403
|
+
internal.runtime.device,
|
|
404
|
+
internal.runtime.deviceScope,
|
|
405
|
+
frame.targetW,
|
|
406
|
+
frame.targetH,
|
|
407
|
+
true,
|
|
408
|
+
);
|
|
409
|
+
const index = role === 'read' ? temporalReadIndex(state) : temporalWriteIndex(state);
|
|
410
|
+
return cloudHistorySurface(state, kind, index).view;
|
|
411
|
+
},
|
|
412
|
+
);
|
|
413
|
+
if (!view.ok) throw view.error;
|
|
414
|
+
return { texture: texture.value, view: view.value, format, sampleCount: 1 };
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
function importCloudHistoryTargets(
|
|
418
|
+
graph: RenderGraphBuilder<RenderPipelineFrame>,
|
|
419
|
+
): NonNullable<
|
|
420
|
+
import('../render-pipeline').RenderPipelineBuildContext<RenderPipelineFrame>['cloudHistory']
|
|
421
|
+
> {
|
|
422
|
+
return {
|
|
423
|
+
currentRadiance: importCloudHistoryTarget(
|
|
424
|
+
graph,
|
|
425
|
+
'cloud-history-radiance-current',
|
|
426
|
+
'radiance',
|
|
427
|
+
'write',
|
|
428
|
+
),
|
|
429
|
+
previousRadiance: importCloudHistoryTarget(
|
|
430
|
+
graph,
|
|
431
|
+
'cloud-history-radiance-previous',
|
|
432
|
+
'radiance',
|
|
433
|
+
'read',
|
|
434
|
+
),
|
|
435
|
+
currentTransmittance: importCloudHistoryTarget(
|
|
436
|
+
graph,
|
|
437
|
+
'cloud-history-transmittance-current',
|
|
438
|
+
'transmittance',
|
|
439
|
+
'write',
|
|
440
|
+
),
|
|
441
|
+
previousTransmittance: importCloudHistoryTarget(
|
|
442
|
+
graph,
|
|
443
|
+
'cloud-history-transmittance-previous',
|
|
444
|
+
'transmittance',
|
|
445
|
+
'read',
|
|
446
|
+
),
|
|
447
|
+
currentDepth: importCloudHistoryTarget(graph, 'cloud-history-depth-current', 'depth', 'write'),
|
|
448
|
+
previousDepth: importCloudHistoryTarget(graph, 'cloud-history-depth-previous', 'depth', 'read'),
|
|
449
|
+
};
|
|
450
|
+
}
|
|
451
|
+
|
|
324
452
|
function importSsrHistoryTarget(
|
|
325
453
|
graph: RenderGraphBuilder<RenderPipelineFrame>,
|
|
326
454
|
label: string,
|
|
@@ -435,7 +563,15 @@ export function shouldUseTemporalFrameTransaction(
|
|
|
435
563
|
export function isMotionBlurTemporalDemand(
|
|
436
564
|
motionBlur: CameraSnapshot['motionBlur'] | undefined,
|
|
437
565
|
): boolean {
|
|
438
|
-
return
|
|
566
|
+
return (
|
|
567
|
+
motionBlur !== undefined &&
|
|
568
|
+
motionBlurTemporalDemand({
|
|
569
|
+
shutterAngle: motionBlur.shutterAngle,
|
|
570
|
+
maxRadiusPixels: motionBlur.maxRadiusPixels,
|
|
571
|
+
sampleCount: motionBlur.sampleCount,
|
|
572
|
+
targetFps: motionBlur.targetFps ?? 60,
|
|
573
|
+
})
|
|
574
|
+
);
|
|
439
575
|
}
|
|
440
576
|
|
|
441
577
|
/**
|
|
@@ -968,6 +1104,7 @@ export interface RenderFeatureGraphRuntimeState {
|
|
|
968
1104
|
string,
|
|
969
1105
|
import('../fullscreen-post-process-pass').PostProcessShaderEntry
|
|
970
1106
|
>;
|
|
1107
|
+
postProcessIdentities: readonly string[];
|
|
971
1108
|
}
|
|
972
1109
|
|
|
973
1110
|
/** The exact fields that define one validated feature-plan collection. */
|
|
@@ -1028,6 +1165,8 @@ export interface RenderFeatureGraphCandidate {
|
|
|
1028
1165
|
string,
|
|
1029
1166
|
import('../fullscreen-post-process-pass').PostProcessShaderEntry
|
|
1030
1167
|
>;
|
|
1168
|
+
/** Public Standard post-effect identities; graph-local resources stay internal. */
|
|
1169
|
+
readonly postProcessIdentities?: readonly string[];
|
|
1031
1170
|
/**
|
|
1032
1171
|
* Physical transient graphics resources are imported into the compiled
|
|
1033
1172
|
* graph. Their lease therefore needs a new graph even when the declarative
|
|
@@ -1051,6 +1190,216 @@ export interface RenderFeatureGraphCandidate {
|
|
|
1051
1190
|
|
|
1052
1191
|
const featureGraphStates = new WeakMap<RenderSystemInternals, RenderFeatureGraphRuntimeState>();
|
|
1053
1192
|
const graphDeviceGenerations = new WeakMap<object, number>();
|
|
1193
|
+
const graphRetirementFailures = new WeakMap<
|
|
1194
|
+
RenderFrameState,
|
|
1195
|
+
Set<CompiledRenderGraph<RenderPipelineFrame>>
|
|
1196
|
+
>();
|
|
1197
|
+
|
|
1198
|
+
type GraphGenerationRole = 'active' | 'candidate' | 'retiring';
|
|
1199
|
+
type GraphGenerationStatus = 'active' | 'retiring' | 'failed' | 'retired';
|
|
1200
|
+
|
|
1201
|
+
interface GraphGenerationAllocationRecord {
|
|
1202
|
+
readonly graph: CompiledRenderGraph<RenderPipelineFrame>;
|
|
1203
|
+
status: GraphGenerationStatus;
|
|
1204
|
+
allocation: RenderGraphResourceAllocationInspection | undefined;
|
|
1205
|
+
}
|
|
1206
|
+
|
|
1207
|
+
/**
|
|
1208
|
+
* One stable allocation owner for a RenderSystem lifetime. Recovery builds a
|
|
1209
|
+
* detached frame state, but that state intentionally shares this owner before
|
|
1210
|
+
* it can publish a candidate into the active RenderSystem. Graph records stay
|
|
1211
|
+
* here across asynchronous retirement so a successful replacement cannot
|
|
1212
|
+
* erase the overlap peak before the next public inspection.
|
|
1213
|
+
*/
|
|
1214
|
+
interface GraphGenerationAllocationOwner {
|
|
1215
|
+
readonly records: Map<CompiledRenderGraph<RenderPipelineFrame>, GraphGenerationAllocationRecord>;
|
|
1216
|
+
peakBytes: number;
|
|
1217
|
+
}
|
|
1218
|
+
|
|
1219
|
+
const graphGenerationAllocationOwners = new WeakMap<
|
|
1220
|
+
RenderFrameState,
|
|
1221
|
+
GraphGenerationAllocationOwner
|
|
1222
|
+
>();
|
|
1223
|
+
|
|
1224
|
+
function graphGenerationAllocationOwner(
|
|
1225
|
+
frameState: RenderFrameState,
|
|
1226
|
+
): GraphGenerationAllocationOwner {
|
|
1227
|
+
const existing = graphGenerationAllocationOwners.get(frameState);
|
|
1228
|
+
if (existing !== undefined) return existing;
|
|
1229
|
+
const created: GraphGenerationAllocationOwner = { records: new Map(), peakBytes: 0 };
|
|
1230
|
+
graphGenerationAllocationOwners.set(frameState, created);
|
|
1231
|
+
return created;
|
|
1232
|
+
}
|
|
1233
|
+
|
|
1234
|
+
function graphRetirementFailureSet(
|
|
1235
|
+
frameState: RenderFrameState,
|
|
1236
|
+
): Set<CompiledRenderGraph<RenderPipelineFrame>> {
|
|
1237
|
+
const existing = graphRetirementFailures.get(frameState);
|
|
1238
|
+
if (existing !== undefined) return existing;
|
|
1239
|
+
const created = new Set<CompiledRenderGraph<RenderPipelineFrame>>();
|
|
1240
|
+
graphRetirementFailures.set(frameState, created);
|
|
1241
|
+
return created;
|
|
1242
|
+
}
|
|
1243
|
+
|
|
1244
|
+
/** Share the renderer-owned graph ledger with a detached recovery frame state. */
|
|
1245
|
+
export function shareRenderGraphGenerationAllocationOwner(
|
|
1246
|
+
source: RenderFrameState,
|
|
1247
|
+
target: RenderFrameState,
|
|
1248
|
+
): void {
|
|
1249
|
+
graphGenerationAllocationOwners.set(target, graphGenerationAllocationOwner(source));
|
|
1250
|
+
graphRetirementFailures.set(target, graphRetirementFailureSet(source));
|
|
1251
|
+
}
|
|
1252
|
+
|
|
1253
|
+
function observeGraphGenerationAllocation(frameState: RenderFrameState): void {
|
|
1254
|
+
const owner = graphGenerationAllocationOwner(frameState);
|
|
1255
|
+
let simultaneousBytes = 0;
|
|
1256
|
+
for (const record of owner.records.values()) {
|
|
1257
|
+
if (record.status === 'retired') continue;
|
|
1258
|
+
const allocation = record.graph.inspect().resourceAllocation;
|
|
1259
|
+
record.allocation = allocation;
|
|
1260
|
+
if (allocation !== undefined) {
|
|
1261
|
+
simultaneousBytes += allocation.liveBytes + allocation.pendingRetirementBytes;
|
|
1262
|
+
}
|
|
1263
|
+
}
|
|
1264
|
+
owner.peakBytes = Math.max(owner.peakBytes, simultaneousBytes);
|
|
1265
|
+
}
|
|
1266
|
+
|
|
1267
|
+
function trackGraphGeneration(
|
|
1268
|
+
frameState: RenderFrameState,
|
|
1269
|
+
graph: CompiledRenderGraph<RenderPipelineFrame>,
|
|
1270
|
+
): void {
|
|
1271
|
+
const owner = graphGenerationAllocationOwner(frameState);
|
|
1272
|
+
const record = owner.records.get(graph);
|
|
1273
|
+
if (record === undefined) {
|
|
1274
|
+
owner.records.set(graph, { graph, status: 'active', allocation: undefined });
|
|
1275
|
+
} else if (record.status === 'retired') {
|
|
1276
|
+
record.status = 'active';
|
|
1277
|
+
}
|
|
1278
|
+
observeGraphGenerationAllocation(frameState);
|
|
1279
|
+
}
|
|
1280
|
+
|
|
1281
|
+
function setGraphGenerationRetiring(
|
|
1282
|
+
frameState: RenderFrameState,
|
|
1283
|
+
graph: CompiledRenderGraph<RenderPipelineFrame>,
|
|
1284
|
+
): void {
|
|
1285
|
+
const owner = graphGenerationAllocationOwner(frameState);
|
|
1286
|
+
const record = owner.records.get(graph);
|
|
1287
|
+
if (record === undefined) {
|
|
1288
|
+
owner.records.set(graph, { graph, status: 'retiring', allocation: undefined });
|
|
1289
|
+
} else if (record.status !== 'failed') {
|
|
1290
|
+
record.status = 'retiring';
|
|
1291
|
+
}
|
|
1292
|
+
}
|
|
1293
|
+
|
|
1294
|
+
function setGraphGenerationRetirementResult(
|
|
1295
|
+
frameState: RenderFrameState,
|
|
1296
|
+
graph: CompiledRenderGraph<RenderPipelineFrame>,
|
|
1297
|
+
succeeded: boolean,
|
|
1298
|
+
): void {
|
|
1299
|
+
const owner = graphGenerationAllocationOwner(frameState);
|
|
1300
|
+
const record = owner.records.get(graph);
|
|
1301
|
+
if (record !== undefined) record.status = succeeded ? 'retired' : 'failed';
|
|
1302
|
+
observeGraphGenerationAllocation(frameState);
|
|
1303
|
+
// A successful graph no longer owns any handles. Keep the renderer-level
|
|
1304
|
+
// peak scalar, but release the graph object from the generation map; failed
|
|
1305
|
+
// and pending owners remain retained for recovery inspection.
|
|
1306
|
+
if (succeeded) owner.records.delete(graph);
|
|
1307
|
+
}
|
|
1308
|
+
|
|
1309
|
+
/**
|
|
1310
|
+
* Project the actual RenderSystem graph-generation owners as one detached
|
|
1311
|
+
* allocation receipt. The candidate and fallback graph can overlap before a
|
|
1312
|
+
* submit settles; failed retirement stays visible until the frame owner is
|
|
1313
|
+
* discarded instead of disappearing with the asynchronous Set entry.
|
|
1314
|
+
*/
|
|
1315
|
+
export function inspectRenderGraphGenerationAllocation(
|
|
1316
|
+
frameState: RenderFrameState,
|
|
1317
|
+
): RenderGraphGenerationAllocationInspection {
|
|
1318
|
+
const rolesByGraph = new Map<
|
|
1319
|
+
CompiledRenderGraph<RenderPipelineFrame>,
|
|
1320
|
+
Set<GraphGenerationRole>
|
|
1321
|
+
>();
|
|
1322
|
+
const add = (
|
|
1323
|
+
graph: CompiledRenderGraph<RenderPipelineFrame> | null | undefined,
|
|
1324
|
+
role: GraphGenerationRole,
|
|
1325
|
+
) => {
|
|
1326
|
+
if (graph === null || graph === undefined) return;
|
|
1327
|
+
const roles = rolesByGraph.get(graph);
|
|
1328
|
+
if (roles === undefined) rolesByGraph.set(graph, new Set([role]));
|
|
1329
|
+
else roles.add(role);
|
|
1330
|
+
};
|
|
1331
|
+
add(frameState.compiledFrameGraph, 'active');
|
|
1332
|
+
add(frameState.volumetricFogCandidateGraph, 'candidate');
|
|
1333
|
+
add(frameState.volumetricFogPreviousGraph, 'retiring');
|
|
1334
|
+
add(frameState.depthOfFieldCandidateGraph, 'candidate');
|
|
1335
|
+
add(frameState.depthOfFieldPreviousGraph, 'retiring');
|
|
1336
|
+
add(frameState.barrelDistortionCandidateGraph, 'candidate');
|
|
1337
|
+
add(frameState.barrelDistortionPreviousGraph, 'retiring');
|
|
1338
|
+
for (const graph of frameState.retiredCompiledFrameGraphs) add(graph, 'retiring');
|
|
1339
|
+
for (const graph of graphRetirementFailureSet(frameState)) add(graph, 'retiring');
|
|
1340
|
+
|
|
1341
|
+
const owner = graphGenerationAllocationOwner(frameState);
|
|
1342
|
+
const entries: RenderGraphGenerationAllocationEntry[] = [];
|
|
1343
|
+
let unavailableGenerationCount = 0;
|
|
1344
|
+
for (const [graph, record] of owner.records) {
|
|
1345
|
+
if (record.status === 'retired') continue;
|
|
1346
|
+
const roles = rolesByGraph.get(graph) ?? new Set<GraphGenerationRole>();
|
|
1347
|
+
if (record.status === 'retiring' || record.status === 'failed') roles.add('retiring');
|
|
1348
|
+
if (roles.size === 0) {
|
|
1349
|
+
// A candidate can be detached from the active state's role fields while
|
|
1350
|
+
// it is still being prepared. Keep its owner record observable until
|
|
1351
|
+
// the publication or cleanup event settles it.
|
|
1352
|
+
roles.add(record.status === 'active' ? 'active' : 'retiring');
|
|
1353
|
+
}
|
|
1354
|
+
// Inspection is a projection of the graph's current ledger. The cached
|
|
1355
|
+
// snapshot is only for event-time peak updates; using it here would make
|
|
1356
|
+
// a successfully fenced graph look live after its retirement started.
|
|
1357
|
+
const allocation = graph.inspect().resourceAllocation;
|
|
1358
|
+
record.allocation = allocation;
|
|
1359
|
+
if (allocation === undefined) {
|
|
1360
|
+
unavailableGenerationCount += 1;
|
|
1361
|
+
continue;
|
|
1362
|
+
}
|
|
1363
|
+
const retirement =
|
|
1364
|
+
record.status === 'failed' ? 'failed' : roles.has('retiring') ? 'pending' : 'active';
|
|
1365
|
+
entries.push({
|
|
1366
|
+
generation: graph.inspect().generation,
|
|
1367
|
+
roles: Object.freeze([...roles]),
|
|
1368
|
+
retirement,
|
|
1369
|
+
allocation,
|
|
1370
|
+
});
|
|
1371
|
+
}
|
|
1372
|
+
entries.sort((left, right) => left.generation - right.generation);
|
|
1373
|
+
const liveBytes = entries.reduce((sum, entry) => sum + entry.allocation.liveBytes, 0);
|
|
1374
|
+
const pendingRetirementBytes = entries.reduce(
|
|
1375
|
+
(sum, entry) => sum + entry.allocation.pendingRetirementBytes,
|
|
1376
|
+
0,
|
|
1377
|
+
);
|
|
1378
|
+
const peakBytes = Math.max(owner.peakBytes, liveBytes + pendingRetirementBytes);
|
|
1379
|
+
const failedEntries = entries.filter((entry) => entry.retirement === 'failed');
|
|
1380
|
+
return Object.freeze({
|
|
1381
|
+
unit: 'engine-allocation-bytes',
|
|
1382
|
+
physicalResidency: 'unknown',
|
|
1383
|
+
availability:
|
|
1384
|
+
entries.length === 0
|
|
1385
|
+
? unavailableGenerationCount === 0
|
|
1386
|
+
? 'complete'
|
|
1387
|
+
: 'unavailable'
|
|
1388
|
+
: unavailableGenerationCount === 0
|
|
1389
|
+
? 'complete'
|
|
1390
|
+
: 'partial',
|
|
1391
|
+
unavailableGenerationCount,
|
|
1392
|
+
entries: Object.freeze(entries.map((entry) => Object.freeze(entry))),
|
|
1393
|
+
liveBytes,
|
|
1394
|
+
pendingRetirementBytes,
|
|
1395
|
+
peakBytes,
|
|
1396
|
+
failedRetirementCount: failedEntries.length,
|
|
1397
|
+
failedRetirementBytes: failedEntries.reduce(
|
|
1398
|
+
(sum, entry) => sum + entry.allocation.liveBytes + entry.allocation.pendingRetirementBytes,
|
|
1399
|
+
0,
|
|
1400
|
+
),
|
|
1401
|
+
});
|
|
1402
|
+
}
|
|
1054
1403
|
|
|
1055
1404
|
interface MutableRenderFeatureGraphInspection {
|
|
1056
1405
|
planRevisionState: RenderFeaturePlanRevisionState;
|
|
@@ -1216,6 +1565,7 @@ export function getRenderFeatureGraphState(
|
|
|
1216
1565
|
const created: RenderFeatureGraphRuntimeState = {
|
|
1217
1566
|
plans: [],
|
|
1218
1567
|
fullscreenEffects: new Map(),
|
|
1568
|
+
postProcessIdentities: [],
|
|
1219
1569
|
};
|
|
1220
1570
|
featureGraphStates.set(internals, created);
|
|
1221
1571
|
return created;
|
|
@@ -1225,6 +1575,7 @@ export function resetRenderFeatureGraphState(internals: RenderSystemInternals):
|
|
|
1225
1575
|
const state = getRenderFeatureGraphState(internals);
|
|
1226
1576
|
state.plans = [];
|
|
1227
1577
|
state.fullscreenEffects = new Map();
|
|
1578
|
+
state.postProcessIdentities = [];
|
|
1228
1579
|
}
|
|
1229
1580
|
|
|
1230
1581
|
export function reportRenderFeatureGraphError(
|
|
@@ -1343,6 +1694,7 @@ function commitFeatureCandidate(
|
|
|
1343
1694
|
const state = getRenderFeatureGraphState(internals);
|
|
1344
1695
|
state.plans = candidate.plans;
|
|
1345
1696
|
state.fullscreenEffects = candidate.fullscreenEffects;
|
|
1697
|
+
state.postProcessIdentities = candidate.postProcessIdentities ?? [];
|
|
1346
1698
|
}
|
|
1347
1699
|
|
|
1348
1700
|
function topologyOf(
|
|
@@ -1364,6 +1716,8 @@ function topologyOf(
|
|
|
1364
1716
|
standardLighting: StandardTopologyInputValue | undefined,
|
|
1365
1717
|
ssr: SsrSpatialAdmission | undefined,
|
|
1366
1718
|
renderExtent: RenderExtent | undefined,
|
|
1719
|
+
surfaceMediumActive: boolean | undefined,
|
|
1720
|
+
analyticFog: boolean,
|
|
1367
1721
|
): Result<RenderPipelineTopology, RhiError> {
|
|
1368
1722
|
const cascadeCount = Math.max(1, Math.min(4, Math.round(lights.cascadeCount ?? 1))) as
|
|
1369
1723
|
| 1
|
|
@@ -1384,10 +1738,9 @@ function topologyOf(
|
|
|
1384
1738
|
floatRenderAttachment: internals.device.caps.rgba16floatRenderable,
|
|
1385
1739
|
});
|
|
1386
1740
|
if (!surfaceProfile.ok) return surfaceProfile;
|
|
1387
|
-
const featurePostEffects =
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
].map(([id]) => id);
|
|
1741
|
+
const featurePostEffects =
|
|
1742
|
+
featureGraphCandidate?.postProcessIdentities ??
|
|
1743
|
+
getRenderFeatureGraphState(internals).postProcessIdentities;
|
|
1391
1744
|
const featurePostEffectDeclarations = [
|
|
1392
1745
|
...(featureGraphCandidate?.fullscreenEffects ??
|
|
1393
1746
|
getRenderFeatureGraphState(internals).fullscreenEffects),
|
|
@@ -1430,6 +1783,7 @@ function topologyOf(
|
|
|
1430
1783
|
reflectionFallback: { enabled: frameState.reflectionFallbackDemand === true },
|
|
1431
1784
|
ssr,
|
|
1432
1785
|
...(renderExtent === undefined ? {} : { extent: renderExtent }),
|
|
1786
|
+
analyticFog: !clearOnly && analyticFog,
|
|
1433
1787
|
surface: {
|
|
1434
1788
|
width,
|
|
1435
1789
|
height,
|
|
@@ -1440,7 +1794,12 @@ function topologyOf(
|
|
|
1440
1794
|
camera: {
|
|
1441
1795
|
tonemap: camera.tonemap,
|
|
1442
1796
|
antialias: camera.antialias,
|
|
1443
|
-
|
|
1797
|
+
// Bloom intensity is a frame parameter, not a graph identity. Fold
|
|
1798
|
+
// only its zero/non-zero admission into the closed topology switch so
|
|
1799
|
+
// positive intensity changes update the recorder UBO in place.
|
|
1800
|
+
bloom: standardBloomAdmitted(camera) ? 'on' : 'off',
|
|
1801
|
+
bloomIntensity: camera.bloomIntensity,
|
|
1802
|
+
barrelDistortion: !clearOnly && (camera.barrelDistortion?.strength ?? 0) > 0,
|
|
1444
1803
|
...(depthOfField === undefined ? {} : { depthOfField }),
|
|
1445
1804
|
},
|
|
1446
1805
|
atmosphere: !clearOnly && frameState.environmentFrame?.source.kind === 'atmosphere',
|
|
@@ -1494,6 +1853,16 @@ function topologyOf(
|
|
|
1494
1853
|
return {
|
|
1495
1854
|
enabled: true,
|
|
1496
1855
|
format: volumetricFog.densityAsset.format,
|
|
1856
|
+
additional: (volumetricFog.additional ?? []).flatMap((member) =>
|
|
1857
|
+
member.densityAsset?.shape.viewDimension === '3d'
|
|
1858
|
+
? [
|
|
1859
|
+
{
|
|
1860
|
+
format: member.densityAsset.format,
|
|
1861
|
+
extent: member.densityAsset.shape.extent,
|
|
1862
|
+
},
|
|
1863
|
+
]
|
|
1864
|
+
: [],
|
|
1865
|
+
),
|
|
1497
1866
|
extent: {
|
|
1498
1867
|
width: volumetricFog.densityAsset.shape.extent.width,
|
|
1499
1868
|
height: volumetricFog.densityAsset.shape.extent.height,
|
|
@@ -1501,7 +1870,7 @@ function topologyOf(
|
|
|
1501
1870
|
},
|
|
1502
1871
|
froxelExtent: deriveVolumetricFogExtent(
|
|
1503
1872
|
{ width, height },
|
|
1504
|
-
volumeProfile.depth,
|
|
1873
|
+
volumeProfile.depth * (1 + (volumetricFog.additional?.length ?? 0)),
|
|
1505
1874
|
volumeProfile.tileSize,
|
|
1506
1875
|
),
|
|
1507
1876
|
resolvedExtent: deriveVolumetricFogResolvedExtent(
|
|
@@ -1542,6 +1911,9 @@ function topologyOf(
|
|
|
1542
1911
|
activeCount: 0,
|
|
1543
1912
|
needsRoughMips: false,
|
|
1544
1913
|
},
|
|
1914
|
+
...((surfaceMediumActive ?? gpuDriven?.surfaceSubmission !== undefined)
|
|
1915
|
+
? { singleLayerMedium: true }
|
|
1916
|
+
: {}),
|
|
1545
1917
|
});
|
|
1546
1918
|
}
|
|
1547
1919
|
|
|
@@ -1566,6 +1938,30 @@ function targetResolver(
|
|
|
1566
1938
|
...(named.resolveTarget === undefined ? {} : { resolveTarget: named.resolveTarget }),
|
|
1567
1939
|
};
|
|
1568
1940
|
}
|
|
1941
|
+
if (typeof resource === 'string') {
|
|
1942
|
+
const target = targets.find((candidate) => candidate.name === resource);
|
|
1943
|
+
if (target !== undefined) {
|
|
1944
|
+
return {
|
|
1945
|
+
texture: target.texture,
|
|
1946
|
+
view: target.view,
|
|
1947
|
+
...(target.resolveTarget === undefined ? {} : { resolveTarget: target.resolveTarget }),
|
|
1948
|
+
};
|
|
1949
|
+
}
|
|
1950
|
+
// Standard lanes expose the depth attachment as a semantic target
|
|
1951
|
+
// without duplicating the public `depth` name on every concrete graph
|
|
1952
|
+
// projection. Keep the string alias stable for feature-authored
|
|
1953
|
+
// fullscreen bindings while preserving the typed target identity.
|
|
1954
|
+
if (resource === 'depth') {
|
|
1955
|
+
const depth = targets.find((candidate) => candidate.kind === 'scene-depth');
|
|
1956
|
+
if (depth !== undefined) {
|
|
1957
|
+
return {
|
|
1958
|
+
texture: depth.texture,
|
|
1959
|
+
view: depth.view,
|
|
1960
|
+
...(depth.resolveTarget === undefined ? {} : { resolveTarget: depth.resolveTarget }),
|
|
1961
|
+
};
|
|
1962
|
+
}
|
|
1963
|
+
}
|
|
1964
|
+
}
|
|
1569
1965
|
}
|
|
1570
1966
|
if (isSceneDataTarget(resource)) {
|
|
1571
1967
|
const semantic = semanticTargets.find(
|
|
@@ -1577,11 +1973,27 @@ function targetResolver(
|
|
|
1577
1973
|
: { texture: semantic.texture, view: semantic.view };
|
|
1578
1974
|
}
|
|
1579
1975
|
if (!isRenderFeatureTargetHandle(resource)) return undefined;
|
|
1976
|
+
// A typed feature handle is an identity, not a format request. Falling
|
|
1977
|
+
// back to another same-format target can silently bind scene color in
|
|
1978
|
+
// place of a missing cloud history/shadow resource and turn a producer
|
|
1979
|
+
// failure into plausible but incorrect pixels.
|
|
1980
|
+
// Standard lanes expose scene depth as a semantic target without a
|
|
1981
|
+
// duplicated public name, while feature plans use the stable `depth`
|
|
1982
|
+
// handle name. Preserve that one semantic alias here as well as above for
|
|
1983
|
+
// string-authored fullscreen bindings.
|
|
1580
1984
|
const target = targets.find(
|
|
1581
1985
|
(candidate) =>
|
|
1582
1986
|
candidate.kind === resource.kind &&
|
|
1583
1987
|
candidate.format === resource.format &&
|
|
1584
|
-
candidate.sampleCount === resource.sampleCount
|
|
1988
|
+
candidate.sampleCount === resource.sampleCount &&
|
|
1989
|
+
(resource.name === undefined ||
|
|
1990
|
+
candidate.name === resource.name ||
|
|
1991
|
+
(resource.kind === 'scene-color' &&
|
|
1992
|
+
resource.name === 'color' &&
|
|
1993
|
+
candidate.kind === 'scene-color') ||
|
|
1994
|
+
(resource.kind === 'scene-depth' &&
|
|
1995
|
+
resource.name === 'depth' &&
|
|
1996
|
+
candidate.kind === 'scene-depth')),
|
|
1585
1997
|
);
|
|
1586
1998
|
return target === undefined
|
|
1587
1999
|
? undefined
|
|
@@ -1601,6 +2013,9 @@ function resolveTargetBindings(
|
|
|
1601
2013
|
};
|
|
1602
2014
|
readonly resources: GraphResourceResolver;
|
|
1603
2015
|
readonly resolveTarget: RenderFeatureGraphTargetResolver;
|
|
2016
|
+
readonly resolveGpuResource?: (
|
|
2017
|
+
name: string,
|
|
2018
|
+
) => import('../features/prepared-gpu-work').RenderFeatureResolvedGpuBuffer | undefined;
|
|
1604
2019
|
},
|
|
1605
2020
|
featurePostProcessEntries?: ReadonlyMap<string, PostProcessShaderEntry>,
|
|
1606
2021
|
): RenderFeatureGraphBindingsResolution | undefined {
|
|
@@ -1612,6 +2027,136 @@ function resolveTargetBindings(
|
|
|
1612
2027
|
const sceneDepth = descriptor?.values.sceneDepth;
|
|
1613
2028
|
const sceneDepthBinding = descriptor?.values.sceneDepthBinding;
|
|
1614
2029
|
if (pipeline === undefined) return undefined;
|
|
2030
|
+
if (descriptor?.values.view === true) {
|
|
2031
|
+
const viewBindGroup = buildPerFrameBindGroups(
|
|
2032
|
+
frame.runtime as RenderSystemInternals,
|
|
2033
|
+
frame.frameState,
|
|
2034
|
+
frame.pipelineState,
|
|
2035
|
+
true,
|
|
2036
|
+
frame.bindGroupCounts,
|
|
2037
|
+
{
|
|
2038
|
+
directionalShadow: frame.frameState.currentDirectionalShadowView ?? undefined,
|
|
2039
|
+
spotShadow: frame.frameState.currentSpotShadowView ?? undefined,
|
|
2040
|
+
},
|
|
2041
|
+
true,
|
|
2042
|
+
frame.standardLighting,
|
|
2043
|
+
).viewBindGroup;
|
|
2044
|
+
return viewBindGroup === null ? undefined : { handle: viewBindGroup, dynamicOffsets: [0, 0] };
|
|
2045
|
+
}
|
|
2046
|
+
// Generic fullscreen producers (for example the CloudLayer scene pass)
|
|
2047
|
+
// share the renderer-owned post-process bind-group contract without opting
|
|
2048
|
+
// into the temporal two-input path below. Their input/depth aliases are
|
|
2049
|
+
// resolved from the active typed graph, so they cannot accidentally sample
|
|
2050
|
+
// a stale surface view or manufacture a second resource owner.
|
|
2051
|
+
if (descriptor?.values.fullscreen === true && !isTemporalFullscreenBinding(descriptor.values)) {
|
|
2052
|
+
const shader = descriptor.values.shader;
|
|
2053
|
+
if (typeof shader !== 'string') return undefined;
|
|
2054
|
+
const entry =
|
|
2055
|
+
featurePostProcessEntries?.get(shader) ?? frame.runtime.lookupPostProcess?.(shader);
|
|
2056
|
+
if (entry === undefined) return undefined;
|
|
2057
|
+
const depthFallback = descriptor.values.depthFallback === true;
|
|
2058
|
+
const depthValue = descriptor.values.depth;
|
|
2059
|
+
const depthTarget =
|
|
2060
|
+
depthFallback || depthValue === undefined
|
|
2061
|
+
? undefined
|
|
2062
|
+
: input.resolveTarget(depthValue as never);
|
|
2063
|
+
const fullscreen = buildFullscreenPostProcessPass(
|
|
2064
|
+
{ device: frame.runtime.device, errorRegistry: frame.runtime.errorRegistry },
|
|
2065
|
+
entry,
|
|
2066
|
+
depthTarget?.resolveTarget !== undefined,
|
|
2067
|
+
);
|
|
2068
|
+
if (fullscreen === null || fullscreen.sampler === null) return undefined;
|
|
2069
|
+
const inputDisabled = descriptor.values.input === false;
|
|
2070
|
+
const inputTarget = inputDisabled
|
|
2071
|
+
? undefined
|
|
2072
|
+
: input.resolveTarget(descriptor.values.input as never);
|
|
2073
|
+
const inputView =
|
|
2074
|
+
inputTarget === undefined
|
|
2075
|
+
? { ok: true as const, value: frame.pipelineState.defaultWhiteTextureView }
|
|
2076
|
+
: input.resources.textureView(inputTarget.view);
|
|
2077
|
+
if (!inputView.ok) return undefined;
|
|
2078
|
+
const depthView = depthFallback
|
|
2079
|
+
? frame.pipelineState.shadowFallbackTextureView
|
|
2080
|
+
: depthTarget === undefined
|
|
2081
|
+
? undefined
|
|
2082
|
+
: (() => {
|
|
2083
|
+
const depthTexture = input.resources.texture(depthTarget.texture);
|
|
2084
|
+
if (!depthTexture.ok) return undefined;
|
|
2085
|
+
const created = frame.runtime.device.createTextureView(depthTexture.value as Texture, {
|
|
2086
|
+
aspect: 'depth-only',
|
|
2087
|
+
dimension: '2d',
|
|
2088
|
+
});
|
|
2089
|
+
return created.ok ? created.value : undefined;
|
|
2090
|
+
})();
|
|
2091
|
+
if (
|
|
2092
|
+
depthTarget !== undefined &&
|
|
2093
|
+
(depthView === undefined || fullscreen.depthSampler === null)
|
|
2094
|
+
) {
|
|
2095
|
+
return undefined;
|
|
2096
|
+
}
|
|
2097
|
+
const additionalViews: { readonly binding: number; readonly view: TextureView }[] = [];
|
|
2098
|
+
const additionalNames = descriptor.values.additionalTextures;
|
|
2099
|
+
if (Array.isArray(additionalNames)) {
|
|
2100
|
+
for (const [index, value] of additionalNames.entries()) {
|
|
2101
|
+
if (typeof value !== 'string') return undefined;
|
|
2102
|
+
const target = input.resolveTarget(value);
|
|
2103
|
+
if (target === undefined) return undefined;
|
|
2104
|
+
const view = input.resources.textureView(target.view);
|
|
2105
|
+
if (!view.ok) return undefined;
|
|
2106
|
+
const binding = fullscreen.extraColorBindings[index];
|
|
2107
|
+
if (binding === undefined) return undefined;
|
|
2108
|
+
additionalViews.push({ binding, view: view.value });
|
|
2109
|
+
}
|
|
2110
|
+
}
|
|
2111
|
+
const layout = pipeline.getBindGroupLayout?.(1);
|
|
2112
|
+
if (layout === undefined) return undefined;
|
|
2113
|
+
const paramsBuffer = frame.runtime.getPostProcessParamsBuffer?.(shader);
|
|
2114
|
+
if (entry.params !== undefined && paramsBuffer === undefined) return undefined;
|
|
2115
|
+
if (entry.params !== undefined && paramsBuffer !== undefined) {
|
|
2116
|
+
const data = frame.postProcessParams.get(shader) ?? entry.params.defaultValue;
|
|
2117
|
+
if (data.byteLength !== entry.params.byteSize) return undefined;
|
|
2118
|
+
const written = frame.runtime.device.queue.writeBuffer(paramsBuffer, 0, data);
|
|
2119
|
+
if (!written.ok) return undefined;
|
|
2120
|
+
}
|
|
2121
|
+
const createdBindGroup = createFullscreenBindGroup(
|
|
2122
|
+
frame.runtime.device,
|
|
2123
|
+
layout,
|
|
2124
|
+
inputView.value,
|
|
2125
|
+
fullscreen.sampler,
|
|
2126
|
+
paramsBuffer,
|
|
2127
|
+
depthView ?? null,
|
|
2128
|
+
fullscreen.depthSampler,
|
|
2129
|
+
additionalViews,
|
|
2130
|
+
fullscreen.extraStorageBindings.map((binding, index) => {
|
|
2131
|
+
const names = descriptor.values.storageBuffers;
|
|
2132
|
+
const name = Array.isArray(names) ? names[index] : undefined;
|
|
2133
|
+
if (typeof name !== 'string') throw new Error('fullscreen storage buffer name missing');
|
|
2134
|
+
const buffer = input.resolveGpuResource?.(name);
|
|
2135
|
+
if (buffer === undefined) throw new Error(`fullscreen storage buffer unavailable: ${name}`);
|
|
2136
|
+
return { binding, buffer: buffer.buffer };
|
|
2137
|
+
}),
|
|
2138
|
+
);
|
|
2139
|
+
if (createdBindGroup !== null) {
|
|
2140
|
+
// Cloud history is a producer of the shared temporal ping-pong state even
|
|
2141
|
+
// when TAA is disabled. Stage the write at encode time; execute's finish
|
|
2142
|
+
// guard and submit transaction then give it the same abort/commit/fence
|
|
2143
|
+
// semantics as the TAA resolve.
|
|
2144
|
+
if (shader === 'cloud-layer-resolve') {
|
|
2145
|
+
const state = getTemporalGpuState(
|
|
2146
|
+
frame.frameState,
|
|
2147
|
+
frame.runtime.device,
|
|
2148
|
+
frame.runtime.deviceScope,
|
|
2149
|
+
frame.targetW,
|
|
2150
|
+
frame.targetH,
|
|
2151
|
+
true,
|
|
2152
|
+
);
|
|
2153
|
+
stageTemporalGpuSubmit(state);
|
|
2154
|
+
frame.frameState.temporalGpuState = state;
|
|
2155
|
+
}
|
|
2156
|
+
return createdBindGroup;
|
|
2157
|
+
}
|
|
2158
|
+
return undefined;
|
|
2159
|
+
}
|
|
1615
2160
|
if (descriptor?.values.fullscreen === true && isTemporalFullscreenBinding(descriptor.values)) {
|
|
1616
2161
|
const shader = descriptor.values.shader;
|
|
1617
2162
|
if (typeof shader !== 'string') return undefined;
|
|
@@ -1626,11 +2171,9 @@ function resolveTargetBindings(
|
|
|
1626
2171
|
);
|
|
1627
2172
|
if (fullscreen === null || fullscreen.sampler === null) return undefined;
|
|
1628
2173
|
const inputTarget = input.resolveTarget(descriptor.values.input as never);
|
|
1629
|
-
|
|
1630
|
-
if (inputTarget === undefined || temporalTarget === undefined) return undefined;
|
|
2174
|
+
if (inputTarget === undefined) return undefined;
|
|
1631
2175
|
const inputView = input.resources.textureView(inputTarget.view);
|
|
1632
|
-
|
|
1633
|
-
if (!inputView.ok || !temporalView.ok) return undefined;
|
|
2176
|
+
if (!inputView.ok) return undefined;
|
|
1634
2177
|
const layout = pipeline.getBindGroupLayout?.(1);
|
|
1635
2178
|
if (layout === undefined) return undefined;
|
|
1636
2179
|
const depth = input.resolveTarget(descriptor.values.depth as never);
|
|
@@ -1649,13 +2192,41 @@ function resolveTargetBindings(
|
|
|
1649
2192
|
if (depth !== undefined && (depthView === undefined || fullscreen.depthSampler === null)) {
|
|
1650
2193
|
return undefined;
|
|
1651
2194
|
}
|
|
2195
|
+
|
|
2196
|
+
const paramsBuffer = frame.runtime.getPostProcessParamsBuffer?.(shader);
|
|
2197
|
+
if (entry.params !== undefined && paramsBuffer === undefined) return undefined;
|
|
2198
|
+
if (entry.params !== undefined && paramsBuffer !== undefined) {
|
|
2199
|
+
const data = frame.postProcessParams.get(shader) ?? entry.params.defaultValue;
|
|
2200
|
+
if (data.byteLength !== entry.params.byteSize) return undefined;
|
|
2201
|
+
const written = frame.runtime.device.queue.writeBuffer(paramsBuffer, 0, data);
|
|
2202
|
+
if (!written.ok) return undefined;
|
|
2203
|
+
}
|
|
2204
|
+
|
|
2205
|
+
if (!isTemporalFullscreenBinding(descriptor.values)) {
|
|
2206
|
+
return (
|
|
2207
|
+
createFullscreenBindGroup(
|
|
2208
|
+
frame.runtime.device,
|
|
2209
|
+
layout,
|
|
2210
|
+
inputView.value,
|
|
2211
|
+
fullscreen.sampler,
|
|
2212
|
+
paramsBuffer,
|
|
2213
|
+
depthView ?? null,
|
|
2214
|
+
fullscreen.depthSampler,
|
|
2215
|
+
) ?? undefined
|
|
2216
|
+
);
|
|
2217
|
+
}
|
|
2218
|
+
|
|
2219
|
+
const temporalTarget = input.resolveTarget(descriptor.values.temporal as never);
|
|
2220
|
+
if (temporalTarget === undefined) return undefined;
|
|
2221
|
+
const temporalView = input.resources.textureView(temporalTarget.view);
|
|
2222
|
+
if (!temporalView.ok) return undefined;
|
|
1652
2223
|
return (
|
|
1653
2224
|
createFullscreenBindGroup(
|
|
1654
2225
|
frame.runtime.device,
|
|
1655
2226
|
layout,
|
|
1656
2227
|
inputView.value,
|
|
1657
2228
|
fullscreen.sampler,
|
|
1658
|
-
|
|
2229
|
+
paramsBuffer,
|
|
1659
2230
|
depthView ?? null,
|
|
1660
2231
|
fullscreen.depthSampler,
|
|
1661
2232
|
[{ binding: fullscreen.extraColorBindings[0] ?? 5, view: temporalView.value }],
|
|
@@ -1733,15 +2304,35 @@ function resolveTargetBindings(
|
|
|
1733
2304
|
return created.value;
|
|
1734
2305
|
}
|
|
1735
2306
|
|
|
1736
|
-
function retire(
|
|
2307
|
+
export function retire(
|
|
1737
2308
|
frameState: RenderFrameState,
|
|
1738
2309
|
graph: CompiledRenderGraph<RenderPipelineFrame>,
|
|
1739
2310
|
): void {
|
|
2311
|
+
if (frameState.retiredCompiledFrameGraphs.has(graph)) return;
|
|
1740
2312
|
frameState.retiredCompiledFrameGraphs.add(graph);
|
|
1741
|
-
graph
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
2313
|
+
setGraphGenerationRetiring(frameState, graph);
|
|
2314
|
+
const failures = graphRetirementFailureSet(frameState);
|
|
2315
|
+
const retirement = graph.retire();
|
|
2316
|
+
// retire() synchronously moves graph-owned resources to pending before its
|
|
2317
|
+
// queue-fence await. Capture that overlap at the lifecycle event, rather
|
|
2318
|
+
// than waiting for a later inspection call.
|
|
2319
|
+
observeGraphGenerationAllocation(frameState);
|
|
2320
|
+
retirement
|
|
2321
|
+
.then((result) => {
|
|
2322
|
+
if (result.ok) {
|
|
2323
|
+
failures?.delete(graph);
|
|
2324
|
+
setGraphGenerationRetirementResult(frameState, graph, true);
|
|
2325
|
+
} else {
|
|
2326
|
+
failures?.add(graph);
|
|
2327
|
+
setGraphGenerationRetirementResult(frameState, graph, false);
|
|
2328
|
+
}
|
|
2329
|
+
frameState.retiredCompiledFrameGraphs.delete(graph);
|
|
2330
|
+
})
|
|
2331
|
+
.catch(() => {
|
|
2332
|
+
failures?.add(graph);
|
|
2333
|
+
setGraphGenerationRetirementResult(frameState, graph, false);
|
|
2334
|
+
frameState.retiredCompiledFrameGraphs.delete(graph);
|
|
2335
|
+
});
|
|
1745
2336
|
}
|
|
1746
2337
|
|
|
1747
2338
|
/**
|
|
@@ -1818,6 +2409,54 @@ export function settleDepthOfFieldGraphCandidate(
|
|
|
1818
2409
|
frameState.depthOfFieldCandidateGraph = null;
|
|
1819
2410
|
}
|
|
1820
2411
|
|
|
2412
|
+
/**
|
|
2413
|
+
* Settle an ordinary graph replacement at the same submit barrier as the
|
|
2414
|
+
* barrel mapping. Resize, camera topology, and post-process enable/disable
|
|
2415
|
+
* all replace the compiled graph; a failed command must restore that graph so
|
|
2416
|
+
* the retained mapping still describes the pixels that are actually shown.
|
|
2417
|
+
*/
|
|
2418
|
+
export function settleBarrelDistortionGraphCandidate(
|
|
2419
|
+
frameState: RenderFrameState,
|
|
2420
|
+
submitted: boolean,
|
|
2421
|
+
): void {
|
|
2422
|
+
const candidate = frameState.barrelDistortionCandidateGraph ?? null;
|
|
2423
|
+
if (candidate === null) return;
|
|
2424
|
+
const previous = frameState.barrelDistortionPreviousGraph ?? null;
|
|
2425
|
+
const sharedWithSpecializedOwner =
|
|
2426
|
+
frameState.depthOfFieldCandidateGraph === candidate ||
|
|
2427
|
+
frameState.volumetricFogCandidateGraph === candidate;
|
|
2428
|
+
if (submitted) {
|
|
2429
|
+
if (!sharedWithSpecializedOwner && previous !== null && previous !== candidate) {
|
|
2430
|
+
retire(frameState, previous);
|
|
2431
|
+
}
|
|
2432
|
+
} else {
|
|
2433
|
+
if (!sharedWithSpecializedOwner) {
|
|
2434
|
+
if (candidate !== previous) retire(frameState, candidate);
|
|
2435
|
+
frameState.compiledFrameGraph = previous;
|
|
2436
|
+
frameState.compiledFrameGraphTopologyKey =
|
|
2437
|
+
frameState.barrelDistortionPreviousGraphKey ?? null;
|
|
2438
|
+
if (frameState.barrelDistortionPreviousPerFrameGraph === undefined) {
|
|
2439
|
+
delete frameState.perFrameGraph;
|
|
2440
|
+
} else {
|
|
2441
|
+
frameState.perFrameGraph = frameState.barrelDistortionPreviousPerFrameGraph;
|
|
2442
|
+
}
|
|
2443
|
+
frameState.graphGeneration = frameState.barrelDistortionPreviousGraphGeneration ?? 0;
|
|
2444
|
+
frameState.compiledFrameGraphGeneration =
|
|
2445
|
+
frameState.barrelDistortionPreviousCompiledGraphGeneration ?? 0;
|
|
2446
|
+
frameState.standardLightingGraphSignature =
|
|
2447
|
+
frameState.barrelDistortionPreviousStandardLightingGraphSignature ?? '';
|
|
2448
|
+
}
|
|
2449
|
+
frameState.barrelDistortionGraphResolution = previous === null ? 'accepted' : 'retained';
|
|
2450
|
+
}
|
|
2451
|
+
frameState.barrelDistortionPreviousGraph = null;
|
|
2452
|
+
frameState.barrelDistortionPreviousGraphKey = null;
|
|
2453
|
+
frameState.barrelDistortionPreviousPerFrameGraph = undefined;
|
|
2454
|
+
frameState.barrelDistortionPreviousGraphGeneration = 0;
|
|
2455
|
+
frameState.barrelDistortionPreviousCompiledGraphGeneration = 0;
|
|
2456
|
+
frameState.barrelDistortionPreviousStandardLightingGraphSignature = '';
|
|
2457
|
+
frameState.barrelDistortionCandidateGraph = null;
|
|
2458
|
+
}
|
|
2459
|
+
|
|
1821
2460
|
export function ensureCompiledFrameGraph(
|
|
1822
2461
|
internals: RenderSystemInternals,
|
|
1823
2462
|
frameState: RenderFrameState,
|
|
@@ -1839,7 +2478,11 @@ export function ensureCompiledFrameGraph(
|
|
|
1839
2478
|
onRecoveryError?: (error: unknown) => void,
|
|
1840
2479
|
ssr?: SsrSpatialAdmission,
|
|
1841
2480
|
renderExtent?: RenderExtent,
|
|
2481
|
+
surfaceMediumActive?: boolean,
|
|
2482
|
+
analyticFog = false,
|
|
2483
|
+
cloudShadowResolution?: number,
|
|
1842
2484
|
): CompiledRenderGraph<RenderPipelineFrame> | null {
|
|
2485
|
+
frameState.barrelDistortionGraphResolution = 'retained';
|
|
1843
2486
|
const featureMetrics = mutableFeatureGraphInspection(internals);
|
|
1844
2487
|
featureMetrics.ensureCalls += 1;
|
|
1845
2488
|
const requestedStandardLightingSignature = standardLightingTopologySignature(standardLighting);
|
|
@@ -1857,10 +2500,16 @@ export function ensureCompiledFrameGraph(
|
|
|
1857
2500
|
: { ...camera, depthOfField: frameDepthOfField };
|
|
1858
2501
|
const lastKnownGood = (): CompiledRenderGraph<RenderPipelineFrame> | null =>
|
|
1859
2502
|
frameState.compiledFrameGraph !== null &&
|
|
2503
|
+
frameState.compiledFrameGraphTopologyKey !== null &&
|
|
1860
2504
|
!hasSubmissionSensitiveFeatures(getRenderFeatureGraphState(internals).plans) &&
|
|
1861
2505
|
frameState.standardLightingGraphSignature === requestedStandardLightingSignature
|
|
1862
2506
|
? frameState.compiledFrameGraph
|
|
1863
2507
|
: null;
|
|
2508
|
+
const retainLastKnownGood = (): CompiledRenderGraph<RenderPipelineFrame> | null => {
|
|
2509
|
+
const graph = lastKnownGood();
|
|
2510
|
+
if (graph !== null) frameState.barrelDistortionGraphResolution = 'retained';
|
|
2511
|
+
return graph;
|
|
2512
|
+
};
|
|
1864
2513
|
const surfaceWidth = Math.max(1, width);
|
|
1865
2514
|
const surfaceHeight = Math.max(1, height);
|
|
1866
2515
|
const featurePlans = featureGraphCandidate?.plans ?? getRenderFeatureGraphState(internals).plans;
|
|
@@ -1872,8 +2521,15 @@ export function ensureCompiledFrameGraph(
|
|
|
1872
2521
|
if (featureGraphCandidate !== undefined) {
|
|
1873
2522
|
recordRenderFeatureCandidateEvent(internals, featureGraphCandidate, 'rejected');
|
|
1874
2523
|
}
|
|
1875
|
-
return volumeTopologyCandidate ? null :
|
|
2524
|
+
return volumeTopologyCandidate ? null : retainLastKnownGood();
|
|
1876
2525
|
}
|
|
2526
|
+
const cloudHistoryDemand = projectedFeaturePlans.value.some(
|
|
2527
|
+
(execution) =>
|
|
2528
|
+
execution.featureIdentity === CLOUD_LAYER_FEATURE_IDENTITY &&
|
|
2529
|
+
execution.passes.some(
|
|
2530
|
+
(pass) => pass.name === 'cloud-layer-transport' || pass.name === 'cloud-layer-resolve',
|
|
2531
|
+
),
|
|
2532
|
+
);
|
|
1877
2533
|
const nextPlanRevision = updateRenderFeaturePlanRevision(
|
|
1878
2534
|
featureMetrics.planRevisionState,
|
|
1879
2535
|
featurePlans,
|
|
@@ -1904,6 +2560,8 @@ export function ensureCompiledFrameGraph(
|
|
|
1904
2560
|
standardLighting,
|
|
1905
2561
|
ssr,
|
|
1906
2562
|
renderExtent,
|
|
2563
|
+
surfaceMediumActive,
|
|
2564
|
+
analyticFog,
|
|
1907
2565
|
);
|
|
1908
2566
|
if (!topologyResult.ok) {
|
|
1909
2567
|
featureMetrics.buildFailures += 1;
|
|
@@ -1912,12 +2570,22 @@ export function ensureCompiledFrameGraph(
|
|
|
1912
2570
|
if (featureGraphCandidate !== undefined) {
|
|
1913
2571
|
recordRenderFeatureCandidateEvent(internals, featureGraphCandidate, 'rejected');
|
|
1914
2572
|
}
|
|
1915
|
-
return volumeTopologyCandidate ? null :
|
|
2573
|
+
return volumeTopologyCandidate ? null : retainLastKnownGood();
|
|
1916
2574
|
}
|
|
1917
2575
|
const requestedPostEffects = topologyResult.value.config?.postEffects ?? [];
|
|
1918
2576
|
const featurePostProcessEntries =
|
|
1919
2577
|
featureGraphCandidate?.fullscreenEffects ??
|
|
1920
2578
|
getRenderFeatureGraphState(internals).fullscreenEffects;
|
|
2579
|
+
// Motion Blur's compute plan intentionally has no raster fullscreen shader
|
|
2580
|
+
// declaration, but it is still a post chain consumer: Standard Post owns
|
|
2581
|
+
// the named `motion-input`/`motion-output` targets and must project it after
|
|
2582
|
+
// TAA. Keep the identity in this deferred set alongside declared fullscreen
|
|
2583
|
+
// effects so an early forward/deferred contribution cannot resolve its
|
|
2584
|
+
// scene-data target against an incomplete target map.
|
|
2585
|
+
const fullscreenFeatureIds = new Set([
|
|
2586
|
+
...featurePostProcessEntries.keys(),
|
|
2587
|
+
'forgeax.motion-blur',
|
|
2588
|
+
]);
|
|
1921
2589
|
const postProcessAdmission = resolvePostProcessChainAdmission(
|
|
1922
2590
|
requestedPostEffects,
|
|
1923
2591
|
(identity) => {
|
|
@@ -1954,6 +2622,7 @@ export function ensureCompiledFrameGraph(
|
|
|
1954
2622
|
if (featureGraphCandidate !== undefined) {
|
|
1955
2623
|
recordRenderFeatureCandidateEvent(internals, featureGraphCandidate, 'rejected');
|
|
1956
2624
|
}
|
|
2625
|
+
frameState.barrelDistortionGraphResolution = 'retained';
|
|
1957
2626
|
return acceptedLkg;
|
|
1958
2627
|
}
|
|
1959
2628
|
const topology = postProcessAdmission.pending
|
|
@@ -1965,8 +2634,19 @@ export function ensureCompiledFrameGraph(
|
|
|
1965
2634
|
},
|
|
1966
2635
|
}
|
|
1967
2636
|
: topologyResult.value;
|
|
2637
|
+
// Keep Bloom's positive parameter values out of the compiled identity. A
|
|
2638
|
+
// crossing of zero has already changed topology.camera.bloom above; the
|
|
2639
|
+
// remaining values are uploaded by the active recorder without rebuilding
|
|
2640
|
+
// targets or pipelines.
|
|
2641
|
+
const topologyIdentity = {
|
|
2642
|
+
...topology,
|
|
2643
|
+
camera: {
|
|
2644
|
+
...topology.camera,
|
|
2645
|
+
bloomIntensity: undefined,
|
|
2646
|
+
},
|
|
2647
|
+
};
|
|
1968
2648
|
const key = JSON.stringify({
|
|
1969
|
-
topology,
|
|
2649
|
+
topology: topologyIdentity,
|
|
1970
2650
|
// Observation domains are an explicit per-frame graph demand. They are
|
|
1971
2651
|
// part of the cache identity so a request made after the ordinary graph
|
|
1972
2652
|
// was compiled can admit the matching tone/output capture boundaries on
|
|
@@ -1979,6 +2659,11 @@ export function ensureCompiledFrameGraph(
|
|
|
1979
2659
|
// so include the prepared projection's presence to invalidate a cached
|
|
1980
2660
|
// CPU-only graph when the GPU owner becomes ready, and vice versa.
|
|
1981
2661
|
gpuDrivenProjectionActive: gpuDriven !== undefined,
|
|
2662
|
+
// Cloud shadow targets are quality-derived graph resources. Include the
|
|
2663
|
+
// resolved texel grid in the cache key so a quality/resize change cannot
|
|
2664
|
+
// reuse a graph compiled for the previous allocation.
|
|
2665
|
+
cloudShadowResolution: cloudShadowResolution ?? 0,
|
|
2666
|
+
cloudHistory: cloudHistoryDemand,
|
|
1982
2667
|
// Query reservations are frame-local transport state. The projection is
|
|
1983
2668
|
// renderer-owned and read dynamically by the compiled pass, so a page
|
|
1984
2669
|
// rotation must not invalidate the graph or its cached bind groups.
|
|
@@ -1993,9 +2678,11 @@ export function ensureCompiledFrameGraph(
|
|
|
1993
2678
|
]),
|
|
1994
2679
|
});
|
|
1995
2680
|
if (frameState.compiledFrameGraph !== null && frameState.compiledFrameGraphTopologyKey === key) {
|
|
2681
|
+
frameState.barrelDistortionGraphResolution = 'accepted';
|
|
1996
2682
|
featureMetrics.reuseHits += 1;
|
|
1997
2683
|
featureMetrics.lastTopologyKey = key;
|
|
1998
2684
|
frameState.standardLightingGraphSignature = requestedStandardLightingSignature;
|
|
2685
|
+
frameState.pendingCloudHistoryActive = cloudHistoryDemand;
|
|
1999
2686
|
if (featureGraphCandidate !== undefined && !postProcessAdmission.pending) {
|
|
2000
2687
|
commitFeatureCandidate(internals, featureGraphCandidate);
|
|
2001
2688
|
} else if (featureGraphCandidate !== undefined) {
|
|
@@ -2025,9 +2712,11 @@ export function ensureCompiledFrameGraph(
|
|
|
2025
2712
|
topology.output?.autoExposure === true ? importAutoExposureGraphResources(builder) : undefined;
|
|
2026
2713
|
if (autoExposureResources !== undefined && !autoExposureResources.ok) {
|
|
2027
2714
|
internals.errorRegistry.fire(autoExposureResources.error);
|
|
2028
|
-
featureGraphCandidate?.onRejected?.();
|
|
2029
2715
|
discardPendingStandardOutput();
|
|
2030
|
-
|
|
2716
|
+
if (featureGraphCandidate !== undefined) {
|
|
2717
|
+
recordRenderFeatureCandidateEvent(internals, featureGraphCandidate, 'rejected');
|
|
2718
|
+
}
|
|
2719
|
+
return retainLastKnownGood();
|
|
2031
2720
|
}
|
|
2032
2721
|
const lutResources =
|
|
2033
2722
|
topology.output?.colorLut === true
|
|
@@ -2071,23 +2760,27 @@ export function ensureCompiledFrameGraph(
|
|
|
2071
2760
|
: undefined;
|
|
2072
2761
|
if (lutResources !== undefined && !lutResources.ok) {
|
|
2073
2762
|
internals.errorRegistry.fire(lutResources.error);
|
|
2074
|
-
featureGraphCandidate?.onRejected?.();
|
|
2075
2763
|
discardPendingStandardOutput();
|
|
2076
|
-
|
|
2764
|
+
if (featureGraphCandidate !== undefined) {
|
|
2765
|
+
recordRenderFeatureCandidateEvent(internals, featureGraphCandidate, 'rejected');
|
|
2766
|
+
}
|
|
2767
|
+
return retainLastKnownGood();
|
|
2077
2768
|
}
|
|
2078
2769
|
const taaHistory = camera.antialias === 'taa' ? importTemporalHistoryTargets(builder) : undefined;
|
|
2770
|
+
const cloudHistory = cloudHistoryDemand ? importCloudHistoryTargets(builder) : undefined;
|
|
2079
2771
|
const targetCoverage =
|
|
2080
2772
|
camera.dynamicResolution === undefined || topology.extent === undefined
|
|
2081
2773
|
? undefined
|
|
2082
2774
|
: createTargetCoverageAttachment(builder, topology.extent);
|
|
2083
2775
|
if (targetCoverage !== undefined && !targetCoverage.ok) {
|
|
2084
2776
|
internals.errorRegistry.fire(targetCoverage.error);
|
|
2085
|
-
featureGraphCandidate?.onRejected?.();
|
|
2086
2777
|
discardPendingStandardOutput();
|
|
2087
|
-
|
|
2778
|
+
if (featureGraphCandidate !== undefined) {
|
|
2779
|
+
recordRenderFeatureCandidateEvent(internals, featureGraphCandidate, 'rejected');
|
|
2780
|
+
}
|
|
2781
|
+
return retainLastKnownGood();
|
|
2088
2782
|
}
|
|
2089
2783
|
const ssrHistory = ssr?.status === 'admitted' ? importSsrHistoryTargets(builder) : undefined;
|
|
2090
|
-
let projectedFeatures = false;
|
|
2091
2784
|
const featureProjection = createRenderFeatureProjectionState();
|
|
2092
2785
|
let featureShadows:
|
|
2093
2786
|
| ReturnType<typeof projectRenderFeatureShadows<RenderPipelineFrame>>
|
|
@@ -2119,8 +2812,10 @@ export function ensureCompiledFrameGraph(
|
|
|
2119
2812
|
: {}),
|
|
2120
2813
|
...(standardLighting === undefined ? {} : { standardLighting }),
|
|
2121
2814
|
capabilities: { rgba16floatRenderable: internals.device.caps.rgba16floatRenderable },
|
|
2815
|
+
...(cloudShadowResolution === undefined ? {} : { cloudShadowResolution }),
|
|
2122
2816
|
...(occlusion === undefined ? {} : { occlusion }),
|
|
2123
2817
|
...(taaHistory === undefined ? {} : { taaHistory }),
|
|
2818
|
+
...(cloudHistory === undefined ? {} : { cloudHistory }),
|
|
2124
2819
|
...(targetCoverage?.ok === true ? { targetCoverage: targetCoverage.value } : {}),
|
|
2125
2820
|
...(ssrHistory === undefined ? {} : { ssrHistory }),
|
|
2126
2821
|
encodeTransmissionMip: ({ pass, resources, source }) => {
|
|
@@ -2136,6 +2831,7 @@ export function ensureCompiledFrameGraph(
|
|
|
2136
2831
|
builder,
|
|
2137
2832
|
target.format,
|
|
2138
2833
|
target.sampleCount,
|
|
2834
|
+
() => frameState.surfaceSubmissionObservation,
|
|
2139
2835
|
target.additionalColorFormats,
|
|
2140
2836
|
);
|
|
2141
2837
|
},
|
|
@@ -2156,14 +2852,42 @@ export function ensureCompiledFrameGraph(
|
|
|
2156
2852
|
semanticTargets = [],
|
|
2157
2853
|
namedTargets = {},
|
|
2158
2854
|
standardSurfaceAccesses = [],
|
|
2855
|
+
featureSelectionOrPlacement,
|
|
2856
|
+
passNames = [],
|
|
2159
2857
|
) => {
|
|
2160
|
-
|
|
2161
|
-
|
|
2162
|
-
|
|
2858
|
+
const selection =
|
|
2859
|
+
featureSelectionOrPlacement !== undefined &&
|
|
2860
|
+
typeof featureSelectionOrPlacement !== 'string'
|
|
2861
|
+
? featureSelectionOrPlacement
|
|
2862
|
+
: undefined;
|
|
2863
|
+
const placement =
|
|
2864
|
+
typeof featureSelectionOrPlacement === 'string' ? featureSelectionOrPlacement : 'post';
|
|
2865
|
+
const include = selection?.include === undefined ? undefined : new Set(selection.include);
|
|
2866
|
+
const exclude = selection?.exclude === undefined ? undefined : new Set(selection.exclude);
|
|
2867
|
+
// Forward/deferred scene lanes contribute scene plans before the
|
|
2868
|
+
// Standard post chain has created its named input/output targets.
|
|
2869
|
+
// Fullscreen effects (Motion Blur included) must wait for that later
|
|
2870
|
+
// call so their temporal input is resolved after TAA. The shared
|
|
2871
|
+
// projection state below deduplicates only the execution/pass that
|
|
2872
|
+
// actually reached the graph; an empty early projection therefore
|
|
2873
|
+
// cannot reserve the later fullscreen pass.
|
|
2874
|
+
const plans = (
|
|
2875
|
+
Object.keys(namedTargets).length === 0
|
|
2876
|
+
? projectedFeaturePlans.value.filter(
|
|
2877
|
+
(execution) => !fullscreenFeatureIds.has(execution.featureIdentity),
|
|
2878
|
+
)
|
|
2879
|
+
: projectedFeaturePlans.value
|
|
2880
|
+
)
|
|
2881
|
+
.filter((execution) => (execution.placement ?? 'post') === placement)
|
|
2882
|
+
.filter((execution) => include === undefined || include.has(execution.featureIdentity))
|
|
2883
|
+
.filter((execution) => exclude === undefined || !exclude.has(execution.featureIdentity));
|
|
2884
|
+
if (plans.length === 0) return ok(undefined);
|
|
2163
2885
|
const resolveTarget = targetResolver(targets, semanticTargets, namedTargets);
|
|
2164
|
-
const projected = projectPlanExecutions(builder,
|
|
2886
|
+
const projected = projectPlanExecutions(builder, plans, {
|
|
2165
2887
|
state: featureProjection,
|
|
2166
2888
|
resolveTarget,
|
|
2889
|
+
placement,
|
|
2890
|
+
...(passNames.length === 0 ? {} : { passNames: new Set(passNames) }),
|
|
2167
2891
|
standardSurfaceAccesses,
|
|
2168
2892
|
resolveBindings: (input) => resolveTargetBindings(input, featurePostProcessEntries),
|
|
2169
2893
|
resolveStandardLighting: (frame, pipeline) => {
|
|
@@ -2188,7 +2912,8 @@ export function ensureCompiledFrameGraph(
|
|
|
2188
2912
|
},
|
|
2189
2913
|
reportError: (error) => reportRenderFeatureGraphError(internals, error),
|
|
2190
2914
|
});
|
|
2191
|
-
|
|
2915
|
+
if (!projected.ok) return projected;
|
|
2916
|
+
return ok(undefined);
|
|
2192
2917
|
},
|
|
2193
2918
|
contributeCubeCaptures: (environmentCube) => {
|
|
2194
2919
|
const reflectionProbes = addReflectionProbeGraphPasses(
|
|
@@ -2203,6 +2928,20 @@ export function ensureCompiledFrameGraph(
|
|
|
2203
2928
|
},
|
|
2204
2929
|
hasFeature: (identity) =>
|
|
2205
2930
|
projectedFeaturePlans.value.some((execution) => execution.featureIdentity === identity),
|
|
2931
|
+
hasFeatureWork: (identity, placement) =>
|
|
2932
|
+
projectedFeaturePlans.value.some(
|
|
2933
|
+
(execution) =>
|
|
2934
|
+
execution.featureIdentity === identity &&
|
|
2935
|
+
execution.passes.length > 0 &&
|
|
2936
|
+
(placement === undefined || (execution.placement ?? 'post') === placement),
|
|
2937
|
+
),
|
|
2938
|
+
hasFeatureRasterWork: (identity, placement) =>
|
|
2939
|
+
projectedFeaturePlans.value.some(
|
|
2940
|
+
(execution) =>
|
|
2941
|
+
execution.featureIdentity === identity &&
|
|
2942
|
+
execution.passes.some((pass) => pass.graphics !== undefined) &&
|
|
2943
|
+
(placement === undefined || (execution.placement ?? 'post') === placement),
|
|
2944
|
+
),
|
|
2206
2945
|
},
|
|
2207
2946
|
topology,
|
|
2208
2947
|
);
|
|
@@ -2210,12 +2949,11 @@ export function ensureCompiledFrameGraph(
|
|
|
2210
2949
|
featureMetrics.buildFailures += 1;
|
|
2211
2950
|
onRecoveryError?.(built.error);
|
|
2212
2951
|
internals.errorRegistry.fire(built.error);
|
|
2213
|
-
featureGraphCandidate?.onRejected?.();
|
|
2214
2952
|
discardPendingStandardOutput();
|
|
2215
2953
|
if (featureGraphCandidate !== undefined) {
|
|
2216
2954
|
recordRenderFeatureCandidateEvent(internals, featureGraphCandidate, 'rejected');
|
|
2217
2955
|
}
|
|
2218
|
-
return volumeTopologyCandidate ? null :
|
|
2956
|
+
return volumeTopologyCandidate ? null : retainLastKnownGood();
|
|
2219
2957
|
}
|
|
2220
2958
|
featureMetrics.compileAttempts += 1;
|
|
2221
2959
|
const compileStarted = typeof performance === 'undefined' ? Date.now() : performance.now();
|
|
@@ -2229,13 +2967,16 @@ export function ensureCompiledFrameGraph(
|
|
|
2229
2967
|
featureMetrics.compileFailures += 1;
|
|
2230
2968
|
onRecoveryError?.(compiled.error);
|
|
2231
2969
|
internals.errorRegistry.fire(compiled.error);
|
|
2232
|
-
featureGraphCandidate?.onRejected?.();
|
|
2233
2970
|
discardPendingStandardOutput();
|
|
2234
2971
|
if (featureGraphCandidate !== undefined) {
|
|
2235
2972
|
recordRenderFeatureCandidateEvent(internals, featureGraphCandidate, 'rejected');
|
|
2236
2973
|
}
|
|
2237
|
-
return
|
|
2974
|
+
return retainLastKnownGood();
|
|
2238
2975
|
}
|
|
2976
|
+
// Register the generation before publishing it. The owner observes the
|
|
2977
|
+
// overlap while the previous graph is still live, even if a queue fence
|
|
2978
|
+
// retires that graph before the next public inspect() call.
|
|
2979
|
+
trackGraphGeneration(frameState, compiled.value);
|
|
2239
2980
|
const previous = frameState.compiledFrameGraph;
|
|
2240
2981
|
const depthOfFieldReplacement =
|
|
2241
2982
|
(frameState.depthOfFieldCandidateGraph === null ||
|
|
@@ -2263,8 +3004,22 @@ export function ensureCompiledFrameGraph(
|
|
|
2263
3004
|
frameState.depthOfFieldPreviousStandardLightingGraphSignature =
|
|
2264
3005
|
frameState.standardLightingGraphSignature;
|
|
2265
3006
|
frameState.depthOfFieldCandidateGraph = compiled.value;
|
|
3007
|
+
} else if (compiled.value !== previous) {
|
|
3008
|
+
// Keep the complete accepted graph projection until queue submission.
|
|
3009
|
+
// This covers barrel enable/disable, output resize, and camera topology
|
|
3010
|
+
// changes without introducing a second resource owner.
|
|
3011
|
+
frameState.barrelDistortionPreviousGraph = previous;
|
|
3012
|
+
frameState.barrelDistortionPreviousGraphKey = frameState.compiledFrameGraphTopologyKey;
|
|
3013
|
+
frameState.barrelDistortionPreviousPerFrameGraph = frameState.perFrameGraph;
|
|
3014
|
+
frameState.barrelDistortionPreviousGraphGeneration = frameState.graphGeneration;
|
|
3015
|
+
frameState.barrelDistortionPreviousCompiledGraphGeneration =
|
|
3016
|
+
frameState.compiledFrameGraphGeneration;
|
|
3017
|
+
frameState.barrelDistortionPreviousStandardLightingGraphSignature =
|
|
3018
|
+
frameState.standardLightingGraphSignature;
|
|
3019
|
+
frameState.barrelDistortionCandidateGraph = compiled.value;
|
|
2266
3020
|
}
|
|
2267
3021
|
frameState.compiledFrameGraph = compiled.value;
|
|
3022
|
+
frameState.barrelDistortionGraphResolution = 'accepted';
|
|
2268
3023
|
frameState.compiledFrameGraphTopologyKey = key;
|
|
2269
3024
|
frameState.standardLightingGraphSignature = requestedStandardLightingSignature;
|
|
2270
3025
|
frameState.compiledFrameGraphGeneration += 1;
|
|
@@ -2296,9 +3051,8 @@ export function ensureCompiledFrameGraph(
|
|
|
2296
3051
|
} else if (featureGraphCandidate !== undefined) {
|
|
2297
3052
|
recordRenderFeatureCandidateEvent(internals, featureGraphCandidate, 'abandoned');
|
|
2298
3053
|
}
|
|
2299
|
-
|
|
2300
|
-
|
|
2301
|
-
}
|
|
3054
|
+
frameState.pendingCloudHistoryActive = cloudHistoryDemand;
|
|
3055
|
+
// The selected candidate owner retires the previous graph only after submit.
|
|
2302
3056
|
return compiled.value;
|
|
2303
3057
|
}
|
|
2304
3058
|
|
|
@@ -2324,20 +3078,31 @@ export function executeCompiledFrameGraph(
|
|
|
2324
3078
|
const legacySubmitCommit = typeof frameHooks === 'function' ? frameHooks : undefined;
|
|
2325
3079
|
const resolvedFrameHooks = typeof frameHooks === 'function' ? undefined : frameHooks;
|
|
2326
3080
|
const graph = frameState.compiledFrameGraph;
|
|
3081
|
+
// Recovery keeps the candidate graph for detached inspection, but clears
|
|
3082
|
+
// its topology key before the replacement canvas context is published. It
|
|
3083
|
+
// is evidence only until the first post-recovery draw compiles a new graph.
|
|
3084
|
+
// Never let that retained graph reach record/execute or queue.submit.
|
|
3085
|
+
const detachedGraph = graph !== null && frameState.compiledFrameGraphTopologyKey === null;
|
|
2327
3086
|
const rejectTemporalFrame = (): void => {
|
|
2328
3087
|
if (frameState.temporalFrameInput === undefined) return;
|
|
2329
3088
|
frameState.temporalFrameTransaction.commit({ accepted: false });
|
|
2330
3089
|
frameState.temporalFrameInput = undefined;
|
|
2331
3090
|
};
|
|
2332
|
-
if (graph === null) {
|
|
3091
|
+
if (graph === null || detachedGraph) {
|
|
2333
3092
|
timingCapture?.discard();
|
|
2334
3093
|
frameState.pendingAutoExposureState = undefined;
|
|
2335
3094
|
frameState.pendingStandardLutState = undefined;
|
|
3095
|
+
settleBarrelDistortionGraphCandidate(frameState, false);
|
|
2336
3096
|
settleVolumetricFogGraphCandidate(frameState, false);
|
|
2337
3097
|
settleDepthOfFieldGraphCandidate(frameState, false);
|
|
2338
3098
|
rejectTemporalFrame();
|
|
2339
3099
|
return false;
|
|
2340
3100
|
}
|
|
3101
|
+
const motionBlurExecution = deriveMotionBlurExecutionReceipt(
|
|
3102
|
+
internals,
|
|
3103
|
+
frameState,
|
|
3104
|
+
getRenderFeatureGraphState(internals).plans,
|
|
3105
|
+
);
|
|
2341
3106
|
const legacyTimingInstrumentation =
|
|
2342
3107
|
timingCapture === undefined ? undefined : createTimingInstrumentation(timingCapture);
|
|
2343
3108
|
const timingHost = internals as RenderSystemInternals & {
|
|
@@ -2400,6 +3165,7 @@ export function executeCompiledFrameGraph(
|
|
|
2400
3165
|
);
|
|
2401
3166
|
settleVolumetricFogGraphCandidate(frameState, false);
|
|
2402
3167
|
settleDepthOfFieldGraphCandidate(frameState, false);
|
|
3168
|
+
settleBarrelDistortionGraphCandidate(frameState, false);
|
|
2403
3169
|
return false;
|
|
2404
3170
|
}
|
|
2405
3171
|
const capturedGeneration = deviceScope?.generation;
|
|
@@ -2903,8 +3669,8 @@ export function executeCompiledFrameGraph(
|
|
|
2903
3669
|
internals.errorRegistry.fire(
|
|
2904
3670
|
new RhiError({
|
|
2905
3671
|
code: 'webgpu-runtime-error',
|
|
2906
|
-
expected: '
|
|
2907
|
-
hint: 'retry the frame after the
|
|
3672
|
+
expected: 'an admitted temporal producer stages a history write before submit',
|
|
3673
|
+
hint: 'retry the frame after the TAA or CloudLayer history pass has encoded successfully',
|
|
2908
3674
|
}),
|
|
2909
3675
|
);
|
|
2910
3676
|
return { ok: false, stage: 'finish' };
|
|
@@ -2960,6 +3726,11 @@ export function executeCompiledFrameGraph(
|
|
|
2960
3726
|
commit: () => {
|
|
2961
3727
|
resolvedFrameHooks?.onSubmitted?.();
|
|
2962
3728
|
legacySubmitCommit?.();
|
|
3729
|
+
if (motionBlurExecution === undefined) {
|
|
3730
|
+
delete frameState.motionBlurExecution;
|
|
3731
|
+
} else {
|
|
3732
|
+
frameState.motionBlurExecution = motionBlurExecution;
|
|
3733
|
+
}
|
|
2963
3734
|
if (frameState.temporalFrameInput !== undefined) {
|
|
2964
3735
|
const temporal = frameState.temporalFrameTransaction.commit({ accepted: true });
|
|
2965
3736
|
if (temporal.ok) {
|
|
@@ -3053,6 +3824,11 @@ export function executeCompiledFrameGraph(
|
|
|
3053
3824
|
}
|
|
3054
3825
|
}
|
|
3055
3826
|
const stagedTemporalCommit = frameState.pendingTemporalCommit ?? { kind: 'none' as const };
|
|
3827
|
+
const stagedCloudHistoryActive = frameState.pendingCloudHistoryActive;
|
|
3828
|
+
if (stagedCloudHistoryActive !== undefined) {
|
|
3829
|
+
frameState.cloudHistoryActive = stagedCloudHistoryActive;
|
|
3830
|
+
delete frameState.pendingCloudHistoryActive;
|
|
3831
|
+
}
|
|
3056
3832
|
if (stagedTemporalCommit.kind !== 'none') {
|
|
3057
3833
|
frameState.lastSuccessfulTemporalView = stagedTemporalCommit.view;
|
|
3058
3834
|
}
|
|
@@ -3061,7 +3837,7 @@ export function executeCompiledFrameGraph(
|
|
|
3061
3837
|
} else if (stagedTemporalCommit.kind === 'off') {
|
|
3062
3838
|
frameState.successfulTemporalFrameIndex = 0;
|
|
3063
3839
|
}
|
|
3064
|
-
if (stagedTemporalCommit.kind === 'off') {
|
|
3840
|
+
if (stagedTemporalCommit.kind === 'off' && frameState.cloudHistoryActive !== true) {
|
|
3065
3841
|
internals.clearPostProcessPipelineCache?.('forgeax.taa-resolve');
|
|
3066
3842
|
// Retire frame-sized resources, not the device-owned prewarmed
|
|
3067
3843
|
// shader. The next TAA frame must not start an async cold compile.
|
|
@@ -3092,6 +3868,7 @@ export function executeCompiledFrameGraph(
|
|
|
3092
3868
|
frameState.pendingAtmospherePublish?.();
|
|
3093
3869
|
frameState.pendingAtmospherePublish = undefined;
|
|
3094
3870
|
onSubmitted?.(internals.device.queue.onSubmittedWorkDone());
|
|
3871
|
+
settleBarrelDistortionGraphCandidate(frameState, true);
|
|
3095
3872
|
settleVolumetricFogGraphCandidate(frameState, true);
|
|
3096
3873
|
settleDepthOfFieldGraphCandidate(frameState, true);
|
|
3097
3874
|
},
|
|
@@ -3127,11 +3904,13 @@ export function executeCompiledFrameGraph(
|
|
|
3127
3904
|
}
|
|
3128
3905
|
frameState.temporalGpuState = undefined;
|
|
3129
3906
|
}
|
|
3907
|
+
delete frameState.pendingCloudHistoryActive;
|
|
3130
3908
|
frameState.pendingTemporalCommit = { kind: 'none' };
|
|
3131
3909
|
if (frameState.environmentGeneration !== undefined) {
|
|
3132
3910
|
frameState.environmentLifecycle?.discard(frameState.environmentGeneration);
|
|
3133
3911
|
frameState.environmentGeneration = undefined;
|
|
3134
3912
|
}
|
|
3913
|
+
settleBarrelDistortionGraphCandidate(frameState, false);
|
|
3135
3914
|
settleVolumetricFogGraphCandidate(frameState, false);
|
|
3136
3915
|
settleDepthOfFieldGraphCandidate(frameState, false);
|
|
3137
3916
|
},
|
|
@@ -3139,6 +3918,7 @@ export function executeCompiledFrameGraph(
|
|
|
3139
3918
|
// The callbacks above settle the normal transaction path. Keep this guard
|
|
3140
3919
|
// for synthetic callers and any future early transaction result that does
|
|
3141
3920
|
// not enter a callback.
|
|
3921
|
+
settleBarrelDistortionGraphCandidate(frameState, transaction.ok);
|
|
3142
3922
|
settleVolumetricFogGraphCandidate(frameState, transaction.ok);
|
|
3143
3923
|
settleDepthOfFieldGraphCandidate(frameState, transaction.ok);
|
|
3144
3924
|
if (!transaction.ok) rejectTemporalFrame();
|