@forgeax/engine-render 0.1.33 → 0.1.35
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 +1062 -127
- 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/device-feature-admission.d.ts +2 -2
- 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/host-contract.d.ts +6 -5
- package/dist/assembly/host-contract.d.ts.map +1 -1
- 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/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/render-target-host.d.ts +5 -0
- package/dist/assembly/render-target-host.d.ts.map +1 -1
- 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/webgpu-pbr-ready.d.ts +1 -0
- package/dist/assembly/webgpu-pbr-ready.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 +1 -1
- 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 +2 -1
- package/dist/assembly/webgpu-renderer.d.ts.map +1 -1
- package/dist/authoring.mjs +2 -4
- package/dist/authoring.mjs.map +1 -1
- package/dist/barrel-distortion.d.ts +47 -0
- package/dist/barrel-distortion.d.ts.map +1 -0
- package/dist/chunk-3XUBWRY2.mjs +1842 -0
- package/dist/chunk-3XUBWRY2.mjs.map +1 -0
- package/dist/{chunk-OO3DRYK7.mjs → chunk-G6HDNGY7.mjs} +2400 -1767
- package/dist/chunk-G6HDNGY7.mjs.map +1 -0
- package/dist/{chunk-ZDQWGQW7.mjs → chunk-LM5IE7GF.mjs} +4 -4
- package/dist/{chunk-ZDQWGQW7.mjs.map → chunk-LM5IE7GF.mjs.map} +1 -1
- package/dist/{chunk-VOZWDM3L.mjs → chunk-LNIUIKQ7.mjs} +1514 -498
- package/dist/chunk-LNIUIKQ7.mjs.map +1 -0
- package/dist/chunk-MXTWKZO4.mjs +3268 -0
- package/dist/chunk-MXTWKZO4.mjs.map +1 -0
- package/dist/chunk-MZ4C7EHF.mjs +6942 -0
- package/dist/chunk-MZ4C7EHF.mjs.map +1 -0
- package/dist/chunk-RIPAEGI6.mjs +48 -0
- package/dist/chunk-RIPAEGI6.mjs.map +1 -0
- package/dist/{chunk-LEAXOMYJ.mjs → chunk-SGPUJW3F.mjs} +117 -5
- package/dist/chunk-SGPUJW3F.mjs.map +1 -0
- package/dist/{chunk-PA5DRJNI.mjs → chunk-X2KA6WHM.mjs} +29 -4
- package/dist/chunk-X2KA6WHM.mjs.map +1 -0
- package/dist/{chunk-BLXGONR2.mjs → chunk-XSFB7XXQ.mjs} +51 -4
- package/dist/chunk-XSFB7XXQ.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/barrel-distortion.d.ts +13 -0
- package/dist/components/barrel-distortion.d.ts.map +1 -0
- 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/construct-renderer.d.ts +1 -1
- package/dist/construct-renderer.d.ts.map +1 -1
- package/dist/construct-renderer.mjs +8406 -5785
- package/dist/construct-renderer.mjs.map +1 -1
- package/dist/device/gpu-residency.d.ts +19 -19
- 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/errors/cloud.d.ts +59 -0
- package/dist/errors/cloud.d.ts.map +1 -0
- package/dist/errors/render.d.ts +20 -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 +5 -1
- package/dist/extract/contracts.d.ts.map +1 -1
- package/dist/extract/material-context.d.ts +7 -0
- package/dist/extract/material-context.d.ts.map +1 -0
- 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 +6 -2
- package/dist/features/error-reporting.d.ts.map +1 -1
- package/dist/features/host.d.ts +15 -0
- package/dist/features/host.d.ts.map +1 -1
- package/dist/features/plan.d.ts +10 -0
- package/dist/features/plan.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 +48 -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/glyph-text-layout-system.d.ts +1 -1
- package/dist/glyph-text-layout-system.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.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 +47 -3
- 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 +26 -2
- package/dist/gpu-driven/view-gpu.d.ts.map +1 -1
- package/dist/gpu-scene.d.ts +5 -0
- 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/frame-resources.d.ts.map +1 -1
- package/dist/ibl/skylight-bind-group.d.ts +14 -5
- package/dist/ibl/skylight-bind-group.d.ts.map +1 -1
- package/dist/index.d.ts +30 -7
- package/dist/index.d.ts.map +1 -1
- package/dist/index.mjs +780 -9
- package/dist/index.mjs.map +1 -1
- package/dist/inspection-types.d.ts +135 -1
- 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 +47 -100
- package/dist/instances.d.ts.map +1 -1
- package/dist/internal.mjs +7 -8
- package/dist/internal.mjs.map +1 -1
- package/dist/pbr-pipeline.d.ts +22 -4
- 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/lut-gpu.d.ts +2 -2
- package/dist/pipeline/standard-output/lut-gpu.d.ts.map +1 -1
- package/dist/pipeline/standard-output/resources.d.ts +2 -2
- package/dist/pipeline/standard-output/resources.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.map +1 -1
- package/dist/pipeline-builder.d.ts +1 -1
- package/dist/pipeline-builder.d.ts.map +1 -1
- 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/publication/contract.d.ts +77 -0
- package/dist/publication/contract.d.ts.map +1 -0
- package/dist/publication/dependencies.d.ts +7 -0
- package/dist/publication/dependencies.d.ts.map +1 -0
- package/dist/publication/prepare-geometry.d.ts +9 -0
- package/dist/publication/prepare-geometry.d.ts.map +1 -0
- package/dist/publication/programs.d.ts +5 -0
- package/dist/publication/programs.d.ts.map +1 -0
- package/dist/publication/publisher.d.ts +33 -0
- package/dist/publication/publisher.d.ts.map +1 -0
- package/dist/publication/receiver.d.ts +29 -0
- package/dist/publication/receiver.d.ts.map +1 -0
- package/dist/publication/resource-scope.d.ts +18 -0
- package/dist/publication/resource-scope.d.ts.map +1 -0
- package/dist/publication/targets.d.ts +33 -0
- package/dist/publication/targets.d.ts.map +1 -0
- package/dist/publication/video.d.ts +5 -0
- package/dist/publication/video.d.ts.map +1 -0
- 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 +43 -9
- package/dist/record/frame-snapshot.d.ts.map +1 -1
- package/dist/record/frame.d.ts +15 -65
- 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/helpers.d.ts +2 -2
- package/dist/record/helpers.d.ts.map +1 -1
- package/dist/record/main-pass-geometry.d.ts +22 -6
- package/dist/record/main-pass-geometry.d.ts.map +1 -1
- package/dist/record/main-pass-material.d.ts +14 -10
- package/dist/record/main-pass-material.d.ts.map +1 -1
- package/dist/record/main-pass-sprite-draws.d.ts +3 -16
- 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/motion-blur-receipt.d.ts +11 -0
- package/dist/record/motion-blur-receipt.d.ts.map +1 -0
- package/dist/record/prepared-material-bindings.d.ts +3 -3
- package/dist/record/prepared-material-bindings.d.ts.map +1 -1
- 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 +24 -5
- 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 +1 -1
- package/dist/record/skybox-post-pass.d.ts.map +1 -1
- package/dist/record/sprite-instance-buffer.d.ts +31 -0
- package/dist/record/sprite-instance-buffer.d.ts.map +1 -0
- package/dist/record/target-capture-graph.d.ts +19 -0
- package/dist/record/target-capture-graph.d.ts.map +1 -0
- package/dist/record/typed-frame-graph.d.ts +24 -15
- 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 +14 -4
- 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 +46 -5
- 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 +103 -2
- 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 +18 -9
- 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-projections.d.ts +3 -2
- package/dist/render-system-projections.d.ts.map +1 -1
- 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 +22 -21
- 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 +18 -7
- package/dist/scene/render-scene.d.ts.map +1 -1
- package/dist/scene/render-source.d.ts +42 -0
- package/dist/scene/render-source.d.ts.map +1 -0
- package/dist/scene/source-systems.d.ts +6 -0
- package/dist/scene/source-systems.d.ts.map +1 -0
- 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/systems/skin-palette-types.d.ts +10 -0
- package/dist/systems/skin-palette-types.d.ts.map +1 -1
- package/dist/systems/transparent-dispatch.d.ts +2 -2
- package/dist/systems/transparent-dispatch.d.ts.map +1 -1
- package/dist/systems/transparent-sort-config.d.ts +2 -1
- package/dist/systems/transparent-sort-config.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 +6 -7
- 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/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 +14 -2
- package/dist/typed-render-graph-primitives.d.ts.map +1 -1
- package/dist/volume/component.d.ts +9 -4
- 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/package.json +22 -21
- package/src/__tests__/atmosphere-daylight.dawn.test.ts +72 -0
- package/src/__tests__/auto-exposure-transaction.integration.test.ts +4 -9
- 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__/construct-renderer-identity.unit.test.ts +49 -0
- package/src/__tests__/detached-recovery-graph.unit.test.ts +277 -0
- package/src/__tests__/device-feature-admission.unit.test.ts +3 -2
- 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__/factory-contract.integration.test.ts +295 -45
- package/src/__tests__/feature-depth-input.dawn.test.ts +129 -2
- 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-material-artifacts.unit.test.ts +143 -0
- package/src/__tests__/gpu-driven-pbr.dawn.test.ts +5 -6
- package/src/__tests__/gpu-driven-production.integration.test.ts +482 -3
- package/src/__tests__/gpu-driven-shadow-views.dawn.test.ts +6 -5
- package/src/__tests__/gpu-driven-view-gpu-evidence.ts +94 -6
- 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-scene.unit.test.ts +119 -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 +97 -305
- package/src/__tests__/instances-world-ownership.integration.test.ts +62 -0
- package/src/__tests__/ktx2-basis-gpu-consumer.dawn.test.ts +4 -1
- package/src/__tests__/main-pass-material-medium-selection.unit.test.ts +145 -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__/materials-standard-contract.unit.test.ts +0 -1
- 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 +13 -7
- 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 +66 -8
- package/src/__tests__/physical-material-budget.unit.test.ts +40 -0
- package/src/__tests__/prepared-graphics-capability.unit.test.ts +66 -2
- package/src/__tests__/probe-bindings.unit.test.ts +582 -1
- package/src/__tests__/probe-scene-dirty.integration.test.ts +28 -1
- 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 +8 -0
- package/src/__tests__/render-feature-diagnostics.unit.test.ts +15 -2
- package/src/__tests__/render-feature-error-reporting.unit.test.ts +21 -1
- 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-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 +20 -20
- 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 +42 -8
- package/src/__tests__/renderer-frame-generation-fence.integration.test.ts +16 -0
- package/src/__tests__/renderer-frame-transaction.integration.test.ts +26 -10
- package/src/__tests__/resource-allocation.unit.test.ts +123 -0
- 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 +15 -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-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.integration.test.ts +182 -1
- 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__/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 +4 -2
- package/src/__tests__/volumetric-fog-budget-recovery.integration.test.ts +30 -20
- 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 +113 -9
- package/src/__tests__/volumetric-fog-topology.unit.test.ts +5 -3
- 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/device-feature-admission.ts +2 -2
- 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/host-contract.ts +8 -5
- 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/recovery/device-loss-fanout.ts +13 -0
- package/src/assembly/recovery/renderer-recover.ts +50 -18
- package/src/assembly/render-feature-post-processes.ts +54 -0
- package/src/assembly/render-target-host.ts +57 -47
- package/src/assembly/renderer-facade.ts +7 -2
- 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 +3 -3
- package/src/assembly/webgpu-pbr-ready.ts +9 -1
- package/src/assembly/webgpu-ready-per-pass.ts +104 -0
- package/src/assembly/webgpu-ready.ts +116 -62
- 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 +303 -313
- package/src/assembly/webgpu-vertex-layouts.ts +1 -1
- package/src/barrel-distortion.ts +247 -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/barrel-distortion.ts +46 -0
- 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/sprite-instances.ts +1 -1
- package/src/construct-renderer.ts +1 -1
- package/src/device/gpu-residency.ts +26 -25
- package/src/dynamic-geometry.ts +12 -1
- package/src/errors/cloud.ts +103 -0
- package/src/errors/render.ts +47 -8
- package/src/examples/single-layer-medium-surface.ts +59 -0
- package/src/extract/camera.ts +15 -1
- package/src/extract/contracts.ts +5 -0
- package/src/extract/material-context.ts +21 -0
- package/src/features/barrel-distortion.ts +172 -0
- package/src/features/error-reporting.ts +26 -6
- package/src/features/host.ts +128 -19
- package/src/features/plan.ts +10 -0
- package/src/features/render-graph-contribution.ts +9 -0
- package/src/features/render-graph-raster.ts +45 -3
- package/src/features/targets.ts +66 -0
- package/src/features/types.ts +51 -0
- package/src/fullscreen-post-process-pass.ts +41 -9
- package/src/glyph-text-layout-system.ts +2 -2
- package/src/gpu-dirty-ranges.ts +48 -0
- package/src/gpu-driven/batch-topology.ts +53 -0
- package/src/gpu-driven/material-artifacts.ts +33 -25
- package/src/gpu-driven/prepared-draw.ts +12 -4
- package/src/gpu-driven/production-raster-material.ts +1894 -0
- package/src/gpu-driven/production-raster.ts +825 -784
- 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 +164 -10
- package/src/gpu-scene.ts +75 -84
- package/src/hdrp-buffers.ts +4 -3
- package/src/ibl/frame-resources.ts +0 -1
- package/src/ibl/skylight-bind-group.ts +62 -32
- package/src/index.ts +205 -9
- package/src/inspection-types.ts +162 -0
- package/src/instance-buffer-cache.ts +4 -4
- package/src/instances.ts +152 -569
- package/src/pbr-pipeline.ts +230 -30
- 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/lut-gpu.ts +3 -3
- package/src/pipeline/standard-output/resources.ts +2 -2
- package/src/pipeline/standard-output/types.ts +12 -1
- package/src/pipeline/standard-pipeline.ts +291 -18
- package/src/pipeline/standard-post.ts +90 -24
- package/src/pipeline-builder.ts +1 -1
- package/src/plugin.ts +4 -0
- package/src/points-lines/__tests__/points-lines.bench.ts +17 -8
- package/src/prepare/prepared-graphics-resolver.ts +2 -0
- package/src/publication/__tests__/derived-geometry.integration.test.ts +177 -0
- package/src/publication/__tests__/features.integration.test.ts +122 -0
- package/src/publication/__tests__/programs.unit.test.ts +25 -0
- package/src/publication/__tests__/publication.integration.test.ts +370 -0
- package/src/publication/__tests__/targets.integration.test.ts +120 -0
- package/src/publication/__tests__/video.browser.test.ts +50 -0
- package/src/publication/contract.ts +104 -0
- package/src/publication/dependencies.ts +54 -0
- package/src/publication/prepare-geometry.ts +94 -0
- package/src/publication/programs.ts +45 -0
- package/src/publication/publisher.ts +618 -0
- package/src/publication/receiver.ts +297 -0
- package/src/publication/resource-scope.ts +31 -0
- package/src/publication/targets.ts +182 -0
- package/src/publication/video.ts +33 -0
- package/src/record/__tests__/main-pass-geometry.unit.test.ts +30 -0
- package/src/record/__tests__/material-bg-cache.unit.test.ts +15 -1
- package/src/record/__tests__/sprite-material-abi.unit.test.ts +9 -11
- package/src/record/__tests__/temporal-payload.unit.test.ts +1 -1
- 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__/video-texture-view.unit.test.ts +9 -9
- 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 +855 -0
- package/src/record/fold-instance-buffer.ts +51 -0
- package/src/record/frame-lighting.ts +36 -2
- package/src/record/frame-snapshot.ts +45 -9
- package/src/record/frame.ts +258 -1105
- package/src/record/gpu-draw-receipts.ts +38 -0
- package/src/record/gpu-timing.ts +48 -5
- package/src/record/helpers.ts +2 -2
- package/src/record/main-pass-geometry.ts +272 -84
- package/src/record/main-pass-material.ts +102 -36
- package/src/record/main-pass-sprite-draws.ts +13 -217
- package/src/record/main-pass.ts +164 -27
- package/src/record/motion-blur-receipt.ts +91 -0
- package/src/record/prepared-material-bindings.ts +11 -6
- package/src/record/probe-blend-buffer.ts +180 -0
- package/src/record/recovery-pipeline.ts +35 -3
- package/src/record/render-context.ts +41 -5
- package/src/record/shadow-pass.ts +30 -4
- package/src/record/skybox-post-pass.ts +28 -4
- package/src/record/sprite-instance-buffer.ts +155 -0
- package/src/record/target-capture-graph.ts +258 -0
- package/src/record/typed-frame-graph.ts +776 -340
- package/src/record/view-ubo.ts +27 -4
- package/src/record/volume-params.ts +225 -0
- package/src/recovery/render-system-candidate.ts +243 -50
- package/src/reflection/record-owner.ts +7 -3
- package/src/render-contract.ts +54 -5
- package/src/render-graph-primitives.ts +7 -1
- package/src/render-pipeline.ts +130 -0
- package/src/render-system-extract-tail.ts +90 -78
- package/src/render-system-extract.ts +76 -76
- package/src/render-system-presentation.ts +56 -0
- package/src/render-system-producer-roots.ts +96 -0
- package/src/render-system-projections.ts +3 -2
- package/src/render-system-residency.ts +159 -0
- package/src/render-system.ts +421 -408
- package/src/scene/probe-blend.ts +96 -4
- package/src/scene/render-scene.ts +416 -337
- package/src/scene/render-source.ts +90 -0
- package/src/scene/source-systems.ts +33 -0
- 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 +5 -1
- package/src/systems/skin-palette-types.ts +11 -0
- package/src/systems/transparent-dispatch.ts +2 -2
- package/src/systems/transparent-sort-config.ts +3 -1
- 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/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 +70 -2
- package/src/volume/component.ts +10 -9
- package/src/volume/extract.ts +11 -5
- package/src/volume/inspection.ts +3 -0
- package/src/volume/passes.ts +87 -4
- package/src/volume/resources.ts +2 -1
- package/dist/chunk-3RTCJTH4.mjs +0 -1610
- package/dist/chunk-3RTCJTH4.mjs.map +0 -1
- package/dist/chunk-BLXGONR2.mjs.map +0 -1
- package/dist/chunk-ILQ5MEZF.mjs +0 -32
- package/dist/chunk-ILQ5MEZF.mjs.map +0 -1
- package/dist/chunk-LEAXOMYJ.mjs.map +0 -1
- package/dist/chunk-NB2S7ZRX.mjs +0 -1783
- package/dist/chunk-NB2S7ZRX.mjs.map +0 -1
- package/dist/chunk-NNQL7CB3.mjs +0 -1713
- package/dist/chunk-NNQL7CB3.mjs.map +0 -1
- package/dist/chunk-OO3DRYK7.mjs.map +0 -1
- package/dist/chunk-PA5DRJNI.mjs.map +0 -1
- package/dist/chunk-PLAXOOX5.mjs +0 -1907
- package/dist/chunk-PLAXOOX5.mjs.map +0 -1
- package/dist/chunk-RXZ3RGOU.mjs +0 -53
- package/dist/chunk-RXZ3RGOU.mjs.map +0 -1
- package/dist/chunk-VOZWDM3L.mjs.map +0 -1
|
@@ -1,11 +1,18 @@
|
|
|
1
|
+
import { addTargetCaptureGraphPasses, type CubeCaptureGraphState } from './target-capture-graph';
|
|
2
|
+
|
|
3
|
+
export type { CubeCaptureGraphState, CubeCaptureGraphWork } from './target-capture-graph';
|
|
4
|
+
|
|
1
5
|
import { encodeMipmapLevel } from '@forgeax/engine-assets-runtime';
|
|
2
6
|
import {
|
|
3
7
|
type CompiledRenderGraph,
|
|
4
8
|
type GraphResourceResolver,
|
|
5
9
|
RenderGraphBuilder,
|
|
6
10
|
RenderGraphError,
|
|
11
|
+
type RenderGraphGenerationAllocationEntry,
|
|
12
|
+
type RenderGraphGenerationAllocationInspection,
|
|
7
13
|
type RenderGraphPassInstrumentation,
|
|
8
14
|
type RenderGraphPassInstrumentationScope,
|
|
15
|
+
type RenderGraphResourceAllocationInspection,
|
|
9
16
|
} from '@forgeax/engine-render-graph';
|
|
10
17
|
import type {
|
|
11
18
|
BindGroup,
|
|
@@ -23,6 +30,7 @@ import { RhiError } from '@forgeax/engine-rhi';
|
|
|
23
30
|
import { err, ok, type Result } from '@forgeax/engine-types';
|
|
24
31
|
import { executeRendererFrameTransaction } from '../assembly/renderer-frame-transaction';
|
|
25
32
|
import { standardBloomAdmitted } from '../bloom-admission';
|
|
33
|
+
import { CLOUD_LAYER_FEATURE_IDENTITY } from '../cloud/feature';
|
|
26
34
|
import { type RenderError, RenderFeatureStageFailedError } from '../errors/render';
|
|
27
35
|
import { depthOfFieldTopology } from '../features/depth-of-field/depth-of-field-feature';
|
|
28
36
|
import { resolveDepthOfFieldFrameParams } from '../features/depth-of-field/depth-of-field-params';
|
|
@@ -64,11 +72,7 @@ import {
|
|
|
64
72
|
} from '../gpu-texture-usage';
|
|
65
73
|
import { GPU_BUFFER_USAGE_COPY_DST, GPU_BUFFER_USAGE_UNIFORM } from '../gpu-usage';
|
|
66
74
|
import { createStandardSurfaceLightingBindGroup } from '../hdrp-buffers';
|
|
67
|
-
import type {
|
|
68
|
-
MotionBlurExecutionPass,
|
|
69
|
-
MotionBlurExecutionReceipt,
|
|
70
|
-
RenderFeatureGraphInspection,
|
|
71
|
-
} from '../inspection-types';
|
|
75
|
+
import type { RenderFeatureGraphInspection } from '../inspection-types';
|
|
72
76
|
import type { RenderExtent } from '../pipeline/render-extent';
|
|
73
77
|
import {
|
|
74
78
|
type StandardTopologyInputValue,
|
|
@@ -95,15 +99,15 @@ import type {
|
|
|
95
99
|
import type { ExtractedLights, ExtractedVolumetricFog } from '../render-system-extract';
|
|
96
100
|
import { SHADOW_ATLAS_DEFAULT_FACE_SIZE, SHADOW_ATLAS_DEFAULT_LAYERS } from '../shadow-atlas';
|
|
97
101
|
import type { SsrAdmissionResult, SsrSpatialAdmission } from '../ssr/admission';
|
|
98
|
-
import type { RenderTarget } from '../targets/contracts';
|
|
99
|
-
import type { RenderTargetPhysical } from '../targets/physical';
|
|
100
102
|
import {
|
|
101
103
|
abortTemporalGpuSubmit,
|
|
104
|
+
CLOUD_HISTORY_FORMATS,
|
|
102
105
|
commitTemporalGpuSubmit,
|
|
103
106
|
getTemporalGpuState,
|
|
104
107
|
hasPendingTemporalGpuSubmit,
|
|
105
108
|
retireTemporalGpuState,
|
|
106
109
|
retireTemporalGpuStateAfterFence,
|
|
110
|
+
stageTemporalGpuSubmit,
|
|
107
111
|
TEMPORAL_HISTORY_FORMATS,
|
|
108
112
|
temporalReadIndex,
|
|
109
113
|
temporalWriteIndex,
|
|
@@ -124,6 +128,7 @@ import type { GpuPassTimingPassIdentity } from './gpu-pass-timing/contract.js';
|
|
|
124
128
|
import type { GpuPassTimingCapture, GpuPassTimingSession } from './gpu-pass-timing/session.js';
|
|
125
129
|
import type { GpuTimingCapture } from './gpu-timing';
|
|
126
130
|
import { encodeMainPass } from './main-pass';
|
|
131
|
+
import { deriveMotionBlurExecutionReceipt } from './motion-blur-receipt';
|
|
127
132
|
import type {
|
|
128
133
|
_InternalRenderPipelineContext,
|
|
129
134
|
PipelineState,
|
|
@@ -327,6 +332,125 @@ function importTemporalHistoryTargets(
|
|
|
327
332
|
};
|
|
328
333
|
}
|
|
329
334
|
|
|
335
|
+
type CloudHistoryKind = keyof typeof CLOUD_HISTORY_FORMATS;
|
|
336
|
+
|
|
337
|
+
function cloudHistorySurface(
|
|
338
|
+
state: import('../temporal/gpu').TemporalGpuState,
|
|
339
|
+
kind: CloudHistoryKind,
|
|
340
|
+
index: 0 | 1,
|
|
341
|
+
): { readonly texture: Texture; readonly view: TextureView } {
|
|
342
|
+
if (!state.cloudHistoryEnabled) {
|
|
343
|
+
throw new Error('cloud history target resolved without a cloud-enabled temporal state');
|
|
344
|
+
}
|
|
345
|
+
switch (kind) {
|
|
346
|
+
case 'radiance':
|
|
347
|
+
if (state.cloudRadiance === undefined)
|
|
348
|
+
throw new Error('cloud radiance history is unavailable');
|
|
349
|
+
return state.cloudRadiance[index];
|
|
350
|
+
case 'transmittance':
|
|
351
|
+
if (state.cloudTransmittance === undefined)
|
|
352
|
+
throw new Error('cloud transmittance history is unavailable');
|
|
353
|
+
return state.cloudTransmittance[index];
|
|
354
|
+
case 'depth':
|
|
355
|
+
if (state.cloudDepth === undefined) throw new Error('cloud depth history is unavailable');
|
|
356
|
+
return state.cloudDepth[index];
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
/** Import one renderer-owned cloud history attachment into the typed graph. */
|
|
361
|
+
function importCloudHistoryTarget(
|
|
362
|
+
graph: RenderGraphBuilder<RenderPipelineFrame>,
|
|
363
|
+
label: string,
|
|
364
|
+
kind: CloudHistoryKind,
|
|
365
|
+
role: 'read' | 'write',
|
|
366
|
+
): import('../render-pipeline').RenderPipelineTarget {
|
|
367
|
+
const format = CLOUD_HISTORY_FORMATS[kind];
|
|
368
|
+
const texture = graph.importTexture(
|
|
369
|
+
label,
|
|
370
|
+
{
|
|
371
|
+
format,
|
|
372
|
+
// Cloud transport/history is intentionally half-resolution. The
|
|
373
|
+
// renderer-owned temporal state allocates the same ceil(width/2) extent
|
|
374
|
+
// and the full-resolution resolve reconstructs scene colour from it.
|
|
375
|
+
size: 'half-surface',
|
|
376
|
+
usage:
|
|
377
|
+
GPU_TEXTURE_USAGE_COPY_SRC |
|
|
378
|
+
GPU_TEXTURE_USAGE_COPY_DST |
|
|
379
|
+
GPU_TEXTURE_USAGE_RENDER_ATTACHMENT |
|
|
380
|
+
GPU_TEXTURE_USAGE_TEXTURE_BINDING,
|
|
381
|
+
domain: 'linear-hdr',
|
|
382
|
+
},
|
|
383
|
+
(frame) => {
|
|
384
|
+
const internal = frame as _InternalRenderPipelineContext;
|
|
385
|
+
const state = getTemporalGpuState(
|
|
386
|
+
internal.frameState,
|
|
387
|
+
internal.runtime.device,
|
|
388
|
+
internal.runtime.deviceScope,
|
|
389
|
+
frame.targetW,
|
|
390
|
+
frame.targetH,
|
|
391
|
+
true,
|
|
392
|
+
);
|
|
393
|
+
const index = role === 'read' ? temporalReadIndex(state) : temporalWriteIndex(state);
|
|
394
|
+
return cloudHistorySurface(state, kind, index).texture;
|
|
395
|
+
},
|
|
396
|
+
);
|
|
397
|
+
if (!texture.ok) throw texture.error;
|
|
398
|
+
const view = graph.importView(
|
|
399
|
+
texture.value,
|
|
400
|
+
{ label: `${label}.view`, dimension: '2d' },
|
|
401
|
+
(frame) => {
|
|
402
|
+
const internal = frame as _InternalRenderPipelineContext;
|
|
403
|
+
const state = getTemporalGpuState(
|
|
404
|
+
internal.frameState,
|
|
405
|
+
internal.runtime.device,
|
|
406
|
+
internal.runtime.deviceScope,
|
|
407
|
+
frame.targetW,
|
|
408
|
+
frame.targetH,
|
|
409
|
+
true,
|
|
410
|
+
);
|
|
411
|
+
const index = role === 'read' ? temporalReadIndex(state) : temporalWriteIndex(state);
|
|
412
|
+
return cloudHistorySurface(state, kind, index).view;
|
|
413
|
+
},
|
|
414
|
+
);
|
|
415
|
+
if (!view.ok) throw view.error;
|
|
416
|
+
return { texture: texture.value, view: view.value, format, sampleCount: 1 };
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
function importCloudHistoryTargets(
|
|
420
|
+
graph: RenderGraphBuilder<RenderPipelineFrame>,
|
|
421
|
+
): NonNullable<
|
|
422
|
+
import('../render-pipeline').RenderPipelineBuildContext<RenderPipelineFrame>['cloudHistory']
|
|
423
|
+
> {
|
|
424
|
+
return {
|
|
425
|
+
currentRadiance: importCloudHistoryTarget(
|
|
426
|
+
graph,
|
|
427
|
+
'cloud-history-radiance-current',
|
|
428
|
+
'radiance',
|
|
429
|
+
'write',
|
|
430
|
+
),
|
|
431
|
+
previousRadiance: importCloudHistoryTarget(
|
|
432
|
+
graph,
|
|
433
|
+
'cloud-history-radiance-previous',
|
|
434
|
+
'radiance',
|
|
435
|
+
'read',
|
|
436
|
+
),
|
|
437
|
+
currentTransmittance: importCloudHistoryTarget(
|
|
438
|
+
graph,
|
|
439
|
+
'cloud-history-transmittance-current',
|
|
440
|
+
'transmittance',
|
|
441
|
+
'write',
|
|
442
|
+
),
|
|
443
|
+
previousTransmittance: importCloudHistoryTarget(
|
|
444
|
+
graph,
|
|
445
|
+
'cloud-history-transmittance-previous',
|
|
446
|
+
'transmittance',
|
|
447
|
+
'read',
|
|
448
|
+
),
|
|
449
|
+
currentDepth: importCloudHistoryTarget(graph, 'cloud-history-depth-current', 'depth', 'write'),
|
|
450
|
+
previousDepth: importCloudHistoryTarget(graph, 'cloud-history-depth-previous', 'depth', 'read'),
|
|
451
|
+
};
|
|
452
|
+
}
|
|
453
|
+
|
|
330
454
|
function importSsrHistoryTarget(
|
|
331
455
|
graph: RenderGraphBuilder<RenderPipelineFrame>,
|
|
332
456
|
label: string,
|
|
@@ -485,19 +609,6 @@ export function createTemporalGraphRoster(input: {
|
|
|
485
609
|
};
|
|
486
610
|
}
|
|
487
611
|
|
|
488
|
-
export interface CubeCaptureGraphWork {
|
|
489
|
-
readonly target: RenderTarget;
|
|
490
|
-
readonly faceIndex: number;
|
|
491
|
-
readonly physical: RenderTargetPhysical;
|
|
492
|
-
readonly faceCamera: import('../render-contract').CameraSnapshot;
|
|
493
|
-
readonly viewBindGroupDynamicOffset: number;
|
|
494
|
-
}
|
|
495
|
-
|
|
496
|
-
export interface CubeCaptureGraphState {
|
|
497
|
-
work: readonly CubeCaptureGraphWork[];
|
|
498
|
-
reflectionProbes?: ReflectionProbeGraphState;
|
|
499
|
-
}
|
|
500
|
-
|
|
501
612
|
export interface ReflectionProbeFilterGraphWork {
|
|
502
613
|
readonly probeIndex: number;
|
|
503
614
|
readonly faceIndex: number;
|
|
@@ -544,195 +655,6 @@ export function boundedReflectionProbeFilterWork(
|
|
|
544
655
|
return state.work.slice(0, Math.max(0, state.maxStepsPerFrame));
|
|
545
656
|
}
|
|
546
657
|
|
|
547
|
-
function renderTargetMipCount(work: CubeCaptureGraphWork): number {
|
|
548
|
-
const { descriptor } = work.physical;
|
|
549
|
-
return descriptor.mipLevels === 1
|
|
550
|
-
? 1
|
|
551
|
-
: Math.floor(Math.log2(Math.max(descriptor.width, descriptor.height))) + 1;
|
|
552
|
-
}
|
|
553
|
-
|
|
554
|
-
function addCubeCaptureGraphPasses(
|
|
555
|
-
builder: RenderGraphBuilder<RenderPipelineFrame>,
|
|
556
|
-
state: CubeCaptureGraphState,
|
|
557
|
-
): Result<void, RenderGraphError> {
|
|
558
|
-
for (let index = 0; index < state.work.length; index += 1) {
|
|
559
|
-
const slot = index;
|
|
560
|
-
const initial = state.work[slot];
|
|
561
|
-
if (initial === undefined) continue;
|
|
562
|
-
const current = (): CubeCaptureGraphWork => state.work[slot] ?? initial;
|
|
563
|
-
const texture = builder.importTexture(
|
|
564
|
-
`cube-capture.${slot}.texture`,
|
|
565
|
-
{
|
|
566
|
-
format: initial.physical.descriptor.format,
|
|
567
|
-
size: {
|
|
568
|
-
width: initial.physical.descriptor.width,
|
|
569
|
-
height: initial.physical.descriptor.height,
|
|
570
|
-
depthOrArrayLayers: initial.physical.descriptor.sampleCount === 4 ? 1 : 6,
|
|
571
|
-
},
|
|
572
|
-
mipLevelCount:
|
|
573
|
-
initial.physical.descriptor.sampleCount === 4 ? 1 : renderTargetMipCount(initial),
|
|
574
|
-
sampleCount: initial.physical.descriptor.sampleCount,
|
|
575
|
-
dimension: '2d',
|
|
576
|
-
usage: 0x10 | 0x04 | 0x01,
|
|
577
|
-
},
|
|
578
|
-
() => current().physical.colorTextures[current().faceIndex] ?? initial.physical.texture,
|
|
579
|
-
);
|
|
580
|
-
if (!texture.ok) return texture;
|
|
581
|
-
const color = builder.importView(
|
|
582
|
-
texture.value,
|
|
583
|
-
{
|
|
584
|
-
label: `cube-capture.${slot}.color`,
|
|
585
|
-
dimension: '2d',
|
|
586
|
-
baseMipLevel: 0,
|
|
587
|
-
mipLevelCount: 1,
|
|
588
|
-
baseArrayLayer: initial.physical.descriptor.sampleCount === 4 ? 0 : initial.faceIndex,
|
|
589
|
-
arrayLayerCount: 1,
|
|
590
|
-
},
|
|
591
|
-
() =>
|
|
592
|
-
current().physical.faceViews[current().faceIndex] ??
|
|
593
|
-
initial.physical.faceViews[initial.faceIndex] ??
|
|
594
|
-
initial.physical.view,
|
|
595
|
-
);
|
|
596
|
-
if (!color.ok) return color;
|
|
597
|
-
const depthTexture = builder.importTexture(
|
|
598
|
-
`cube-capture.${slot}.depth-texture`,
|
|
599
|
-
{
|
|
600
|
-
format: 'depth24plus-stencil8',
|
|
601
|
-
size: {
|
|
602
|
-
width: initial.physical.descriptor.width,
|
|
603
|
-
height: initial.physical.descriptor.height,
|
|
604
|
-
depthOrArrayLayers: initial.physical.descriptor.sampleCount === 4 ? 1 : 6,
|
|
605
|
-
},
|
|
606
|
-
mipLevelCount: 1,
|
|
607
|
-
sampleCount: initial.physical.descriptor.sampleCount,
|
|
608
|
-
dimension: '2d',
|
|
609
|
-
usage: 0x10,
|
|
610
|
-
},
|
|
611
|
-
() => current().physical.depthTextures[current().faceIndex] as Texture,
|
|
612
|
-
);
|
|
613
|
-
if (!depthTexture.ok) return depthTexture;
|
|
614
|
-
const depth = builder.importView(
|
|
615
|
-
depthTexture.value,
|
|
616
|
-
{
|
|
617
|
-
label: `cube-capture.${slot}.depth`,
|
|
618
|
-
dimension: '2d',
|
|
619
|
-
baseArrayLayer: initial.physical.descriptor.sampleCount === 4 ? 0 : initial.faceIndex,
|
|
620
|
-
arrayLayerCount: 1,
|
|
621
|
-
},
|
|
622
|
-
() => current().physical.depthViews[current().faceIndex] as TextureView,
|
|
623
|
-
);
|
|
624
|
-
if (!depth.ok) return depth;
|
|
625
|
-
const resolveTexture =
|
|
626
|
-
initial.physical.descriptor.sampleCount === 4
|
|
627
|
-
? builder.importTexture(
|
|
628
|
-
`cube-capture.${slot}.resolve-texture`,
|
|
629
|
-
{
|
|
630
|
-
format: initial.physical.descriptor.format,
|
|
631
|
-
size: {
|
|
632
|
-
width: initial.physical.descriptor.width,
|
|
633
|
-
height: initial.physical.descriptor.height,
|
|
634
|
-
depthOrArrayLayers: 6,
|
|
635
|
-
},
|
|
636
|
-
mipLevelCount: renderTargetMipCount(initial),
|
|
637
|
-
sampleCount: 1,
|
|
638
|
-
dimension: '2d',
|
|
639
|
-
usage: 0x10 | 0x04 | 0x01,
|
|
640
|
-
},
|
|
641
|
-
() =>
|
|
642
|
-
current().physical.resolveTexture ??
|
|
643
|
-
initial.physical.resolveTexture ??
|
|
644
|
-
initial.physical.texture,
|
|
645
|
-
)
|
|
646
|
-
: undefined;
|
|
647
|
-
if (resolveTexture !== undefined && !resolveTexture.ok) return resolveTexture;
|
|
648
|
-
const resolve =
|
|
649
|
-
resolveTexture === undefined
|
|
650
|
-
? undefined
|
|
651
|
-
: builder.importView(
|
|
652
|
-
resolveTexture.value,
|
|
653
|
-
{
|
|
654
|
-
label: `cube-capture.${slot}.resolve`,
|
|
655
|
-
dimension: '2d',
|
|
656
|
-
baseMipLevel: 0,
|
|
657
|
-
mipLevelCount: 1,
|
|
658
|
-
baseArrayLayer: initial.faceIndex,
|
|
659
|
-
arrayLayerCount: 1,
|
|
660
|
-
},
|
|
661
|
-
() =>
|
|
662
|
-
current().physical.resolveFaceViews[current().faceIndex] ??
|
|
663
|
-
initial.physical.resolveFaceViews[initial.faceIndex] ??
|
|
664
|
-
initial.physical.resolveView,
|
|
665
|
-
);
|
|
666
|
-
if (resolve !== undefined && !resolve.ok) return resolve;
|
|
667
|
-
const added = builder.addRasterPass(`cube-capture-face.${slot}`, {
|
|
668
|
-
accesses: [
|
|
669
|
-
{ resource: color.value, usage: 'color-attachment' },
|
|
670
|
-
{ resource: depth.value, usage: 'depth-stencil-write' },
|
|
671
|
-
...(resolve === undefined
|
|
672
|
-
? []
|
|
673
|
-
: [{ resource: resolve.value, usage: 'color-attachment' as const }]),
|
|
674
|
-
],
|
|
675
|
-
colorAttachments: [
|
|
676
|
-
{
|
|
677
|
-
view: color.value,
|
|
678
|
-
...(resolve === undefined ? {} : { resolveTarget: resolve.value }),
|
|
679
|
-
loadOp: 'clear',
|
|
680
|
-
storeOp: 'store',
|
|
681
|
-
clearValue: () => {
|
|
682
|
-
return { r: 0, g: 0, b: 0, a: 1 };
|
|
683
|
-
},
|
|
684
|
-
},
|
|
685
|
-
],
|
|
686
|
-
depthStencilAttachment: {
|
|
687
|
-
view: depth.value,
|
|
688
|
-
depthClearValue: 1,
|
|
689
|
-
depthLoadOp: 'clear',
|
|
690
|
-
depthStoreOp: 'store',
|
|
691
|
-
stencilClearValue: 0,
|
|
692
|
-
stencilLoadOp: 'clear',
|
|
693
|
-
stencilStoreOp: 'store',
|
|
694
|
-
},
|
|
695
|
-
encode: ({ pass, frame, resources }) => {
|
|
696
|
-
const internal = frame as _InternalRenderPipelineContext;
|
|
697
|
-
const captureColor = resources.textureView(color.value);
|
|
698
|
-
if (!captureColor.ok) return;
|
|
699
|
-
const captureDepth = resources.textureView(depth.value);
|
|
700
|
-
if (!captureDepth.ok) return;
|
|
701
|
-
const captureResolve =
|
|
702
|
-
resolve === undefined ? undefined : resources.textureView(resolve.value);
|
|
703
|
-
if (resolve !== undefined && (captureResolve === undefined || !captureResolve.ok)) return;
|
|
704
|
-
const captureResolveView = captureResolve?.ok ? captureResolve.value : null;
|
|
705
|
-
const captureContext = {
|
|
706
|
-
...internal,
|
|
707
|
-
camera: current().faceCamera,
|
|
708
|
-
// Cube faces are raw scene captures, not display-camera HDR output.
|
|
709
|
-
// Select the PSO against the actual target attachment so an LDR
|
|
710
|
-
// cube target is rendered by a compatible forward pipeline.
|
|
711
|
-
tonemapActive: false,
|
|
712
|
-
skyboxActive: false,
|
|
713
|
-
transparentColorFormat: initial.physical.descriptor.format as GPUTextureFormat,
|
|
714
|
-
msaaActive: initial.physical.descriptor.sampleCount === 4,
|
|
715
|
-
viewBindGroupDynamicOffset: current().viewBindGroupDynamicOffset,
|
|
716
|
-
geometryColorView: captureColor.value,
|
|
717
|
-
geometryDepthView: captureDepth.value,
|
|
718
|
-
geometryColorResolveView: captureResolveView,
|
|
719
|
-
splitLdrSprite: false,
|
|
720
|
-
ldrSpritePassView: null,
|
|
721
|
-
};
|
|
722
|
-
encodeMainPass(captureContext, pass, undefined, {
|
|
723
|
-
colorViews: [captureColor.value],
|
|
724
|
-
colorFormats: [initial.physical.descriptor.format as GPUTextureFormat],
|
|
725
|
-
depthView: captureDepth.value,
|
|
726
|
-
passKind: 'forward',
|
|
727
|
-
clearColor: [0, 0, 0, 1],
|
|
728
|
-
});
|
|
729
|
-
},
|
|
730
|
-
});
|
|
731
|
-
if (!added.ok) return added;
|
|
732
|
-
}
|
|
733
|
-
return ok(undefined);
|
|
734
|
-
}
|
|
735
|
-
|
|
736
658
|
export function addReflectionProbeGraphPasses(
|
|
737
659
|
builder: RenderGraphBuilder<RenderPipelineFrame>,
|
|
738
660
|
state: ReflectionProbeGraphState,
|
|
@@ -982,6 +904,7 @@ export interface RenderFeatureGraphRuntimeState {
|
|
|
982
904
|
string,
|
|
983
905
|
import('../fullscreen-post-process-pass').PostProcessShaderEntry
|
|
984
906
|
>;
|
|
907
|
+
postProcessIdentities: readonly string[];
|
|
985
908
|
}
|
|
986
909
|
|
|
987
910
|
/** The exact fields that define one validated feature-plan collection. */
|
|
@@ -1042,6 +965,8 @@ export interface RenderFeatureGraphCandidate {
|
|
|
1042
965
|
string,
|
|
1043
966
|
import('../fullscreen-post-process-pass').PostProcessShaderEntry
|
|
1044
967
|
>;
|
|
968
|
+
/** Public Standard post-effect identities; graph-local resources stay internal. */
|
|
969
|
+
readonly postProcessIdentities?: readonly string[];
|
|
1045
970
|
/**
|
|
1046
971
|
* Physical transient graphics resources are imported into the compiled
|
|
1047
972
|
* graph. Their lease therefore needs a new graph even when the declarative
|
|
@@ -1065,6 +990,216 @@ export interface RenderFeatureGraphCandidate {
|
|
|
1065
990
|
|
|
1066
991
|
const featureGraphStates = new WeakMap<RenderSystemInternals, RenderFeatureGraphRuntimeState>();
|
|
1067
992
|
const graphDeviceGenerations = new WeakMap<object, number>();
|
|
993
|
+
const graphRetirementFailures = new WeakMap<
|
|
994
|
+
RenderFrameState,
|
|
995
|
+
Set<CompiledRenderGraph<RenderPipelineFrame>>
|
|
996
|
+
>();
|
|
997
|
+
|
|
998
|
+
type GraphGenerationRole = 'active' | 'candidate' | 'retiring';
|
|
999
|
+
type GraphGenerationStatus = 'active' | 'retiring' | 'failed' | 'retired';
|
|
1000
|
+
|
|
1001
|
+
interface GraphGenerationAllocationRecord {
|
|
1002
|
+
readonly graph: CompiledRenderGraph<RenderPipelineFrame>;
|
|
1003
|
+
status: GraphGenerationStatus;
|
|
1004
|
+
allocation: RenderGraphResourceAllocationInspection | undefined;
|
|
1005
|
+
}
|
|
1006
|
+
|
|
1007
|
+
/**
|
|
1008
|
+
* One stable allocation owner for a RenderSystem lifetime. Recovery builds a
|
|
1009
|
+
* detached frame state, but that state intentionally shares this owner before
|
|
1010
|
+
* it can publish a candidate into the active RenderSystem. Graph records stay
|
|
1011
|
+
* here across asynchronous retirement so a successful replacement cannot
|
|
1012
|
+
* erase the overlap peak before the next public inspection.
|
|
1013
|
+
*/
|
|
1014
|
+
interface GraphGenerationAllocationOwner {
|
|
1015
|
+
readonly records: Map<CompiledRenderGraph<RenderPipelineFrame>, GraphGenerationAllocationRecord>;
|
|
1016
|
+
peakBytes: number;
|
|
1017
|
+
}
|
|
1018
|
+
|
|
1019
|
+
const graphGenerationAllocationOwners = new WeakMap<
|
|
1020
|
+
RenderFrameState,
|
|
1021
|
+
GraphGenerationAllocationOwner
|
|
1022
|
+
>();
|
|
1023
|
+
|
|
1024
|
+
function graphGenerationAllocationOwner(
|
|
1025
|
+
frameState: RenderFrameState,
|
|
1026
|
+
): GraphGenerationAllocationOwner {
|
|
1027
|
+
const existing = graphGenerationAllocationOwners.get(frameState);
|
|
1028
|
+
if (existing !== undefined) return existing;
|
|
1029
|
+
const created: GraphGenerationAllocationOwner = { records: new Map(), peakBytes: 0 };
|
|
1030
|
+
graphGenerationAllocationOwners.set(frameState, created);
|
|
1031
|
+
return created;
|
|
1032
|
+
}
|
|
1033
|
+
|
|
1034
|
+
function graphRetirementFailureSet(
|
|
1035
|
+
frameState: RenderFrameState,
|
|
1036
|
+
): Set<CompiledRenderGraph<RenderPipelineFrame>> {
|
|
1037
|
+
const existing = graphRetirementFailures.get(frameState);
|
|
1038
|
+
if (existing !== undefined) return existing;
|
|
1039
|
+
const created = new Set<CompiledRenderGraph<RenderPipelineFrame>>();
|
|
1040
|
+
graphRetirementFailures.set(frameState, created);
|
|
1041
|
+
return created;
|
|
1042
|
+
}
|
|
1043
|
+
|
|
1044
|
+
/** Share the renderer-owned graph ledger with a detached recovery frame state. */
|
|
1045
|
+
export function shareRenderGraphGenerationAllocationOwner(
|
|
1046
|
+
source: RenderFrameState,
|
|
1047
|
+
target: RenderFrameState,
|
|
1048
|
+
): void {
|
|
1049
|
+
graphGenerationAllocationOwners.set(target, graphGenerationAllocationOwner(source));
|
|
1050
|
+
graphRetirementFailures.set(target, graphRetirementFailureSet(source));
|
|
1051
|
+
}
|
|
1052
|
+
|
|
1053
|
+
function observeGraphGenerationAllocation(frameState: RenderFrameState): void {
|
|
1054
|
+
const owner = graphGenerationAllocationOwner(frameState);
|
|
1055
|
+
let simultaneousBytes = 0;
|
|
1056
|
+
for (const record of owner.records.values()) {
|
|
1057
|
+
if (record.status === 'retired') continue;
|
|
1058
|
+
const allocation = record.graph.inspect().resourceAllocation;
|
|
1059
|
+
record.allocation = allocation;
|
|
1060
|
+
if (allocation !== undefined) {
|
|
1061
|
+
simultaneousBytes += allocation.liveBytes + allocation.pendingRetirementBytes;
|
|
1062
|
+
}
|
|
1063
|
+
}
|
|
1064
|
+
owner.peakBytes = Math.max(owner.peakBytes, simultaneousBytes);
|
|
1065
|
+
}
|
|
1066
|
+
|
|
1067
|
+
function trackGraphGeneration(
|
|
1068
|
+
frameState: RenderFrameState,
|
|
1069
|
+
graph: CompiledRenderGraph<RenderPipelineFrame>,
|
|
1070
|
+
): void {
|
|
1071
|
+
const owner = graphGenerationAllocationOwner(frameState);
|
|
1072
|
+
const record = owner.records.get(graph);
|
|
1073
|
+
if (record === undefined) {
|
|
1074
|
+
owner.records.set(graph, { graph, status: 'active', allocation: undefined });
|
|
1075
|
+
} else if (record.status === 'retired') {
|
|
1076
|
+
record.status = 'active';
|
|
1077
|
+
}
|
|
1078
|
+
observeGraphGenerationAllocation(frameState);
|
|
1079
|
+
}
|
|
1080
|
+
|
|
1081
|
+
function setGraphGenerationRetiring(
|
|
1082
|
+
frameState: RenderFrameState,
|
|
1083
|
+
graph: CompiledRenderGraph<RenderPipelineFrame>,
|
|
1084
|
+
): void {
|
|
1085
|
+
const owner = graphGenerationAllocationOwner(frameState);
|
|
1086
|
+
const record = owner.records.get(graph);
|
|
1087
|
+
if (record === undefined) {
|
|
1088
|
+
owner.records.set(graph, { graph, status: 'retiring', allocation: undefined });
|
|
1089
|
+
} else if (record.status !== 'failed') {
|
|
1090
|
+
record.status = 'retiring';
|
|
1091
|
+
}
|
|
1092
|
+
}
|
|
1093
|
+
|
|
1094
|
+
function setGraphGenerationRetirementResult(
|
|
1095
|
+
frameState: RenderFrameState,
|
|
1096
|
+
graph: CompiledRenderGraph<RenderPipelineFrame>,
|
|
1097
|
+
succeeded: boolean,
|
|
1098
|
+
): void {
|
|
1099
|
+
const owner = graphGenerationAllocationOwner(frameState);
|
|
1100
|
+
const record = owner.records.get(graph);
|
|
1101
|
+
if (record !== undefined) record.status = succeeded ? 'retired' : 'failed';
|
|
1102
|
+
observeGraphGenerationAllocation(frameState);
|
|
1103
|
+
// A successful graph no longer owns any handles. Keep the renderer-level
|
|
1104
|
+
// peak scalar, but release the graph object from the generation map; failed
|
|
1105
|
+
// and pending owners remain retained for recovery inspection.
|
|
1106
|
+
if (succeeded) owner.records.delete(graph);
|
|
1107
|
+
}
|
|
1108
|
+
|
|
1109
|
+
/**
|
|
1110
|
+
* Project the actual RenderSystem graph-generation owners as one detached
|
|
1111
|
+
* allocation receipt. The candidate and fallback graph can overlap before a
|
|
1112
|
+
* submit settles; failed retirement stays visible until the frame owner is
|
|
1113
|
+
* discarded instead of disappearing with the asynchronous Set entry.
|
|
1114
|
+
*/
|
|
1115
|
+
export function inspectRenderGraphGenerationAllocation(
|
|
1116
|
+
frameState: RenderFrameState,
|
|
1117
|
+
): RenderGraphGenerationAllocationInspection {
|
|
1118
|
+
const rolesByGraph = new Map<
|
|
1119
|
+
CompiledRenderGraph<RenderPipelineFrame>,
|
|
1120
|
+
Set<GraphGenerationRole>
|
|
1121
|
+
>();
|
|
1122
|
+
const add = (
|
|
1123
|
+
graph: CompiledRenderGraph<RenderPipelineFrame> | null | undefined,
|
|
1124
|
+
role: GraphGenerationRole,
|
|
1125
|
+
) => {
|
|
1126
|
+
if (graph === null || graph === undefined) return;
|
|
1127
|
+
const roles = rolesByGraph.get(graph);
|
|
1128
|
+
if (roles === undefined) rolesByGraph.set(graph, new Set([role]));
|
|
1129
|
+
else roles.add(role);
|
|
1130
|
+
};
|
|
1131
|
+
add(frameState.compiledFrameGraph, 'active');
|
|
1132
|
+
add(frameState.volumetricFogCandidateGraph, 'candidate');
|
|
1133
|
+
add(frameState.volumetricFogPreviousGraph, 'retiring');
|
|
1134
|
+
add(frameState.depthOfFieldCandidateGraph, 'candidate');
|
|
1135
|
+
add(frameState.depthOfFieldPreviousGraph, 'retiring');
|
|
1136
|
+
add(frameState.barrelDistortionCandidateGraph, 'candidate');
|
|
1137
|
+
add(frameState.barrelDistortionPreviousGraph, 'retiring');
|
|
1138
|
+
for (const graph of frameState.retiredCompiledFrameGraphs) add(graph, 'retiring');
|
|
1139
|
+
for (const graph of graphRetirementFailureSet(frameState)) add(graph, 'retiring');
|
|
1140
|
+
|
|
1141
|
+
const owner = graphGenerationAllocationOwner(frameState);
|
|
1142
|
+
const entries: RenderGraphGenerationAllocationEntry[] = [];
|
|
1143
|
+
let unavailableGenerationCount = 0;
|
|
1144
|
+
for (const [graph, record] of owner.records) {
|
|
1145
|
+
if (record.status === 'retired') continue;
|
|
1146
|
+
const roles = rolesByGraph.get(graph) ?? new Set<GraphGenerationRole>();
|
|
1147
|
+
if (record.status === 'retiring' || record.status === 'failed') roles.add('retiring');
|
|
1148
|
+
if (roles.size === 0) {
|
|
1149
|
+
// A candidate can be detached from the active state's role fields while
|
|
1150
|
+
// it is still being prepared. Keep its owner record observable until
|
|
1151
|
+
// the publication or cleanup event settles it.
|
|
1152
|
+
roles.add(record.status === 'active' ? 'active' : 'retiring');
|
|
1153
|
+
}
|
|
1154
|
+
// Inspection is a projection of the graph's current ledger. The cached
|
|
1155
|
+
// snapshot is only for event-time peak updates; using it here would make
|
|
1156
|
+
// a successfully fenced graph look live after its retirement started.
|
|
1157
|
+
const allocation = graph.inspect().resourceAllocation;
|
|
1158
|
+
record.allocation = allocation;
|
|
1159
|
+
if (allocation === undefined) {
|
|
1160
|
+
unavailableGenerationCount += 1;
|
|
1161
|
+
continue;
|
|
1162
|
+
}
|
|
1163
|
+
const retirement =
|
|
1164
|
+
record.status === 'failed' ? 'failed' : roles.has('retiring') ? 'pending' : 'active';
|
|
1165
|
+
entries.push({
|
|
1166
|
+
generation: graph.inspect().generation,
|
|
1167
|
+
roles: Object.freeze([...roles]),
|
|
1168
|
+
retirement,
|
|
1169
|
+
allocation,
|
|
1170
|
+
});
|
|
1171
|
+
}
|
|
1172
|
+
entries.sort((left, right) => left.generation - right.generation);
|
|
1173
|
+
const liveBytes = entries.reduce((sum, entry) => sum + entry.allocation.liveBytes, 0);
|
|
1174
|
+
const pendingRetirementBytes = entries.reduce(
|
|
1175
|
+
(sum, entry) => sum + entry.allocation.pendingRetirementBytes,
|
|
1176
|
+
0,
|
|
1177
|
+
);
|
|
1178
|
+
const peakBytes = Math.max(owner.peakBytes, liveBytes + pendingRetirementBytes);
|
|
1179
|
+
const failedEntries = entries.filter((entry) => entry.retirement === 'failed');
|
|
1180
|
+
return Object.freeze({
|
|
1181
|
+
unit: 'engine-allocation-bytes',
|
|
1182
|
+
physicalResidency: 'unknown',
|
|
1183
|
+
availability:
|
|
1184
|
+
entries.length === 0
|
|
1185
|
+
? unavailableGenerationCount === 0
|
|
1186
|
+
? 'complete'
|
|
1187
|
+
: 'unavailable'
|
|
1188
|
+
: unavailableGenerationCount === 0
|
|
1189
|
+
? 'complete'
|
|
1190
|
+
: 'partial',
|
|
1191
|
+
unavailableGenerationCount,
|
|
1192
|
+
entries: Object.freeze(entries.map((entry) => Object.freeze(entry))),
|
|
1193
|
+
liveBytes,
|
|
1194
|
+
pendingRetirementBytes,
|
|
1195
|
+
peakBytes,
|
|
1196
|
+
failedRetirementCount: failedEntries.length,
|
|
1197
|
+
failedRetirementBytes: failedEntries.reduce(
|
|
1198
|
+
(sum, entry) => sum + entry.allocation.liveBytes + entry.allocation.pendingRetirementBytes,
|
|
1199
|
+
0,
|
|
1200
|
+
),
|
|
1201
|
+
});
|
|
1202
|
+
}
|
|
1068
1203
|
|
|
1069
1204
|
interface MutableRenderFeatureGraphInspection {
|
|
1070
1205
|
planRevisionState: RenderFeaturePlanRevisionState;
|
|
@@ -1230,6 +1365,7 @@ export function getRenderFeatureGraphState(
|
|
|
1230
1365
|
const created: RenderFeatureGraphRuntimeState = {
|
|
1231
1366
|
plans: [],
|
|
1232
1367
|
fullscreenEffects: new Map(),
|
|
1368
|
+
postProcessIdentities: [],
|
|
1233
1369
|
};
|
|
1234
1370
|
featureGraphStates.set(internals, created);
|
|
1235
1371
|
return created;
|
|
@@ -1239,6 +1375,7 @@ export function resetRenderFeatureGraphState(internals: RenderSystemInternals):
|
|
|
1239
1375
|
const state = getRenderFeatureGraphState(internals);
|
|
1240
1376
|
state.plans = [];
|
|
1241
1377
|
state.fullscreenEffects = new Map();
|
|
1378
|
+
state.postProcessIdentities = [];
|
|
1242
1379
|
}
|
|
1243
1380
|
|
|
1244
1381
|
export function reportRenderFeatureGraphError(
|
|
@@ -1357,6 +1494,7 @@ function commitFeatureCandidate(
|
|
|
1357
1494
|
const state = getRenderFeatureGraphState(internals);
|
|
1358
1495
|
state.plans = candidate.plans;
|
|
1359
1496
|
state.fullscreenEffects = candidate.fullscreenEffects;
|
|
1497
|
+
state.postProcessIdentities = candidate.postProcessIdentities ?? [];
|
|
1360
1498
|
}
|
|
1361
1499
|
|
|
1362
1500
|
function topologyOf(
|
|
@@ -1378,6 +1516,7 @@ function topologyOf(
|
|
|
1378
1516
|
standardLighting: StandardTopologyInputValue | undefined,
|
|
1379
1517
|
ssr: SsrSpatialAdmission | undefined,
|
|
1380
1518
|
renderExtent: RenderExtent | undefined,
|
|
1519
|
+
surfaceMediumActive: boolean | undefined,
|
|
1381
1520
|
analyticFog: boolean,
|
|
1382
1521
|
): Result<RenderPipelineTopology, RhiError> {
|
|
1383
1522
|
const cascadeCount = Math.max(1, Math.min(4, Math.round(lights.cascadeCount ?? 1))) as
|
|
@@ -1399,10 +1538,9 @@ function topologyOf(
|
|
|
1399
1538
|
floatRenderAttachment: internals.device.caps.rgba16floatRenderable,
|
|
1400
1539
|
});
|
|
1401
1540
|
if (!surfaceProfile.ok) return surfaceProfile;
|
|
1402
|
-
const featurePostEffects =
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
].map(([id]) => id);
|
|
1541
|
+
const featurePostEffects =
|
|
1542
|
+
featureGraphCandidate?.postProcessIdentities ??
|
|
1543
|
+
getRenderFeatureGraphState(internals).postProcessIdentities;
|
|
1406
1544
|
const featurePostEffectDeclarations = [
|
|
1407
1545
|
...(featureGraphCandidate?.fullscreenEffects ??
|
|
1408
1546
|
getRenderFeatureGraphState(internals).fullscreenEffects),
|
|
@@ -1461,6 +1599,7 @@ function topologyOf(
|
|
|
1461
1599
|
// positive intensity changes update the recorder UBO in place.
|
|
1462
1600
|
bloom: standardBloomAdmitted(camera) ? 'on' : 'off',
|
|
1463
1601
|
bloomIntensity: camera.bloomIntensity,
|
|
1602
|
+
barrelDistortion: !clearOnly && (camera.barrelDistortion?.strength ?? 0) > 0,
|
|
1464
1603
|
...(depthOfField === undefined ? {} : { depthOfField }),
|
|
1465
1604
|
},
|
|
1466
1605
|
atmosphere: !clearOnly && frameState.environmentFrame?.source.kind === 'atmosphere',
|
|
@@ -1514,6 +1653,16 @@ function topologyOf(
|
|
|
1514
1653
|
return {
|
|
1515
1654
|
enabled: true,
|
|
1516
1655
|
format: volumetricFog.densityAsset.format,
|
|
1656
|
+
additional: (volumetricFog.additional ?? []).flatMap((member) =>
|
|
1657
|
+
member.densityAsset?.shape.viewDimension === '3d'
|
|
1658
|
+
? [
|
|
1659
|
+
{
|
|
1660
|
+
format: member.densityAsset.format,
|
|
1661
|
+
extent: member.densityAsset.shape.extent,
|
|
1662
|
+
},
|
|
1663
|
+
]
|
|
1664
|
+
: [],
|
|
1665
|
+
),
|
|
1517
1666
|
extent: {
|
|
1518
1667
|
width: volumetricFog.densityAsset.shape.extent.width,
|
|
1519
1668
|
height: volumetricFog.densityAsset.shape.extent.height,
|
|
@@ -1521,7 +1670,7 @@ function topologyOf(
|
|
|
1521
1670
|
},
|
|
1522
1671
|
froxelExtent: deriveVolumetricFogExtent(
|
|
1523
1672
|
{ width, height },
|
|
1524
|
-
volumeProfile.depth,
|
|
1673
|
+
volumeProfile.depth * (1 + (volumetricFog.additional?.length ?? 0)),
|
|
1525
1674
|
volumeProfile.tileSize,
|
|
1526
1675
|
),
|
|
1527
1676
|
resolvedExtent: deriveVolumetricFogResolvedExtent(
|
|
@@ -1562,6 +1711,9 @@ function topologyOf(
|
|
|
1562
1711
|
activeCount: 0,
|
|
1563
1712
|
needsRoughMips: false,
|
|
1564
1713
|
},
|
|
1714
|
+
...((surfaceMediumActive ?? gpuDriven?.surfaceSubmission !== undefined)
|
|
1715
|
+
? { singleLayerMedium: true }
|
|
1716
|
+
: {}),
|
|
1565
1717
|
});
|
|
1566
1718
|
}
|
|
1567
1719
|
|
|
@@ -1586,6 +1738,30 @@ function targetResolver(
|
|
|
1586
1738
|
...(named.resolveTarget === undefined ? {} : { resolveTarget: named.resolveTarget }),
|
|
1587
1739
|
};
|
|
1588
1740
|
}
|
|
1741
|
+
if (typeof resource === 'string') {
|
|
1742
|
+
const target = targets.find((candidate) => candidate.name === resource);
|
|
1743
|
+
if (target !== undefined) {
|
|
1744
|
+
return {
|
|
1745
|
+
texture: target.texture,
|
|
1746
|
+
view: target.view,
|
|
1747
|
+
...(target.resolveTarget === undefined ? {} : { resolveTarget: target.resolveTarget }),
|
|
1748
|
+
};
|
|
1749
|
+
}
|
|
1750
|
+
// Standard lanes expose the depth attachment as a semantic target
|
|
1751
|
+
// without duplicating the public `depth` name on every concrete graph
|
|
1752
|
+
// projection. Keep the string alias stable for feature-authored
|
|
1753
|
+
// fullscreen bindings while preserving the typed target identity.
|
|
1754
|
+
if (resource === 'depth') {
|
|
1755
|
+
const depth = targets.find((candidate) => candidate.kind === 'scene-depth');
|
|
1756
|
+
if (depth !== undefined) {
|
|
1757
|
+
return {
|
|
1758
|
+
texture: depth.texture,
|
|
1759
|
+
view: depth.view,
|
|
1760
|
+
...(depth.resolveTarget === undefined ? {} : { resolveTarget: depth.resolveTarget }),
|
|
1761
|
+
};
|
|
1762
|
+
}
|
|
1763
|
+
}
|
|
1764
|
+
}
|
|
1589
1765
|
}
|
|
1590
1766
|
if (isSceneDataTarget(resource)) {
|
|
1591
1767
|
const semantic = semanticTargets.find(
|
|
@@ -1597,11 +1773,27 @@ function targetResolver(
|
|
|
1597
1773
|
: { texture: semantic.texture, view: semantic.view };
|
|
1598
1774
|
}
|
|
1599
1775
|
if (!isRenderFeatureTargetHandle(resource)) return undefined;
|
|
1776
|
+
// A typed feature handle is an identity, not a format request. Falling
|
|
1777
|
+
// back to another same-format target can silently bind scene color in
|
|
1778
|
+
// place of a missing cloud history/shadow resource and turn a producer
|
|
1779
|
+
// failure into plausible but incorrect pixels.
|
|
1780
|
+
// Standard lanes expose scene depth as a semantic target without a
|
|
1781
|
+
// duplicated public name, while feature plans use the stable `depth`
|
|
1782
|
+
// handle name. Preserve that one semantic alias here as well as above for
|
|
1783
|
+
// string-authored fullscreen bindings.
|
|
1600
1784
|
const target = targets.find(
|
|
1601
1785
|
(candidate) =>
|
|
1602
1786
|
candidate.kind === resource.kind &&
|
|
1603
1787
|
candidate.format === resource.format &&
|
|
1604
|
-
candidate.sampleCount === resource.sampleCount
|
|
1788
|
+
candidate.sampleCount === resource.sampleCount &&
|
|
1789
|
+
(resource.name === undefined ||
|
|
1790
|
+
candidate.name === resource.name ||
|
|
1791
|
+
(resource.kind === 'scene-color' &&
|
|
1792
|
+
resource.name === 'color' &&
|
|
1793
|
+
candidate.kind === 'scene-color') ||
|
|
1794
|
+
(resource.kind === 'scene-depth' &&
|
|
1795
|
+
resource.name === 'depth' &&
|
|
1796
|
+
candidate.kind === 'scene-depth')),
|
|
1605
1797
|
);
|
|
1606
1798
|
return target === undefined
|
|
1607
1799
|
? undefined
|
|
@@ -1621,6 +1813,9 @@ function resolveTargetBindings(
|
|
|
1621
1813
|
};
|
|
1622
1814
|
readonly resources: GraphResourceResolver;
|
|
1623
1815
|
readonly resolveTarget: RenderFeatureGraphTargetResolver;
|
|
1816
|
+
readonly resolveGpuResource?: (
|
|
1817
|
+
name: string,
|
|
1818
|
+
) => import('../features/prepared-gpu-work').RenderFeatureResolvedGpuBuffer | undefined;
|
|
1624
1819
|
},
|
|
1625
1820
|
featurePostProcessEntries?: ReadonlyMap<string, PostProcessShaderEntry>,
|
|
1626
1821
|
): RenderFeatureGraphBindingsResolution | undefined {
|
|
@@ -1632,6 +1827,136 @@ function resolveTargetBindings(
|
|
|
1632
1827
|
const sceneDepth = descriptor?.values.sceneDepth;
|
|
1633
1828
|
const sceneDepthBinding = descriptor?.values.sceneDepthBinding;
|
|
1634
1829
|
if (pipeline === undefined) return undefined;
|
|
1830
|
+
if (descriptor?.values.view === true) {
|
|
1831
|
+
const viewBindGroup = buildPerFrameBindGroups(
|
|
1832
|
+
frame.runtime as RenderSystemInternals,
|
|
1833
|
+
frame.frameState,
|
|
1834
|
+
frame.pipelineState,
|
|
1835
|
+
true,
|
|
1836
|
+
frame.bindGroupCounts,
|
|
1837
|
+
{
|
|
1838
|
+
directionalShadow: frame.frameState.currentDirectionalShadowView ?? undefined,
|
|
1839
|
+
spotShadow: frame.frameState.currentSpotShadowView ?? undefined,
|
|
1840
|
+
},
|
|
1841
|
+
true,
|
|
1842
|
+
frame.standardLighting,
|
|
1843
|
+
).viewBindGroup;
|
|
1844
|
+
return viewBindGroup === null ? undefined : { handle: viewBindGroup, dynamicOffsets: [0, 0] };
|
|
1845
|
+
}
|
|
1846
|
+
// Generic fullscreen producers (for example the CloudLayer scene pass)
|
|
1847
|
+
// share the renderer-owned post-process bind-group contract without opting
|
|
1848
|
+
// into the temporal two-input path below. Their input/depth aliases are
|
|
1849
|
+
// resolved from the active typed graph, so they cannot accidentally sample
|
|
1850
|
+
// a stale surface view or manufacture a second resource owner.
|
|
1851
|
+
if (descriptor?.values.fullscreen === true && !isTemporalFullscreenBinding(descriptor.values)) {
|
|
1852
|
+
const shader = descriptor.values.shader;
|
|
1853
|
+
if (typeof shader !== 'string') return undefined;
|
|
1854
|
+
const entry =
|
|
1855
|
+
featurePostProcessEntries?.get(shader) ?? frame.runtime.lookupPostProcess?.(shader);
|
|
1856
|
+
if (entry === undefined) return undefined;
|
|
1857
|
+
const depthFallback = descriptor.values.depthFallback === true;
|
|
1858
|
+
const depthValue = descriptor.values.depth;
|
|
1859
|
+
const depthTarget =
|
|
1860
|
+
depthFallback || depthValue === undefined
|
|
1861
|
+
? undefined
|
|
1862
|
+
: input.resolveTarget(depthValue as never);
|
|
1863
|
+
const fullscreen = buildFullscreenPostProcessPass(
|
|
1864
|
+
{ device: frame.runtime.device, errorRegistry: frame.runtime.errorRegistry },
|
|
1865
|
+
entry,
|
|
1866
|
+
depthTarget?.resolveTarget !== undefined,
|
|
1867
|
+
);
|
|
1868
|
+
if (fullscreen === null || fullscreen.sampler === null) return undefined;
|
|
1869
|
+
const inputDisabled = descriptor.values.input === false;
|
|
1870
|
+
const inputTarget = inputDisabled
|
|
1871
|
+
? undefined
|
|
1872
|
+
: input.resolveTarget(descriptor.values.input as never);
|
|
1873
|
+
const inputView =
|
|
1874
|
+
inputTarget === undefined
|
|
1875
|
+
? { ok: true as const, value: frame.pipelineState.defaultWhiteTextureView }
|
|
1876
|
+
: input.resources.textureView(inputTarget.view);
|
|
1877
|
+
if (!inputView.ok) return undefined;
|
|
1878
|
+
const depthView = depthFallback
|
|
1879
|
+
? frame.pipelineState.shadowFallbackTextureView
|
|
1880
|
+
: depthTarget === undefined
|
|
1881
|
+
? undefined
|
|
1882
|
+
: (() => {
|
|
1883
|
+
const depthTexture = input.resources.texture(depthTarget.texture);
|
|
1884
|
+
if (!depthTexture.ok) return undefined;
|
|
1885
|
+
const created = frame.runtime.device.createTextureView(depthTexture.value as Texture, {
|
|
1886
|
+
aspect: 'depth-only',
|
|
1887
|
+
dimension: '2d',
|
|
1888
|
+
});
|
|
1889
|
+
return created.ok ? created.value : undefined;
|
|
1890
|
+
})();
|
|
1891
|
+
if (
|
|
1892
|
+
depthTarget !== undefined &&
|
|
1893
|
+
(depthView === undefined || fullscreen.depthSampler === null)
|
|
1894
|
+
) {
|
|
1895
|
+
return undefined;
|
|
1896
|
+
}
|
|
1897
|
+
const additionalViews: { readonly binding: number; readonly view: TextureView }[] = [];
|
|
1898
|
+
const additionalNames = descriptor.values.additionalTextures;
|
|
1899
|
+
if (Array.isArray(additionalNames)) {
|
|
1900
|
+
for (const [index, value] of additionalNames.entries()) {
|
|
1901
|
+
if (typeof value !== 'string') return undefined;
|
|
1902
|
+
const target = input.resolveTarget(value);
|
|
1903
|
+
if (target === undefined) return undefined;
|
|
1904
|
+
const view = input.resources.textureView(target.view);
|
|
1905
|
+
if (!view.ok) return undefined;
|
|
1906
|
+
const binding = fullscreen.extraColorBindings[index];
|
|
1907
|
+
if (binding === undefined) return undefined;
|
|
1908
|
+
additionalViews.push({ binding, view: view.value });
|
|
1909
|
+
}
|
|
1910
|
+
}
|
|
1911
|
+
const layout = pipeline.getBindGroupLayout?.(1);
|
|
1912
|
+
if (layout === undefined) return undefined;
|
|
1913
|
+
const paramsBuffer = frame.runtime.getPostProcessParamsBuffer?.(shader);
|
|
1914
|
+
if (entry.params !== undefined && paramsBuffer === undefined) return undefined;
|
|
1915
|
+
if (entry.params !== undefined && paramsBuffer !== undefined) {
|
|
1916
|
+
const data = frame.postProcessParams.get(shader) ?? entry.params.defaultValue;
|
|
1917
|
+
if (data.byteLength !== entry.params.byteSize) return undefined;
|
|
1918
|
+
const written = frame.runtime.device.queue.writeBuffer(paramsBuffer, 0, data);
|
|
1919
|
+
if (!written.ok) return undefined;
|
|
1920
|
+
}
|
|
1921
|
+
const createdBindGroup = createFullscreenBindGroup(
|
|
1922
|
+
frame.runtime.device,
|
|
1923
|
+
layout,
|
|
1924
|
+
inputView.value,
|
|
1925
|
+
fullscreen.sampler,
|
|
1926
|
+
paramsBuffer,
|
|
1927
|
+
depthView ?? null,
|
|
1928
|
+
fullscreen.depthSampler,
|
|
1929
|
+
additionalViews,
|
|
1930
|
+
fullscreen.extraStorageBindings.map((binding, index) => {
|
|
1931
|
+
const names = descriptor.values.storageBuffers;
|
|
1932
|
+
const name = Array.isArray(names) ? names[index] : undefined;
|
|
1933
|
+
if (typeof name !== 'string') throw new Error('fullscreen storage buffer name missing');
|
|
1934
|
+
const buffer = input.resolveGpuResource?.(name);
|
|
1935
|
+
if (buffer === undefined) throw new Error(`fullscreen storage buffer unavailable: ${name}`);
|
|
1936
|
+
return { binding, buffer: buffer.buffer };
|
|
1937
|
+
}),
|
|
1938
|
+
);
|
|
1939
|
+
if (createdBindGroup !== null) {
|
|
1940
|
+
// Cloud history is a producer of the shared temporal ping-pong state even
|
|
1941
|
+
// when TAA is disabled. Stage the write at encode time; execute's finish
|
|
1942
|
+
// guard and submit transaction then give it the same abort/commit/fence
|
|
1943
|
+
// semantics as the TAA resolve.
|
|
1944
|
+
if (shader === 'cloud-layer-resolve') {
|
|
1945
|
+
const state = getTemporalGpuState(
|
|
1946
|
+
frame.frameState,
|
|
1947
|
+
frame.runtime.device,
|
|
1948
|
+
frame.runtime.deviceScope,
|
|
1949
|
+
frame.targetW,
|
|
1950
|
+
frame.targetH,
|
|
1951
|
+
true,
|
|
1952
|
+
);
|
|
1953
|
+
stageTemporalGpuSubmit(state);
|
|
1954
|
+
frame.frameState.temporalGpuState = state;
|
|
1955
|
+
}
|
|
1956
|
+
return createdBindGroup;
|
|
1957
|
+
}
|
|
1958
|
+
return undefined;
|
|
1959
|
+
}
|
|
1635
1960
|
if (descriptor?.values.fullscreen === true && isTemporalFullscreenBinding(descriptor.values)) {
|
|
1636
1961
|
const shader = descriptor.values.shader;
|
|
1637
1962
|
if (typeof shader !== 'string') return undefined;
|
|
@@ -1646,11 +1971,9 @@ function resolveTargetBindings(
|
|
|
1646
1971
|
);
|
|
1647
1972
|
if (fullscreen === null || fullscreen.sampler === null) return undefined;
|
|
1648
1973
|
const inputTarget = input.resolveTarget(descriptor.values.input as never);
|
|
1649
|
-
|
|
1650
|
-
if (inputTarget === undefined || temporalTarget === undefined) return undefined;
|
|
1974
|
+
if (inputTarget === undefined) return undefined;
|
|
1651
1975
|
const inputView = input.resources.textureView(inputTarget.view);
|
|
1652
|
-
|
|
1653
|
-
if (!inputView.ok || !temporalView.ok) return undefined;
|
|
1976
|
+
if (!inputView.ok) return undefined;
|
|
1654
1977
|
const layout = pipeline.getBindGroupLayout?.(1);
|
|
1655
1978
|
if (layout === undefined) return undefined;
|
|
1656
1979
|
const depth = input.resolveTarget(descriptor.values.depth as never);
|
|
@@ -1669,13 +1992,41 @@ function resolveTargetBindings(
|
|
|
1669
1992
|
if (depth !== undefined && (depthView === undefined || fullscreen.depthSampler === null)) {
|
|
1670
1993
|
return undefined;
|
|
1671
1994
|
}
|
|
1995
|
+
|
|
1996
|
+
const paramsBuffer = frame.runtime.getPostProcessParamsBuffer?.(shader);
|
|
1997
|
+
if (entry.params !== undefined && paramsBuffer === undefined) return undefined;
|
|
1998
|
+
if (entry.params !== undefined && paramsBuffer !== undefined) {
|
|
1999
|
+
const data = frame.postProcessParams.get(shader) ?? entry.params.defaultValue;
|
|
2000
|
+
if (data.byteLength !== entry.params.byteSize) return undefined;
|
|
2001
|
+
const written = frame.runtime.device.queue.writeBuffer(paramsBuffer, 0, data);
|
|
2002
|
+
if (!written.ok) return undefined;
|
|
2003
|
+
}
|
|
2004
|
+
|
|
2005
|
+
if (!isTemporalFullscreenBinding(descriptor.values)) {
|
|
2006
|
+
return (
|
|
2007
|
+
createFullscreenBindGroup(
|
|
2008
|
+
frame.runtime.device,
|
|
2009
|
+
layout,
|
|
2010
|
+
inputView.value,
|
|
2011
|
+
fullscreen.sampler,
|
|
2012
|
+
paramsBuffer,
|
|
2013
|
+
depthView ?? null,
|
|
2014
|
+
fullscreen.depthSampler,
|
|
2015
|
+
) ?? undefined
|
|
2016
|
+
);
|
|
2017
|
+
}
|
|
2018
|
+
|
|
2019
|
+
const temporalTarget = input.resolveTarget(descriptor.values.temporal as never);
|
|
2020
|
+
if (temporalTarget === undefined) return undefined;
|
|
2021
|
+
const temporalView = input.resources.textureView(temporalTarget.view);
|
|
2022
|
+
if (!temporalView.ok) return undefined;
|
|
1672
2023
|
return (
|
|
1673
2024
|
createFullscreenBindGroup(
|
|
1674
2025
|
frame.runtime.device,
|
|
1675
2026
|
layout,
|
|
1676
2027
|
inputView.value,
|
|
1677
2028
|
fullscreen.sampler,
|
|
1678
|
-
|
|
2029
|
+
paramsBuffer,
|
|
1679
2030
|
depthView ?? null,
|
|
1680
2031
|
fullscreen.depthSampler,
|
|
1681
2032
|
[{ binding: fullscreen.extraColorBindings[0] ?? 5, view: temporalView.value }],
|
|
@@ -1753,15 +2104,35 @@ function resolveTargetBindings(
|
|
|
1753
2104
|
return created.value;
|
|
1754
2105
|
}
|
|
1755
2106
|
|
|
1756
|
-
function retire(
|
|
2107
|
+
export function retire(
|
|
1757
2108
|
frameState: RenderFrameState,
|
|
1758
2109
|
graph: CompiledRenderGraph<RenderPipelineFrame>,
|
|
1759
2110
|
): void {
|
|
2111
|
+
if (frameState.retiredCompiledFrameGraphs.has(graph)) return;
|
|
1760
2112
|
frameState.retiredCompiledFrameGraphs.add(graph);
|
|
1761
|
-
graph
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
2113
|
+
setGraphGenerationRetiring(frameState, graph);
|
|
2114
|
+
const failures = graphRetirementFailureSet(frameState);
|
|
2115
|
+
const retirement = graph.retire();
|
|
2116
|
+
// retire() synchronously moves graph-owned resources to pending before its
|
|
2117
|
+
// queue-fence await. Capture that overlap at the lifecycle event, rather
|
|
2118
|
+
// than waiting for a later inspection call.
|
|
2119
|
+
observeGraphGenerationAllocation(frameState);
|
|
2120
|
+
retirement
|
|
2121
|
+
.then((result) => {
|
|
2122
|
+
if (result.ok) {
|
|
2123
|
+
failures?.delete(graph);
|
|
2124
|
+
setGraphGenerationRetirementResult(frameState, graph, true);
|
|
2125
|
+
} else {
|
|
2126
|
+
failures?.add(graph);
|
|
2127
|
+
setGraphGenerationRetirementResult(frameState, graph, false);
|
|
2128
|
+
}
|
|
2129
|
+
frameState.retiredCompiledFrameGraphs.delete(graph);
|
|
2130
|
+
})
|
|
2131
|
+
.catch(() => {
|
|
2132
|
+
failures?.add(graph);
|
|
2133
|
+
setGraphGenerationRetirementResult(frameState, graph, false);
|
|
2134
|
+
frameState.retiredCompiledFrameGraphs.delete(graph);
|
|
2135
|
+
});
|
|
1765
2136
|
}
|
|
1766
2137
|
|
|
1767
2138
|
/**
|
|
@@ -1838,6 +2209,54 @@ export function settleDepthOfFieldGraphCandidate(
|
|
|
1838
2209
|
frameState.depthOfFieldCandidateGraph = null;
|
|
1839
2210
|
}
|
|
1840
2211
|
|
|
2212
|
+
/**
|
|
2213
|
+
* Settle an ordinary graph replacement at the same submit barrier as the
|
|
2214
|
+
* barrel mapping. Resize, camera topology, and post-process enable/disable
|
|
2215
|
+
* all replace the compiled graph; a failed command must restore that graph so
|
|
2216
|
+
* the retained mapping still describes the pixels that are actually shown.
|
|
2217
|
+
*/
|
|
2218
|
+
export function settleBarrelDistortionGraphCandidate(
|
|
2219
|
+
frameState: RenderFrameState,
|
|
2220
|
+
submitted: boolean,
|
|
2221
|
+
): void {
|
|
2222
|
+
const candidate = frameState.barrelDistortionCandidateGraph ?? null;
|
|
2223
|
+
if (candidate === null) return;
|
|
2224
|
+
const previous = frameState.barrelDistortionPreviousGraph ?? null;
|
|
2225
|
+
const sharedWithSpecializedOwner =
|
|
2226
|
+
frameState.depthOfFieldCandidateGraph === candidate ||
|
|
2227
|
+
frameState.volumetricFogCandidateGraph === candidate;
|
|
2228
|
+
if (submitted) {
|
|
2229
|
+
if (!sharedWithSpecializedOwner && previous !== null && previous !== candidate) {
|
|
2230
|
+
retire(frameState, previous);
|
|
2231
|
+
}
|
|
2232
|
+
} else {
|
|
2233
|
+
if (!sharedWithSpecializedOwner) {
|
|
2234
|
+
if (candidate !== previous) retire(frameState, candidate);
|
|
2235
|
+
frameState.compiledFrameGraph = previous;
|
|
2236
|
+
frameState.compiledFrameGraphTopologyKey =
|
|
2237
|
+
frameState.barrelDistortionPreviousGraphKey ?? null;
|
|
2238
|
+
if (frameState.barrelDistortionPreviousPerFrameGraph === undefined) {
|
|
2239
|
+
delete frameState.perFrameGraph;
|
|
2240
|
+
} else {
|
|
2241
|
+
frameState.perFrameGraph = frameState.barrelDistortionPreviousPerFrameGraph;
|
|
2242
|
+
}
|
|
2243
|
+
frameState.graphGeneration = frameState.barrelDistortionPreviousGraphGeneration ?? 0;
|
|
2244
|
+
frameState.compiledFrameGraphGeneration =
|
|
2245
|
+
frameState.barrelDistortionPreviousCompiledGraphGeneration ?? 0;
|
|
2246
|
+
frameState.standardLightingGraphSignature =
|
|
2247
|
+
frameState.barrelDistortionPreviousStandardLightingGraphSignature ?? '';
|
|
2248
|
+
}
|
|
2249
|
+
frameState.barrelDistortionGraphResolution = previous === null ? 'accepted' : 'retained';
|
|
2250
|
+
}
|
|
2251
|
+
frameState.barrelDistortionPreviousGraph = null;
|
|
2252
|
+
frameState.barrelDistortionPreviousGraphKey = null;
|
|
2253
|
+
frameState.barrelDistortionPreviousPerFrameGraph = undefined;
|
|
2254
|
+
frameState.barrelDistortionPreviousGraphGeneration = 0;
|
|
2255
|
+
frameState.barrelDistortionPreviousCompiledGraphGeneration = 0;
|
|
2256
|
+
frameState.barrelDistortionPreviousStandardLightingGraphSignature = '';
|
|
2257
|
+
frameState.barrelDistortionCandidateGraph = null;
|
|
2258
|
+
}
|
|
2259
|
+
|
|
1841
2260
|
export function ensureCompiledFrameGraph(
|
|
1842
2261
|
internals: RenderSystemInternals,
|
|
1843
2262
|
frameState: RenderFrameState,
|
|
@@ -1859,8 +2278,11 @@ export function ensureCompiledFrameGraph(
|
|
|
1859
2278
|
onRecoveryError?: (error: unknown) => void,
|
|
1860
2279
|
ssr?: SsrSpatialAdmission,
|
|
1861
2280
|
renderExtent?: RenderExtent,
|
|
2281
|
+
surfaceMediumActive?: boolean,
|
|
1862
2282
|
analyticFog = false,
|
|
2283
|
+
cloudShadowResolution?: number,
|
|
1863
2284
|
): CompiledRenderGraph<RenderPipelineFrame> | null {
|
|
2285
|
+
frameState.barrelDistortionGraphResolution = 'retained';
|
|
1864
2286
|
const featureMetrics = mutableFeatureGraphInspection(internals);
|
|
1865
2287
|
featureMetrics.ensureCalls += 1;
|
|
1866
2288
|
const requestedStandardLightingSignature = standardLightingTopologySignature(standardLighting);
|
|
@@ -1878,10 +2300,16 @@ export function ensureCompiledFrameGraph(
|
|
|
1878
2300
|
: { ...camera, depthOfField: frameDepthOfField };
|
|
1879
2301
|
const lastKnownGood = (): CompiledRenderGraph<RenderPipelineFrame> | null =>
|
|
1880
2302
|
frameState.compiledFrameGraph !== null &&
|
|
2303
|
+
frameState.compiledFrameGraphTopologyKey !== null &&
|
|
1881
2304
|
!hasSubmissionSensitiveFeatures(getRenderFeatureGraphState(internals).plans) &&
|
|
1882
2305
|
frameState.standardLightingGraphSignature === requestedStandardLightingSignature
|
|
1883
2306
|
? frameState.compiledFrameGraph
|
|
1884
2307
|
: null;
|
|
2308
|
+
const retainLastKnownGood = (): CompiledRenderGraph<RenderPipelineFrame> | null => {
|
|
2309
|
+
const graph = lastKnownGood();
|
|
2310
|
+
if (graph !== null) frameState.barrelDistortionGraphResolution = 'retained';
|
|
2311
|
+
return graph;
|
|
2312
|
+
};
|
|
1885
2313
|
const surfaceWidth = Math.max(1, width);
|
|
1886
2314
|
const surfaceHeight = Math.max(1, height);
|
|
1887
2315
|
const featurePlans = featureGraphCandidate?.plans ?? getRenderFeatureGraphState(internals).plans;
|
|
@@ -1893,8 +2321,15 @@ export function ensureCompiledFrameGraph(
|
|
|
1893
2321
|
if (featureGraphCandidate !== undefined) {
|
|
1894
2322
|
recordRenderFeatureCandidateEvent(internals, featureGraphCandidate, 'rejected');
|
|
1895
2323
|
}
|
|
1896
|
-
return volumeTopologyCandidate ? null :
|
|
2324
|
+
return volumeTopologyCandidate ? null : retainLastKnownGood();
|
|
1897
2325
|
}
|
|
2326
|
+
const cloudHistoryDemand = projectedFeaturePlans.value.some(
|
|
2327
|
+
(execution) =>
|
|
2328
|
+
execution.featureIdentity === CLOUD_LAYER_FEATURE_IDENTITY &&
|
|
2329
|
+
execution.passes.some(
|
|
2330
|
+
(pass) => pass.name === 'cloud-layer-transport' || pass.name === 'cloud-layer-resolve',
|
|
2331
|
+
),
|
|
2332
|
+
);
|
|
1898
2333
|
const nextPlanRevision = updateRenderFeaturePlanRevision(
|
|
1899
2334
|
featureMetrics.planRevisionState,
|
|
1900
2335
|
featurePlans,
|
|
@@ -1925,6 +2360,7 @@ export function ensureCompiledFrameGraph(
|
|
|
1925
2360
|
standardLighting,
|
|
1926
2361
|
ssr,
|
|
1927
2362
|
renderExtent,
|
|
2363
|
+
surfaceMediumActive,
|
|
1928
2364
|
analyticFog,
|
|
1929
2365
|
);
|
|
1930
2366
|
if (!topologyResult.ok) {
|
|
@@ -1934,7 +2370,7 @@ export function ensureCompiledFrameGraph(
|
|
|
1934
2370
|
if (featureGraphCandidate !== undefined) {
|
|
1935
2371
|
recordRenderFeatureCandidateEvent(internals, featureGraphCandidate, 'rejected');
|
|
1936
2372
|
}
|
|
1937
|
-
return volumeTopologyCandidate ? null :
|
|
2373
|
+
return volumeTopologyCandidate ? null : retainLastKnownGood();
|
|
1938
2374
|
}
|
|
1939
2375
|
const requestedPostEffects = topologyResult.value.config?.postEffects ?? [];
|
|
1940
2376
|
const featurePostProcessEntries =
|
|
@@ -1986,6 +2422,7 @@ export function ensureCompiledFrameGraph(
|
|
|
1986
2422
|
if (featureGraphCandidate !== undefined) {
|
|
1987
2423
|
recordRenderFeatureCandidateEvent(internals, featureGraphCandidate, 'rejected');
|
|
1988
2424
|
}
|
|
2425
|
+
frameState.barrelDistortionGraphResolution = 'retained';
|
|
1989
2426
|
return acceptedLkg;
|
|
1990
2427
|
}
|
|
1991
2428
|
const topology = postProcessAdmission.pending
|
|
@@ -2022,12 +2459,17 @@ export function ensureCompiledFrameGraph(
|
|
|
2022
2459
|
// so include the prepared projection's presence to invalidate a cached
|
|
2023
2460
|
// CPU-only graph when the GPU owner becomes ready, and vice versa.
|
|
2024
2461
|
gpuDrivenProjectionActive: gpuDriven !== undefined,
|
|
2462
|
+
// Cloud shadow targets are quality-derived graph resources. Include the
|
|
2463
|
+
// resolved texel grid in the cache key so a quality/resize change cannot
|
|
2464
|
+
// reuse a graph compiled for the previous allocation.
|
|
2465
|
+
cloudShadowResolution: cloudShadowResolution ?? 0,
|
|
2466
|
+
cloudHistory: cloudHistoryDemand,
|
|
2025
2467
|
// Query reservations are frame-local transport state. The projection is
|
|
2026
2468
|
// renderer-owned and read dynamically by the compiled pass, so a page
|
|
2027
2469
|
// rotation must not invalidate the graph or its cached bind groups.
|
|
2028
2470
|
occlusionQuery:
|
|
2029
2471
|
occlusion === undefined ? undefined : { active: true, sampleCount: occlusion.sampleCount },
|
|
2030
|
-
cubeCaptureSlots: cubeCaptureState?.work.
|
|
2472
|
+
cubeCaptureSlots: cubeCaptureState?.work.map((work) => work.physical.descriptor),
|
|
2031
2473
|
reflectionProbeSlots: cubeCaptureState?.reflectionProbes?.work.map((work) => [
|
|
2032
2474
|
work.probeIndex,
|
|
2033
2475
|
work.rawCaptureFace ?? -1,
|
|
@@ -2036,9 +2478,11 @@ export function ensureCompiledFrameGraph(
|
|
|
2036
2478
|
]),
|
|
2037
2479
|
});
|
|
2038
2480
|
if (frameState.compiledFrameGraph !== null && frameState.compiledFrameGraphTopologyKey === key) {
|
|
2481
|
+
frameState.barrelDistortionGraphResolution = 'accepted';
|
|
2039
2482
|
featureMetrics.reuseHits += 1;
|
|
2040
2483
|
featureMetrics.lastTopologyKey = key;
|
|
2041
2484
|
frameState.standardLightingGraphSignature = requestedStandardLightingSignature;
|
|
2485
|
+
frameState.pendingCloudHistoryActive = cloudHistoryDemand;
|
|
2042
2486
|
if (featureGraphCandidate !== undefined && !postProcessAdmission.pending) {
|
|
2043
2487
|
commitFeatureCandidate(internals, featureGraphCandidate);
|
|
2044
2488
|
} else if (featureGraphCandidate !== undefined) {
|
|
@@ -2068,9 +2512,11 @@ export function ensureCompiledFrameGraph(
|
|
|
2068
2512
|
topology.output?.autoExposure === true ? importAutoExposureGraphResources(builder) : undefined;
|
|
2069
2513
|
if (autoExposureResources !== undefined && !autoExposureResources.ok) {
|
|
2070
2514
|
internals.errorRegistry.fire(autoExposureResources.error);
|
|
2071
|
-
featureGraphCandidate?.onRejected?.();
|
|
2072
2515
|
discardPendingStandardOutput();
|
|
2073
|
-
|
|
2516
|
+
if (featureGraphCandidate !== undefined) {
|
|
2517
|
+
recordRenderFeatureCandidateEvent(internals, featureGraphCandidate, 'rejected');
|
|
2518
|
+
}
|
|
2519
|
+
return retainLastKnownGood();
|
|
2074
2520
|
}
|
|
2075
2521
|
const lutResources =
|
|
2076
2522
|
topology.output?.colorLut === true
|
|
@@ -2114,20 +2560,25 @@ export function ensureCompiledFrameGraph(
|
|
|
2114
2560
|
: undefined;
|
|
2115
2561
|
if (lutResources !== undefined && !lutResources.ok) {
|
|
2116
2562
|
internals.errorRegistry.fire(lutResources.error);
|
|
2117
|
-
featureGraphCandidate?.onRejected?.();
|
|
2118
2563
|
discardPendingStandardOutput();
|
|
2119
|
-
|
|
2564
|
+
if (featureGraphCandidate !== undefined) {
|
|
2565
|
+
recordRenderFeatureCandidateEvent(internals, featureGraphCandidate, 'rejected');
|
|
2566
|
+
}
|
|
2567
|
+
return retainLastKnownGood();
|
|
2120
2568
|
}
|
|
2121
2569
|
const taaHistory = camera.antialias === 'taa' ? importTemporalHistoryTargets(builder) : undefined;
|
|
2570
|
+
const cloudHistory = cloudHistoryDemand ? importCloudHistoryTargets(builder) : undefined;
|
|
2122
2571
|
const targetCoverage =
|
|
2123
2572
|
camera.dynamicResolution === undefined || topology.extent === undefined
|
|
2124
2573
|
? undefined
|
|
2125
2574
|
: createTargetCoverageAttachment(builder, topology.extent);
|
|
2126
2575
|
if (targetCoverage !== undefined && !targetCoverage.ok) {
|
|
2127
2576
|
internals.errorRegistry.fire(targetCoverage.error);
|
|
2128
|
-
featureGraphCandidate?.onRejected?.();
|
|
2129
2577
|
discardPendingStandardOutput();
|
|
2130
|
-
|
|
2578
|
+
if (featureGraphCandidate !== undefined) {
|
|
2579
|
+
recordRenderFeatureCandidateEvent(internals, featureGraphCandidate, 'rejected');
|
|
2580
|
+
}
|
|
2581
|
+
return retainLastKnownGood();
|
|
2131
2582
|
}
|
|
2132
2583
|
const ssrHistory = ssr?.status === 'admitted' ? importSsrHistoryTargets(builder) : undefined;
|
|
2133
2584
|
const featureProjection = createRenderFeatureProjectionState();
|
|
@@ -2161,8 +2612,10 @@ export function ensureCompiledFrameGraph(
|
|
|
2161
2612
|
: {}),
|
|
2162
2613
|
...(standardLighting === undefined ? {} : { standardLighting }),
|
|
2163
2614
|
capabilities: { rgba16floatRenderable: internals.device.caps.rgba16floatRenderable },
|
|
2615
|
+
...(cloudShadowResolution === undefined ? {} : { cloudShadowResolution }),
|
|
2164
2616
|
...(occlusion === undefined ? {} : { occlusion }),
|
|
2165
2617
|
...(taaHistory === undefined ? {} : { taaHistory }),
|
|
2618
|
+
...(cloudHistory === undefined ? {} : { cloudHistory }),
|
|
2166
2619
|
...(targetCoverage?.ok === true ? { targetCoverage: targetCoverage.value } : {}),
|
|
2167
2620
|
...(ssrHistory === undefined ? {} : { ssrHistory }),
|
|
2168
2621
|
encodeTransmissionMip: ({ pass, resources, source }) => {
|
|
@@ -2178,6 +2631,7 @@ export function ensureCompiledFrameGraph(
|
|
|
2178
2631
|
builder,
|
|
2179
2632
|
target.format,
|
|
2180
2633
|
target.sampleCount,
|
|
2634
|
+
() => frameState.surfaceSubmissionObservation,
|
|
2181
2635
|
target.additionalColorFormats,
|
|
2182
2636
|
);
|
|
2183
2637
|
},
|
|
@@ -2198,23 +2652,42 @@ export function ensureCompiledFrameGraph(
|
|
|
2198
2652
|
semanticTargets = [],
|
|
2199
2653
|
namedTargets = {},
|
|
2200
2654
|
standardSurfaceAccesses = [],
|
|
2655
|
+
featureSelectionOrPlacement,
|
|
2656
|
+
passNames = [],
|
|
2201
2657
|
) => {
|
|
2202
|
-
|
|
2658
|
+
const selection =
|
|
2659
|
+
featureSelectionOrPlacement !== undefined &&
|
|
2660
|
+
typeof featureSelectionOrPlacement !== 'string'
|
|
2661
|
+
? featureSelectionOrPlacement
|
|
2662
|
+
: undefined;
|
|
2663
|
+
const placement =
|
|
2664
|
+
typeof featureSelectionOrPlacement === 'string' ? featureSelectionOrPlacement : 'post';
|
|
2665
|
+
const include = selection?.include === undefined ? undefined : new Set(selection.include);
|
|
2666
|
+
const exclude = selection?.exclude === undefined ? undefined : new Set(selection.exclude);
|
|
2667
|
+
// Forward/deferred scene lanes contribute scene plans before the
|
|
2203
2668
|
// Standard post chain has created its named input/output targets.
|
|
2204
2669
|
// Fullscreen effects (Motion Blur included) must wait for that later
|
|
2205
|
-
// call so their temporal input is resolved after TAA.
|
|
2206
|
-
//
|
|
2207
|
-
|
|
2670
|
+
// call so their temporal input is resolved after TAA. The shared
|
|
2671
|
+
// projection state below deduplicates only the execution/pass that
|
|
2672
|
+
// actually reached the graph; an empty early projection therefore
|
|
2673
|
+
// cannot reserve the later fullscreen pass.
|
|
2674
|
+
const plans = (
|
|
2208
2675
|
Object.keys(namedTargets).length === 0
|
|
2209
2676
|
? projectedFeaturePlans.value.filter(
|
|
2210
2677
|
(execution) => !fullscreenFeatureIds.has(execution.featureIdentity),
|
|
2211
2678
|
)
|
|
2212
|
-
: projectedFeaturePlans.value
|
|
2679
|
+
: projectedFeaturePlans.value
|
|
2680
|
+
)
|
|
2681
|
+
.filter((execution) => (execution.placement ?? 'post') === placement)
|
|
2682
|
+
.filter((execution) => include === undefined || include.has(execution.featureIdentity))
|
|
2683
|
+
.filter((execution) => exclude === undefined || !exclude.has(execution.featureIdentity));
|
|
2213
2684
|
if (plans.length === 0) return ok(undefined);
|
|
2214
2685
|
const resolveTarget = targetResolver(targets, semanticTargets, namedTargets);
|
|
2215
2686
|
const projected = projectPlanExecutions(builder, plans, {
|
|
2216
2687
|
state: featureProjection,
|
|
2217
2688
|
resolveTarget,
|
|
2689
|
+
placement,
|
|
2690
|
+
...(passNames.length === 0 ? {} : { passNames: new Set(passNames) }),
|
|
2218
2691
|
standardSurfaceAccesses,
|
|
2219
2692
|
resolveBindings: (input) => resolveTargetBindings(input, featurePostProcessEntries),
|
|
2220
2693
|
resolveStandardLighting: (frame, pipeline) => {
|
|
@@ -2239,7 +2712,8 @@ export function ensureCompiledFrameGraph(
|
|
|
2239
2712
|
},
|
|
2240
2713
|
reportError: (error) => reportRenderFeatureGraphError(internals, error),
|
|
2241
2714
|
});
|
|
2242
|
-
|
|
2715
|
+
if (!projected.ok) return projected;
|
|
2716
|
+
return ok(undefined);
|
|
2243
2717
|
},
|
|
2244
2718
|
contributeCubeCaptures: (environmentCube) => {
|
|
2245
2719
|
const reflectionProbes = addReflectionProbeGraphPasses(
|
|
@@ -2250,10 +2724,24 @@ export function ensureCompiledFrameGraph(
|
|
|
2250
2724
|
if (!reflectionProbes.ok) return reflectionProbes;
|
|
2251
2725
|
return cubeCaptureState === undefined
|
|
2252
2726
|
? ok(undefined)
|
|
2253
|
-
:
|
|
2727
|
+
: addTargetCaptureGraphPasses(builder, cubeCaptureState);
|
|
2254
2728
|
},
|
|
2255
2729
|
hasFeature: (identity) =>
|
|
2256
2730
|
projectedFeaturePlans.value.some((execution) => execution.featureIdentity === identity),
|
|
2731
|
+
hasFeatureWork: (identity, placement) =>
|
|
2732
|
+
projectedFeaturePlans.value.some(
|
|
2733
|
+
(execution) =>
|
|
2734
|
+
execution.featureIdentity === identity &&
|
|
2735
|
+
execution.passes.length > 0 &&
|
|
2736
|
+
(placement === undefined || (execution.placement ?? 'post') === placement),
|
|
2737
|
+
),
|
|
2738
|
+
hasFeatureRasterWork: (identity, placement) =>
|
|
2739
|
+
projectedFeaturePlans.value.some(
|
|
2740
|
+
(execution) =>
|
|
2741
|
+
execution.featureIdentity === identity &&
|
|
2742
|
+
execution.passes.some((pass) => pass.graphics !== undefined) &&
|
|
2743
|
+
(placement === undefined || (execution.placement ?? 'post') === placement),
|
|
2744
|
+
),
|
|
2257
2745
|
},
|
|
2258
2746
|
topology,
|
|
2259
2747
|
);
|
|
@@ -2261,12 +2749,11 @@ export function ensureCompiledFrameGraph(
|
|
|
2261
2749
|
featureMetrics.buildFailures += 1;
|
|
2262
2750
|
onRecoveryError?.(built.error);
|
|
2263
2751
|
internals.errorRegistry.fire(built.error);
|
|
2264
|
-
featureGraphCandidate?.onRejected?.();
|
|
2265
2752
|
discardPendingStandardOutput();
|
|
2266
2753
|
if (featureGraphCandidate !== undefined) {
|
|
2267
2754
|
recordRenderFeatureCandidateEvent(internals, featureGraphCandidate, 'rejected');
|
|
2268
2755
|
}
|
|
2269
|
-
return volumeTopologyCandidate ? null :
|
|
2756
|
+
return volumeTopologyCandidate ? null : retainLastKnownGood();
|
|
2270
2757
|
}
|
|
2271
2758
|
featureMetrics.compileAttempts += 1;
|
|
2272
2759
|
const compileStarted = typeof performance === 'undefined' ? Date.now() : performance.now();
|
|
@@ -2280,13 +2767,16 @@ export function ensureCompiledFrameGraph(
|
|
|
2280
2767
|
featureMetrics.compileFailures += 1;
|
|
2281
2768
|
onRecoveryError?.(compiled.error);
|
|
2282
2769
|
internals.errorRegistry.fire(compiled.error);
|
|
2283
|
-
featureGraphCandidate?.onRejected?.();
|
|
2284
2770
|
discardPendingStandardOutput();
|
|
2285
2771
|
if (featureGraphCandidate !== undefined) {
|
|
2286
2772
|
recordRenderFeatureCandidateEvent(internals, featureGraphCandidate, 'rejected');
|
|
2287
2773
|
}
|
|
2288
|
-
return
|
|
2774
|
+
return retainLastKnownGood();
|
|
2289
2775
|
}
|
|
2776
|
+
// Register the generation before publishing it. The owner observes the
|
|
2777
|
+
// overlap while the previous graph is still live, even if a queue fence
|
|
2778
|
+
// retires that graph before the next public inspect() call.
|
|
2779
|
+
trackGraphGeneration(frameState, compiled.value);
|
|
2290
2780
|
const previous = frameState.compiledFrameGraph;
|
|
2291
2781
|
const depthOfFieldReplacement =
|
|
2292
2782
|
(frameState.depthOfFieldCandidateGraph === null ||
|
|
@@ -2314,8 +2804,22 @@ export function ensureCompiledFrameGraph(
|
|
|
2314
2804
|
frameState.depthOfFieldPreviousStandardLightingGraphSignature =
|
|
2315
2805
|
frameState.standardLightingGraphSignature;
|
|
2316
2806
|
frameState.depthOfFieldCandidateGraph = compiled.value;
|
|
2807
|
+
} else if (compiled.value !== previous) {
|
|
2808
|
+
// Keep the complete accepted graph projection until queue submission.
|
|
2809
|
+
// This covers barrel enable/disable, output resize, and camera topology
|
|
2810
|
+
// changes without introducing a second resource owner.
|
|
2811
|
+
frameState.barrelDistortionPreviousGraph = previous;
|
|
2812
|
+
frameState.barrelDistortionPreviousGraphKey = frameState.compiledFrameGraphTopologyKey;
|
|
2813
|
+
frameState.barrelDistortionPreviousPerFrameGraph = frameState.perFrameGraph;
|
|
2814
|
+
frameState.barrelDistortionPreviousGraphGeneration = frameState.graphGeneration;
|
|
2815
|
+
frameState.barrelDistortionPreviousCompiledGraphGeneration =
|
|
2816
|
+
frameState.compiledFrameGraphGeneration;
|
|
2817
|
+
frameState.barrelDistortionPreviousStandardLightingGraphSignature =
|
|
2818
|
+
frameState.standardLightingGraphSignature;
|
|
2819
|
+
frameState.barrelDistortionCandidateGraph = compiled.value;
|
|
2317
2820
|
}
|
|
2318
2821
|
frameState.compiledFrameGraph = compiled.value;
|
|
2822
|
+
frameState.barrelDistortionGraphResolution = 'accepted';
|
|
2319
2823
|
frameState.compiledFrameGraphTopologyKey = key;
|
|
2320
2824
|
frameState.standardLightingGraphSignature = requestedStandardLightingSignature;
|
|
2321
2825
|
frameState.compiledFrameGraphGeneration += 1;
|
|
@@ -2347,99 +2851,11 @@ export function ensureCompiledFrameGraph(
|
|
|
2347
2851
|
} else if (featureGraphCandidate !== undefined) {
|
|
2348
2852
|
recordRenderFeatureCandidateEvent(internals, featureGraphCandidate, 'abandoned');
|
|
2349
2853
|
}
|
|
2350
|
-
|
|
2351
|
-
|
|
2352
|
-
}
|
|
2854
|
+
frameState.pendingCloudHistoryActive = cloudHistoryDemand;
|
|
2855
|
+
// The selected candidate owner retires the previous graph only after submit.
|
|
2353
2856
|
return compiled.value;
|
|
2354
2857
|
}
|
|
2355
2858
|
|
|
2356
|
-
/**
|
|
2357
|
-
* Project one accepted Motion Blur compute execution from the same graph and
|
|
2358
|
-
* resolved dispatch objects used by the encoder. A plan/capability candidate
|
|
2359
|
-
* without both executed passes deliberately returns no receipt.
|
|
2360
|
-
*/
|
|
2361
|
-
function deriveMotionBlurExecutionReceipt(
|
|
2362
|
-
internals: RenderSystemInternals,
|
|
2363
|
-
frameState: RenderFrameState,
|
|
2364
|
-
): MotionBlurExecutionReceipt | undefined {
|
|
2365
|
-
const graph = frameState.compiledFrameGraph;
|
|
2366
|
-
const deviceGeneration = internals.deviceScope?.generation;
|
|
2367
|
-
if (graph === null || deviceGeneration === undefined) return undefined;
|
|
2368
|
-
const info = graph.inspect();
|
|
2369
|
-
const graphPasses = new Map(info.passes.map((pass) => [pass.name, pass]));
|
|
2370
|
-
const summaryGraphPass = graphPasses.get('motion-blur-tile-summary');
|
|
2371
|
-
const reconstructGraphPass = graphPasses.get('motion-blur');
|
|
2372
|
-
if (summaryGraphPass?.kind !== 'compute' || reconstructGraphPass?.kind !== 'compute') {
|
|
2373
|
-
return undefined;
|
|
2374
|
-
}
|
|
2375
|
-
const planned = getRenderFeatureGraphState(internals).plans.find(
|
|
2376
|
-
(candidate) => candidate.featureIdentity === 'forgeax.motion-blur',
|
|
2377
|
-
);
|
|
2378
|
-
const execution =
|
|
2379
|
-
planned === undefined ? undefined : getRenderFeaturePlanExecutionProjection(planned);
|
|
2380
|
-
if (execution === undefined || execution.featureIdentity !== 'forgeax.motion-blur') {
|
|
2381
|
-
return undefined;
|
|
2382
|
-
}
|
|
2383
|
-
const executionPass = (name: 'motion-blur-tile-summary' | 'motion-blur') =>
|
|
2384
|
-
execution.passes.find((pass) => pass.name === name);
|
|
2385
|
-
const summary = executionPass('motion-blur-tile-summary');
|
|
2386
|
-
const reconstruct = executionPass('motion-blur');
|
|
2387
|
-
if (
|
|
2388
|
-
summary?.gpuCompute === undefined ||
|
|
2389
|
-
reconstruct?.gpuCompute === undefined ||
|
|
2390
|
-
summary.resolvedGpuCompute === undefined ||
|
|
2391
|
-
reconstruct.resolvedGpuCompute === undefined
|
|
2392
|
-
) {
|
|
2393
|
-
return undefined;
|
|
2394
|
-
}
|
|
2395
|
-
const directWorkgroups = (
|
|
2396
|
-
pass: NonNullable<typeof summary.resolvedGpuCompute>,
|
|
2397
|
-
): readonly [number, number, number] | undefined => {
|
|
2398
|
-
const dispatch = pass.dispatches[0];
|
|
2399
|
-
if (dispatch === undefined || !('workgroups' in dispatch)) return undefined;
|
|
2400
|
-
return dispatch.workgroups;
|
|
2401
|
-
};
|
|
2402
|
-
const summaryWorkgroups = directWorkgroups(summary.resolvedGpuCompute);
|
|
2403
|
-
const reconstructWorkgroups = directWorkgroups(reconstruct.resolvedGpuCompute);
|
|
2404
|
-
if (summaryWorkgroups === undefined || reconstructWorkgroups === undefined) return undefined;
|
|
2405
|
-
const outputResource = info.resources.find(
|
|
2406
|
-
(resource) =>
|
|
2407
|
-
resource.label === 'motion-blurred-color' ||
|
|
2408
|
-
reconstructGraphPass.accesses.some(
|
|
2409
|
-
(access) => access.resource === resource.label && access.usage === 'storage-write',
|
|
2410
|
-
),
|
|
2411
|
-
);
|
|
2412
|
-
if (
|
|
2413
|
-
outputResource?.descriptor.kind !== 'texture' ||
|
|
2414
|
-
outputResource.descriptor.format !== 'rgba16float'
|
|
2415
|
-
) {
|
|
2416
|
-
return undefined;
|
|
2417
|
-
}
|
|
2418
|
-
const summaryReceipt: MotionBlurExecutionPass = {
|
|
2419
|
-
name: 'motion-blur-tile-summary',
|
|
2420
|
-
kind: 'compute',
|
|
2421
|
-
entryPoint: 'tile_summary',
|
|
2422
|
-
workgroups: summaryWorkgroups,
|
|
2423
|
-
};
|
|
2424
|
-
const reconstructReceipt: MotionBlurExecutionPass = {
|
|
2425
|
-
name: 'motion-blur',
|
|
2426
|
-
kind: 'compute',
|
|
2427
|
-
entryPoint: 'reconstruct',
|
|
2428
|
-
workgroups: reconstructWorkgroups,
|
|
2429
|
-
};
|
|
2430
|
-
return Object.freeze({
|
|
2431
|
-
frameId: frameState.frameNumber,
|
|
2432
|
-
deviceGeneration,
|
|
2433
|
-
// RenderGraphBuilder generations are process-global. The renderer's
|
|
2434
|
-
// frame-state generation is the identity used by inspection and by the
|
|
2435
|
-
// same-frame admission check below, so retain that owner-scoped value.
|
|
2436
|
-
graphGeneration: frameState.graphGeneration,
|
|
2437
|
-
program: 'motion-blur-compute' as const,
|
|
2438
|
-
outputFormat: 'rgba16float' as const,
|
|
2439
|
-
passes: [summaryReceipt, reconstructReceipt] as const,
|
|
2440
|
-
});
|
|
2441
|
-
}
|
|
2442
|
-
|
|
2443
2859
|
export function executeCompiledFrameGraph(
|
|
2444
2860
|
internals: RenderSystemInternals,
|
|
2445
2861
|
frameState: RenderFrameState,
|
|
@@ -2462,21 +2878,31 @@ export function executeCompiledFrameGraph(
|
|
|
2462
2878
|
const legacySubmitCommit = typeof frameHooks === 'function' ? frameHooks : undefined;
|
|
2463
2879
|
const resolvedFrameHooks = typeof frameHooks === 'function' ? undefined : frameHooks;
|
|
2464
2880
|
const graph = frameState.compiledFrameGraph;
|
|
2881
|
+
// Recovery keeps the candidate graph for detached inspection, but clears
|
|
2882
|
+
// its topology key before the replacement canvas context is published. It
|
|
2883
|
+
// is evidence only until the first post-recovery draw compiles a new graph.
|
|
2884
|
+
// Never let that retained graph reach record/execute or queue.submit.
|
|
2885
|
+
const detachedGraph = graph !== null && frameState.compiledFrameGraphTopologyKey === null;
|
|
2465
2886
|
const rejectTemporalFrame = (): void => {
|
|
2466
2887
|
if (frameState.temporalFrameInput === undefined) return;
|
|
2467
2888
|
frameState.temporalFrameTransaction.commit({ accepted: false });
|
|
2468
2889
|
frameState.temporalFrameInput = undefined;
|
|
2469
2890
|
};
|
|
2470
|
-
if (graph === null) {
|
|
2891
|
+
if (graph === null || detachedGraph) {
|
|
2471
2892
|
timingCapture?.discard();
|
|
2472
2893
|
frameState.pendingAutoExposureState = undefined;
|
|
2473
2894
|
frameState.pendingStandardLutState = undefined;
|
|
2895
|
+
settleBarrelDistortionGraphCandidate(frameState, false);
|
|
2474
2896
|
settleVolumetricFogGraphCandidate(frameState, false);
|
|
2475
2897
|
settleDepthOfFieldGraphCandidate(frameState, false);
|
|
2476
2898
|
rejectTemporalFrame();
|
|
2477
2899
|
return false;
|
|
2478
2900
|
}
|
|
2479
|
-
const motionBlurExecution = deriveMotionBlurExecutionReceipt(
|
|
2901
|
+
const motionBlurExecution = deriveMotionBlurExecutionReceipt(
|
|
2902
|
+
internals,
|
|
2903
|
+
frameState,
|
|
2904
|
+
getRenderFeatureGraphState(internals).plans,
|
|
2905
|
+
);
|
|
2480
2906
|
const legacyTimingInstrumentation =
|
|
2481
2907
|
timingCapture === undefined ? undefined : createTimingInstrumentation(timingCapture);
|
|
2482
2908
|
const timingHost = internals as RenderSystemInternals & {
|
|
@@ -2539,6 +2965,7 @@ export function executeCompiledFrameGraph(
|
|
|
2539
2965
|
);
|
|
2540
2966
|
settleVolumetricFogGraphCandidate(frameState, false);
|
|
2541
2967
|
settleDepthOfFieldGraphCandidate(frameState, false);
|
|
2968
|
+
settleBarrelDistortionGraphCandidate(frameState, false);
|
|
2542
2969
|
return false;
|
|
2543
2970
|
}
|
|
2544
2971
|
const capturedGeneration = deviceScope?.generation;
|
|
@@ -3042,8 +3469,8 @@ export function executeCompiledFrameGraph(
|
|
|
3042
3469
|
internals.errorRegistry.fire(
|
|
3043
3470
|
new RhiError({
|
|
3044
3471
|
code: 'webgpu-runtime-error',
|
|
3045
|
-
expected: '
|
|
3046
|
-
hint: 'retry the frame after the
|
|
3472
|
+
expected: 'an admitted temporal producer stages a history write before submit',
|
|
3473
|
+
hint: 'retry the frame after the TAA or CloudLayer history pass has encoded successfully',
|
|
3047
3474
|
}),
|
|
3048
3475
|
);
|
|
3049
3476
|
return { ok: false, stage: 'finish' };
|
|
@@ -3197,6 +3624,11 @@ export function executeCompiledFrameGraph(
|
|
|
3197
3624
|
}
|
|
3198
3625
|
}
|
|
3199
3626
|
const stagedTemporalCommit = frameState.pendingTemporalCommit ?? { kind: 'none' as const };
|
|
3627
|
+
const stagedCloudHistoryActive = frameState.pendingCloudHistoryActive;
|
|
3628
|
+
if (stagedCloudHistoryActive !== undefined) {
|
|
3629
|
+
frameState.cloudHistoryActive = stagedCloudHistoryActive;
|
|
3630
|
+
delete frameState.pendingCloudHistoryActive;
|
|
3631
|
+
}
|
|
3200
3632
|
if (stagedTemporalCommit.kind !== 'none') {
|
|
3201
3633
|
frameState.lastSuccessfulTemporalView = stagedTemporalCommit.view;
|
|
3202
3634
|
}
|
|
@@ -3205,7 +3637,7 @@ export function executeCompiledFrameGraph(
|
|
|
3205
3637
|
} else if (stagedTemporalCommit.kind === 'off') {
|
|
3206
3638
|
frameState.successfulTemporalFrameIndex = 0;
|
|
3207
3639
|
}
|
|
3208
|
-
if (stagedTemporalCommit.kind === 'off') {
|
|
3640
|
+
if (stagedTemporalCommit.kind === 'off' && frameState.cloudHistoryActive !== true) {
|
|
3209
3641
|
internals.clearPostProcessPipelineCache?.('forgeax.taa-resolve');
|
|
3210
3642
|
// Retire frame-sized resources, not the device-owned prewarmed
|
|
3211
3643
|
// shader. The next TAA frame must not start an async cold compile.
|
|
@@ -3236,6 +3668,7 @@ export function executeCompiledFrameGraph(
|
|
|
3236
3668
|
frameState.pendingAtmospherePublish?.();
|
|
3237
3669
|
frameState.pendingAtmospherePublish = undefined;
|
|
3238
3670
|
onSubmitted?.(internals.device.queue.onSubmittedWorkDone());
|
|
3671
|
+
settleBarrelDistortionGraphCandidate(frameState, true);
|
|
3239
3672
|
settleVolumetricFogGraphCandidate(frameState, true);
|
|
3240
3673
|
settleDepthOfFieldGraphCandidate(frameState, true);
|
|
3241
3674
|
},
|
|
@@ -3271,11 +3704,13 @@ export function executeCompiledFrameGraph(
|
|
|
3271
3704
|
}
|
|
3272
3705
|
frameState.temporalGpuState = undefined;
|
|
3273
3706
|
}
|
|
3707
|
+
delete frameState.pendingCloudHistoryActive;
|
|
3274
3708
|
frameState.pendingTemporalCommit = { kind: 'none' };
|
|
3275
3709
|
if (frameState.environmentGeneration !== undefined) {
|
|
3276
3710
|
frameState.environmentLifecycle?.discard(frameState.environmentGeneration);
|
|
3277
3711
|
frameState.environmentGeneration = undefined;
|
|
3278
3712
|
}
|
|
3713
|
+
settleBarrelDistortionGraphCandidate(frameState, false);
|
|
3279
3714
|
settleVolumetricFogGraphCandidate(frameState, false);
|
|
3280
3715
|
settleDepthOfFieldGraphCandidate(frameState, false);
|
|
3281
3716
|
},
|
|
@@ -3283,6 +3718,7 @@ export function executeCompiledFrameGraph(
|
|
|
3283
3718
|
// The callbacks above settle the normal transaction path. Keep this guard
|
|
3284
3719
|
// for synthetic callers and any future early transaction result that does
|
|
3285
3720
|
// not enter a callback.
|
|
3721
|
+
settleBarrelDistortionGraphCandidate(frameState, transaction.ok);
|
|
3286
3722
|
settleVolumetricFogGraphCandidate(frameState, transaction.ok);
|
|
3287
3723
|
settleDepthOfFieldGraphCandidate(frameState, transaction.ok);
|
|
3288
3724
|
if (!transaction.ok) rejectTemporalFrame();
|