@forgeax/engine-render 0.1.19 → 0.1.21
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 +215 -0
- package/dist/.tsbuildinfo +1 -1
- package/dist/assembly/device-feature-admission.d.ts +18 -0
- package/dist/assembly/device-feature-admission.d.ts.map +1 -0
- package/dist/assembly/directional-shadow-inspection.d.ts +38 -0
- package/dist/assembly/directional-shadow-inspection.d.ts.map +1 -0
- package/dist/assembly/factory.d.ts +34 -20
- package/dist/assembly/factory.d.ts.map +1 -1
- package/dist/assembly/host-contract.d.ts +9 -0
- package/dist/assembly/host-contract.d.ts.map +1 -1
- package/dist/assembly/render-target-host.d.ts +46 -0
- package/dist/assembly/render-target-host.d.ts.map +1 -0
- package/dist/assets/render-asset-port.d.ts.map +1 -1
- package/dist/authoring.mjs +3 -0
- package/dist/authoring.mjs.map +1 -1
- package/dist/capture/cube-views.d.ts +21 -0
- package/dist/capture/cube-views.d.ts.map +1 -0
- package/dist/capture/scheduler.d.ts +54 -0
- package/dist/capture/scheduler.d.ts.map +1 -0
- package/dist/{chunk-RJRUS55L.mjs → chunk-5YADUCA7.mjs} +1896 -1624
- package/dist/chunk-5YADUCA7.mjs.map +1 -0
- package/dist/{chunk-LOSO4CTV.mjs → chunk-6OPXDQ2E.mjs} +423 -46
- package/dist/chunk-6OPXDQ2E.mjs.map +1 -0
- package/dist/{chunk-IPXCABEP.mjs → chunk-BXBQQKFQ.mjs} +3 -9
- package/dist/chunk-BXBQQKFQ.mjs.map +1 -0
- package/dist/chunk-FS2KNUQH.mjs +1294 -0
- package/dist/chunk-FS2KNUQH.mjs.map +1 -0
- package/dist/components/camera.d.ts +1 -0
- package/dist/components/camera.d.ts.map +1 -1
- package/dist/components/cube-camera.d.ts +20 -0
- package/dist/components/cube-camera.d.ts.map +1 -0
- package/dist/components/directional-light.d.ts +11 -2
- package/dist/components/directional-light.d.ts.map +1 -1
- package/dist/components/directional-shadow-filter.d.ts +25 -0
- package/dist/components/directional-shadow-filter.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/light-helpers.d.ts.map +1 -1
- package/dist/components/reflection-probe.d.ts +17 -0
- package/dist/components/reflection-probe.d.ts.map +1 -0
- package/dist/components/spot-light.d.ts +12 -0
- package/dist/components/spot-light.d.ts.map +1 -1
- package/dist/construct-renderer.mjs +8552 -1612
- package/dist/construct-renderer.mjs.map +1 -1
- package/dist/device/gpu-residency.d.ts +19 -2
- package/dist/device/gpu-residency.d.ts.map +1 -1
- package/dist/environment/frame.d.ts.map +1 -1
- package/dist/environment/lifecycle.d.ts +5 -0
- package/dist/environment/lifecycle.d.ts.map +1 -1
- package/dist/errors/render.d.ts +209 -93
- package/dist/errors/render.d.ts.map +1 -1
- package/dist/extract/directional-shadow-projection.d.ts +23 -0
- package/dist/extract/directional-shadow-projection.d.ts.map +1 -0
- package/dist/extract/environment.d.ts +14 -0
- package/dist/extract/environment.d.ts.map +1 -1
- package/dist/extract/visibility.d.ts.map +1 -1
- package/dist/features/fullscreen.d.ts.map +1 -1
- package/dist/features/targets.d.ts.map +1 -1
- package/dist/features/types.d.ts +10 -0
- package/dist/features/types.d.ts.map +1 -1
- package/dist/fullscreen-post-process-pass.d.ts +13 -2
- package/dist/fullscreen-post-process-pass.d.ts.map +1 -1
- package/dist/gpu-driven/batch-topology.d.ts.map +1 -1
- package/dist/gpu-driven/production-raster.d.ts +0 -1
- package/dist/gpu-driven/production-raster.d.ts.map +1 -1
- package/dist/gpu-scene.d.ts.map +1 -1
- package/dist/gpu-usage.d.ts +2 -0
- package/dist/gpu-usage.d.ts.map +1 -1
- package/dist/hdrp-buffers.d.ts +19 -17
- package/dist/hdrp-buffers.d.ts.map +1 -1
- package/dist/ibl/IblPipelineCache.d.ts +4 -0
- package/dist/ibl/IblPipelineCache.d.ts.map +1 -1
- package/dist/ibl/kernel-cache.d.ts +36 -0
- package/dist/ibl/kernel-cache.d.ts.map +1 -0
- package/dist/index.d.ts +35 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.mjs +4 -4
- package/dist/index.mjs.map +1 -1
- package/dist/inspection-types.d.ts +51 -0
- package/dist/inspection-types.d.ts.map +1 -1
- package/dist/instances-derived-bounds.d.ts +50 -0
- package/dist/instances-derived-bounds.d.ts.map +1 -0
- package/dist/internal.mjs +1 -1
- package/dist/light-buffer-layout.d.ts +30 -13
- package/dist/light-buffer-layout.d.ts.map +1 -1
- package/dist/mesh-material-bindings.d.ts +54 -0
- package/dist/mesh-material-bindings.d.ts.map +1 -1
- package/dist/pbr-pipeline.d.ts +20 -7
- package/dist/pbr-pipeline.d.ts.map +1 -1
- package/dist/pipeline/standard-forward-lane.d.ts +2 -1
- package/dist/pipeline/standard-forward-lane.d.ts.map +1 -1
- package/dist/pipeline/standard-lighting/errors.d.ts +4 -0
- package/dist/pipeline/standard-lighting/errors.d.ts.map +1 -0
- package/dist/pipeline/standard-lighting/graph.d.ts +24 -0
- package/dist/pipeline/standard-lighting/graph.d.ts.map +1 -0
- package/dist/pipeline/standard-lighting/inspection.d.ts +38 -0
- package/dist/pipeline/standard-lighting/inspection.d.ts.map +1 -0
- package/dist/pipeline/standard-lighting/layout.d.ts +28 -0
- package/dist/pipeline/standard-lighting/layout.d.ts.map +1 -0
- package/dist/pipeline/standard-lighting/light-frame.d.ts +33 -0
- package/dist/pipeline/standard-lighting/light-frame.d.ts.map +1 -0
- package/dist/pipeline/standard-lighting/membership.d.ts +14 -0
- package/dist/pipeline/standard-lighting/membership.d.ts.map +1 -0
- package/dist/pipeline/standard-lighting/prepare.d.ts +16 -0
- package/dist/pipeline/standard-lighting/prepare.d.ts.map +1 -0
- package/dist/pipeline/standard-lighting/topology.d.ts +45 -0
- package/dist/pipeline/standard-lighting/topology.d.ts.map +1 -0
- package/dist/pipeline/standard-lighting/transport.d.ts +36 -0
- package/dist/pipeline/standard-lighting/transport.d.ts.map +1 -0
- package/dist/pipeline/standard-pipeline.d.ts +4 -13
- package/dist/pipeline/standard-pipeline.d.ts.map +1 -1
- package/dist/pipeline/standard-post.d.ts.map +1 -1
- package/dist/pipeline/standard-profile.d.ts +12 -20
- package/dist/pipeline/standard-profile.d.ts.map +1 -1
- package/dist/pipeline-spec.d.ts +40 -7
- package/dist/pipeline-spec.d.ts.map +1 -1
- package/dist/point-shadow-inspection.d.ts +21 -0
- package/dist/point-shadow-inspection.d.ts.map +1 -0
- package/dist/record/frame-lighting.d.ts +29 -32
- package/dist/record/frame-lighting.d.ts.map +1 -1
- package/dist/record/frame-snapshot.d.ts +65 -15
- package/dist/record/frame-snapshot.d.ts.map +1 -1
- package/dist/record/frame-targets.d.ts +5 -0
- package/dist/record/frame-targets.d.ts.map +1 -1
- package/dist/record/frame.d.ts +12 -5
- package/dist/record/frame.d.ts.map +1 -1
- package/dist/record/gpu-pass-timing/contract.d.ts +96 -0
- package/dist/record/gpu-pass-timing/contract.d.ts.map +1 -0
- package/dist/record/gpu-pass-timing/errors.d.ts +18 -0
- package/dist/record/gpu-pass-timing/errors.d.ts.map +1 -0
- package/dist/record/gpu-pass-timing/index.d.ts +8 -0
- package/dist/record/gpu-pass-timing/index.d.ts.map +1 -0
- package/dist/record/gpu-pass-timing/parser.d.ts +11 -0
- package/dist/record/gpu-pass-timing/parser.d.ts.map +1 -0
- package/dist/record/gpu-pass-timing/session.d.ts +43 -0
- package/dist/record/gpu-pass-timing/session.d.ts.map +1 -0
- package/dist/record/gpu-timing.d.ts +37 -0
- package/dist/record/gpu-timing.d.ts.map +1 -0
- package/dist/record/main-pass-geometry.d.ts.map +1 -1
- package/dist/record/main-pass-material.d.ts +23 -2
- package/dist/record/main-pass-material.d.ts.map +1 -1
- package/dist/record/main-pass-sprite-draws.d.ts.map +1 -1
- package/dist/record/main-pass.d.ts +2 -0
- package/dist/record/main-pass.d.ts.map +1 -1
- package/dist/record/render-context.d.ts +48 -3
- package/dist/record/render-context.d.ts.map +1 -1
- package/dist/record/shadow-pass.d.ts.map +1 -1
- package/dist/record/skybox-post-pass.d.ts.map +1 -1
- package/dist/record/typed-frame-graph.d.ts +81 -5
- package/dist/record/typed-frame-graph.d.ts.map +1 -1
- package/dist/record/view-ubo.d.ts +7 -4
- package/dist/record/view-ubo.d.ts.map +1 -1
- package/dist/reflection/filter.d.ts +22 -0
- package/dist/reflection/filter.d.ts.map +1 -0
- package/dist/reflection/gpu-table.d.ts +25 -0
- package/dist/reflection/gpu-table.d.ts.map +1 -0
- package/dist/reflection/projection.d.ts +91 -0
- package/dist/reflection/projection.d.ts.map +1 -0
- package/dist/render-contract.d.ts +114 -7
- package/dist/render-contract.d.ts.map +1 -1
- package/dist/render-data.d.ts +10 -6
- package/dist/render-data.d.ts.map +1 -1
- package/dist/render-graph-primitives.d.ts +1 -0
- package/dist/render-graph-primitives.d.ts.map +1 -1
- package/dist/render-pipeline.d.ts +78 -2
- package/dist/render-pipeline.d.ts.map +1 -1
- package/dist/render-system-extract.d.ts +113 -20
- package/dist/render-system-extract.d.ts.map +1 -1
- package/dist/render-system.d.ts +24 -3
- package/dist/render-system.d.ts.map +1 -1
- package/dist/renderer-inspect.d.ts +29 -0
- package/dist/renderer-inspect.d.ts.map +1 -0
- package/dist/renderer.d.ts +43 -0
- package/dist/renderer.d.ts.map +1 -0
- package/dist/scene/render-scene.d.ts +14 -0
- package/dist/scene/render-scene.d.ts.map +1 -1
- package/dist/shadow-atlas.d.ts +3 -3
- package/dist/shadow-atlas.d.ts.map +1 -1
- package/dist/ssao-buffers.d.ts +3 -0
- package/dist/ssao-buffers.d.ts.map +1 -1
- package/dist/targets/contracts.d.ts +66 -0
- package/dist/targets/contracts.d.ts.map +1 -0
- package/dist/targets/graph-projection.d.ts +29 -0
- package/dist/targets/graph-projection.d.ts.map +1 -0
- package/dist/targets/material-source.d.ts +34 -0
- package/dist/targets/material-source.d.ts.map +1 -0
- package/dist/targets/owner.d.ts +32 -0
- package/dist/targets/owner.d.ts.map +1 -0
- package/dist/targets/physical.d.ts +18 -0
- package/dist/targets/physical.d.ts.map +1 -0
- package/dist/targets/readback.d.ts +39 -0
- package/dist/targets/readback.d.ts.map +1 -0
- package/dist/temporal/frame.d.ts +44 -0
- package/dist/temporal/frame.d.ts.map +1 -0
- package/dist/temporal/index.mjs +3 -3
- package/dist/typed-render-graph-primitives.d.ts +6 -1
- package/dist/typed-render-graph-primitives.d.ts.map +1 -1
- package/dist/typed-shadow-atlas.d.ts +10 -0
- package/dist/typed-shadow-atlas.d.ts.map +1 -0
- package/dist/typed-shadow-passes.d.ts +1 -1
- package/dist/typed-shadow-passes.d.ts.map +1 -1
- package/dist/volume/capability.d.ts +57 -0
- package/dist/volume/capability.d.ts.map +1 -0
- package/dist/volume/component.d.ts +61 -0
- package/dist/volume/component.d.ts.map +1 -0
- package/dist/volume/extract.d.ts +11 -0
- package/dist/volume/extract.d.ts.map +1 -0
- package/dist/volume/inspection.d.ts +38 -0
- package/dist/volume/inspection.d.ts.map +1 -0
- package/dist/volume/passes.d.ts +38 -0
- package/dist/volume/passes.d.ts.map +1 -0
- package/dist/volume/recovery.d.ts +38 -0
- package/dist/volume/recovery.d.ts.map +1 -0
- package/dist/volume/resources.d.ts +57 -0
- package/dist/volume/resources.d.ts.map +1 -0
- package/dist/volume/temporal.d.ts +35 -0
- package/dist/volume/temporal.d.ts.map +1 -0
- package/package.json +20 -20
- package/src/__tests__/bloom-exact-zero.unit.test.ts +48 -19
- package/src/__tests__/bloom-lifecycle.integration.test.ts +41 -13
- package/src/__tests__/camera-target-consumption.unit.test.ts +53 -0
- package/src/__tests__/cluster-binner.unit.test.ts +35 -0
- package/src/__tests__/cluster-grid-default-surface.unit.test.ts +7 -2
- package/src/__tests__/cube-camera-scheduler.unit.test.ts +70 -0
- package/src/__tests__/cube-camera-single-submit.perf.test.ts +75 -0
- package/src/__tests__/cube-camera-view-matrices.unit.test.ts +41 -0
- package/src/__tests__/cube-camera-vocabulary.unit.test.ts +47 -0
- package/src/__tests__/cube-camera.integration.test.ts +42 -0
- package/src/__tests__/device-feature-admission.unit.test.ts +73 -0
- package/src/__tests__/direct-light-snapshot.unit.test.ts +3 -3
- package/src/__tests__/docs-gate-green.unit.test.ts +38 -0
- package/src/__tests__/factory-contract.integration.test.ts +255 -29
- package/src/__tests__/fog-component.unit.test.ts +67 -0
- package/src/__tests__/fog.integration.test.ts +86 -0
- package/src/__tests__/fullscreen-feature-plan.unit.test.ts +37 -0
- package/src/__tests__/gpu-driven-indirect-raster-evidence.ts +10 -9
- package/src/__tests__/gpu-driven-indirect-raster.dawn.test.ts +17 -1
- package/src/__tests__/gpu-driven-production.integration.test.ts +16 -17
- package/src/__tests__/gpu-driven-view-graph.integration.test.ts +12 -4
- package/src/__tests__/gpu-pass-timing-browser-runner.ts +281 -0
- package/src/__tests__/gpu-pass-timing-coexistence.integration.test.ts +80 -0
- package/src/__tests__/gpu-pass-timing-contract.unit.test.ts +243 -0
- package/src/__tests__/gpu-pass-timing-exact-zero.unit.test.ts +131 -0
- package/src/__tests__/gpu-pass-timing-lifecycle.integration.test.ts +230 -0
- package/src/__tests__/gpu-pass-timing-observation.unit.test.ts +233 -0
- package/src/__tests__/gpu-pass-timing-session.unit.test.ts +438 -0
- package/src/__tests__/gpu-pass-timing.browser.test.ts +26 -0
- package/src/__tests__/gpu-pass-timing.rhi-null.unit.test.ts +125 -0
- package/src/__tests__/hdrp-group2-visibility.unit.test.ts +24 -0
- package/src/__tests__/instances-culling.integration.test.ts +94 -0
- package/src/__tests__/instances-derived-bounds.unit.test.ts +118 -0
- package/src/__tests__/ktx2-basis-gpu-consumer.dawn.test.ts +14 -14
- package/src/__tests__/material-observation.integration.test.ts +101 -0
- package/src/__tests__/mesh-buffer-usage-surface.unit.test.ts +1 -1
- package/src/__tests__/pbr-view-layout.unit.test.ts +16 -0
- package/src/__tests__/point-shadow-inspection.unit.test.ts +60 -0
- package/src/__tests__/public-surface.test-d.ts +10 -0
- package/src/__tests__/reflection-probe-authoring.unit.test.ts +71 -0
- package/src/__tests__/reflection-probe-filter.unit.test.ts +54 -0
- package/src/__tests__/reflection-probe-ibl-topology.unit.test.ts +45 -0
- package/src/__tests__/reflection-probe-pass-encode.integration.test.ts +101 -0
- package/src/__tests__/reflection-probe-performance.perf.test.ts +60 -0
- package/src/__tests__/reflection-probe-recovery.integration.test.ts +55 -0
- package/src/__tests__/reflection-probe-selection.unit.test.ts +46 -0
- package/src/__tests__/render-error-code-owner.test-d.ts +23 -3
- package/src/__tests__/render-feature-docs.unit.test.ts +1 -1
- package/src/__tests__/render-target-admission.unit.test.ts +80 -0
- package/src/__tests__/render-target-graph-projection.unit.test.ts +102 -0
- package/src/__tests__/render-target-inspection.unit.test.ts +52 -0
- package/src/__tests__/render-target-material-source.test-d.ts +30 -0
- package/src/__tests__/render-target-material-source.unit.test.ts +97 -0
- package/src/__tests__/render-target-owner-placement.unit.test.ts +203 -0
- package/src/__tests__/render-target-owner.unit.test.ts +122 -0
- package/src/__tests__/render-target-probe-soak.perf.test.ts +94 -0
- package/src/__tests__/render-target-public-schema.json +107 -0
- package/src/__tests__/render-target-public-schema.unit.test.ts +91 -0
- package/src/__tests__/render-target-public-surface.test-d.ts +83 -0
- package/src/__tests__/render-target-readback.integration.test.ts +90 -0
- package/src/__tests__/render-target-recovery.integration.test.ts +85 -0
- package/src/__tests__/renderer-factory-material-contract.unit.test.ts +76 -0
- package/src/__tests__/renderer-frame-transaction.integration.test.ts +1 -1
- package/src/__tests__/renderer-lifecycle.integration.test.ts +14 -0
- package/src/__tests__/shader-stage-surface.unit.test.ts +19 -4
- package/src/__tests__/skin-motion-regression.unit.test.ts +132 -0
- package/src/__tests__/skinned-shadow-caster.test.ts +32 -2
- package/src/__tests__/standard-cluster-capability.integration.test.ts +63 -0
- package/src/__tests__/standard-cluster-transport.unit.test.ts +121 -0
- package/src/__tests__/standard-cluster-variant-resolution.unit.test.ts +232 -0
- package/src/__tests__/standard-clustered-pipeline.unit.test.ts +8 -5
- package/src/__tests__/standard-lighting-inspection.integration.test.ts +138 -0
- package/src/__tests__/standard-lighting-ssot.unit.test.ts +18 -0
- package/src/__tests__/standard-lighting-write.unit.test.ts +377 -0
- package/src/__tests__/standard-lighting.integration.test.ts +67 -0
- package/src/__tests__/standard-pipeline.dawn.test.ts +206 -5
- package/src/__tests__/standard-pipeline.integration.test.ts +181 -150
- package/src/__tests__/standard-probe-binding.unit.test.ts +25 -0
- package/src/__tests__/standard-profile-oracle.unit.test.ts +23 -36
- package/src/__tests__/typed-pipeline-topology.unit.test.ts +395 -14
- package/src/__tests__/urp-pipeline-targets.unit.test.ts +2 -2
- package/src/__tests__/visibility-resolver.unit.test.ts +15 -0
- package/src/__tests__/volume-optics-oracle.unit.test.ts +85 -0
- package/src/__tests__/volumetric-fog-budget-recovery.integration.test.ts +655 -0
- package/src/__tests__/volumetric-fog-component.unit.test.ts +71 -0
- package/src/__tests__/volumetric-fog-composite-stage-readback.dawn.test.ts +376 -0
- package/src/__tests__/volumetric-fog-errors.unit.test.ts +51 -0
- package/src/__tests__/volumetric-fog-inspection.unit.test.ts +77 -0
- package/src/__tests__/volumetric-fog-light-capability.unit.test.ts +19 -0
- package/src/__tests__/volumetric-fog-light-consumers.integration.test.ts +18 -0
- package/src/__tests__/volumetric-fog-light-errors.unit.test.ts +17 -0
- package/src/__tests__/volumetric-fog-light-topology.unit.test.ts +21 -0
- package/src/__tests__/volumetric-fog-light-transaction.integration.test.ts +53 -0
- package/src/__tests__/volumetric-fog-m9-watcher.integration.test.ts +27 -0
- package/src/__tests__/volumetric-fog-point-light-owner.integration.test.ts +44 -0
- package/src/__tests__/volumetric-fog-point-spot-accumulation.integration.test.ts +49 -0
- package/src/__tests__/volumetric-fog-point-spot-contract.unit.test.ts +28 -0
- package/src/__tests__/volumetric-fog-point-spot-lkg.integration.test.ts +65 -0
- package/src/__tests__/volumetric-fog-point-spot-selection.integration.test.ts +49 -0
- package/src/__tests__/volumetric-fog-point-spot-temporal.unit.test.ts +55 -0
- package/src/__tests__/volumetric-fog-projector-contract.unit.test.ts +22 -0
- package/src/__tests__/volumetric-fog-projector-inspection.unit.test.ts +12 -0
- package/src/__tests__/volumetric-fog-projector-surface-volume.integration.test.ts +11 -0
- package/src/__tests__/volumetric-fog-projector-transaction.integration.test.ts +26 -0
- package/src/__tests__/volumetric-fog-recovery.integration.test.ts +47 -0
- package/src/__tests__/volumetric-fog-selected-light-resolution.integration.test.ts +63 -0
- package/src/__tests__/volumetric-fog-spot-closure.integration.test.ts +26 -0
- package/src/__tests__/volumetric-fog-spot-contract.test-d.ts +21 -0
- package/src/__tests__/volumetric-fog-spot-contract.unit.test.ts +27 -0
- package/src/__tests__/volumetric-fog-spot-frame-optics.integration.test.ts +14 -0
- package/src/__tests__/volumetric-fog-spot-optics.integration.test.ts +29 -0
- package/src/__tests__/volumetric-fog-stage-readback.dawn.test.ts +550 -0
- package/src/__tests__/volumetric-fog-temporal-selected-light.unit.test.ts +33 -0
- package/src/__tests__/volumetric-fog-temporal.unit.test.ts +45 -0
- package/src/__tests__/volumetric-fog-topology.unit.test.ts +237 -0
- package/src/__tests__/volumetric-fog-transparent.integration.test.ts +27 -0
- package/src/assembly/device-feature-admission.ts +73 -0
- package/src/assembly/directional-shadow-inspection.ts +122 -0
- package/src/assembly/factory.ts +1093 -246
- package/src/assembly/host-contract.ts +25 -0
- package/src/assembly/render-target-host.ts +847 -0
- package/src/assets/asset-decoders.ts +1 -1
- package/src/assets/render-asset-port.ts +7 -1
- package/src/capture/cube-views.ts +69 -0
- package/src/capture/scheduler.ts +265 -0
- package/src/components/__tests__/schema-contract.unit.test.ts +12 -0
- package/src/components/__tests__/schema-parity.unit.test.ts +9 -0
- package/src/components/camera.ts +4 -0
- package/src/components/cube-camera.ts +52 -0
- package/src/components/directional-light.ts +22 -2
- package/src/components/directional-shadow-filter.ts +57 -0
- package/src/components/index.ts +2 -0
- package/src/components/light-helpers.ts +85 -7
- package/src/components/reflection-probe.ts +49 -0
- package/src/components/spot-light.ts +22 -3
- package/src/device/gpu-residency.ts +168 -58
- package/src/environment/frame.ts +6 -24
- package/src/environment/lifecycle.ts +12 -0
- package/src/errors/render.ts +405 -143
- package/src/extract/directional-shadow-projection.ts +61 -0
- package/src/extract/environment.ts +57 -0
- package/src/extract/visibility.ts +25 -1
- package/src/features/fullscreen.ts +3 -0
- package/src/features/targets.ts +4 -1
- package/src/features/types.ts +10 -0
- package/src/fullscreen-post-process-pass.ts +43 -2
- package/src/gpu-driven/batch-topology.ts +1 -0
- package/src/gpu-driven/production-raster.ts +1 -3
- package/src/gpu-scene.ts +8 -1
- package/src/gpu-usage.ts +2 -0
- package/src/hdrp-buffers.ts +165 -59
- package/src/ibl/IblPipelineCache.ts +11 -0
- package/src/ibl/kernel-cache.ts +88 -0
- package/src/index.ts +186 -1
- package/src/inspection-types.ts +56 -0
- package/src/instances-derived-bounds.ts +171 -0
- package/src/light-buffer-layout.ts +74 -26
- package/src/mesh-material-bindings.ts +132 -0
- package/src/pbr-pipeline.ts +139 -27
- package/src/pipeline/standard-forward-lane.ts +65 -15
- package/src/pipeline/standard-lighting/errors.ts +6 -0
- package/src/pipeline/standard-lighting/graph.ts +157 -0
- package/src/pipeline/standard-lighting/inspection.ts +88 -0
- package/src/pipeline/standard-lighting/layout.ts +31 -0
- package/src/pipeline/standard-lighting/light-frame.ts +34 -0
- package/src/pipeline/standard-lighting/membership.ts +43 -0
- package/src/pipeline/standard-lighting/prepare.ts +37 -0
- package/src/pipeline/standard-lighting/topology.ts +120 -0
- package/src/pipeline/standard-lighting/transport.ts +77 -0
- package/src/pipeline/standard-pipeline.ts +141 -192
- package/src/pipeline/standard-post.ts +26 -7
- package/src/pipeline/standard-profile.ts +23 -30
- package/src/pipeline-spec.ts +84 -21
- package/src/point-shadow-inspection.ts +55 -0
- package/src/record/__tests__/temporal-payload.unit.test.ts +42 -1
- package/src/record/__tests__/transparent-group2-selection.unit.test.ts +73 -0
- package/src/record/__tests__/view-ubo-layout.unit.test.ts +40 -0
- package/src/record/frame-lighting.ts +470 -516
- package/src/record/frame-snapshot.ts +76 -28
- package/src/record/frame-targets.ts +23 -2
- package/src/record/frame.ts +1169 -79
- package/src/record/gpu-pass-timing/contract.ts +180 -0
- package/src/record/gpu-pass-timing/errors.ts +34 -0
- package/src/record/gpu-pass-timing/index.ts +37 -0
- package/src/record/gpu-pass-timing/parser.ts +97 -0
- package/src/record/gpu-pass-timing/session.ts +938 -0
- package/src/record/gpu-timing.ts +233 -0
- package/src/record/main-pass-geometry.ts +120 -80
- package/src/record/main-pass-material.ts +101 -11
- package/src/record/main-pass-sprite-draws.ts +54 -25
- package/src/record/main-pass.ts +71 -15
- package/src/record/render-context.ts +77 -0
- package/src/record/shadow-pass.ts +104 -66
- package/src/record/skybox-post-pass.ts +20 -4
- package/src/record/typed-frame-graph.ts +1016 -32
- package/src/record/view-ubo.ts +63 -28
- package/src/reflection/filter.ts +81 -0
- package/src/reflection/gpu-table.ts +44 -0
- package/src/reflection/projection.ts +281 -0
- package/src/render-contract.ts +147 -4
- package/src/render-data.ts +50 -22
- package/src/render-graph-primitives.ts +9 -4
- package/src/render-pipeline.ts +161 -2
- package/src/render-system-extract.ts +886 -103
- package/src/render-system.ts +1174 -66
- package/src/renderer-inspect.ts +66 -0
- package/src/renderer.ts +222 -0
- package/src/scene/render-scene.ts +117 -9
- package/src/shadow-atlas.ts +5 -5
- package/src/ssao-buffers.ts +9 -2
- package/src/targets/contracts.ts +182 -0
- package/src/targets/graph-projection.ts +169 -0
- package/src/targets/material-source.ts +143 -0
- package/src/targets/owner.ts +214 -0
- package/src/targets/physical.ts +18 -0
- package/src/targets/readback.ts +153 -0
- package/src/temporal/frame.ts +128 -0
- package/src/transmission/__tests__/standard-transmission.dawn.test.ts +61 -23
- package/src/typed-render-graph-primitives.ts +34 -2
- package/src/typed-shadow-atlas.ts +17 -0
- package/src/typed-shadow-passes.ts +47 -40
- package/src/volume/capability.ts +173 -0
- package/src/volume/component.ts +110 -0
- package/src/volume/extract.ts +21 -0
- package/src/volume/inspection.ts +78 -0
- package/src/volume/passes.ts +686 -0
- package/src/volume/recovery.ts +86 -0
- package/src/volume/resources.ts +236 -0
- package/src/volume/temporal.ts +89 -0
- package/dist/chunk-IPXCABEP.mjs.map +0 -1
- package/dist/chunk-LOSO4CTV.mjs.map +0 -1
- package/dist/chunk-RJRUS55L.mjs.map +0 -1
- package/dist/chunk-YTQ5C7YQ.mjs +0 -584
- package/dist/chunk-YTQ5C7YQ.mjs.map +0 -1
|
@@ -3,12 +3,18 @@ import {
|
|
|
3
3
|
type CompiledRenderGraph,
|
|
4
4
|
type GraphResourceResolver,
|
|
5
5
|
RenderGraphBuilder,
|
|
6
|
+
RenderGraphError,
|
|
7
|
+
type RenderGraphPassInstrumentation,
|
|
8
|
+
type RenderGraphPassInstrumentationScope,
|
|
6
9
|
} from '@forgeax/engine-render-graph';
|
|
7
10
|
import type {
|
|
11
|
+
BindGroup,
|
|
8
12
|
BindGroupLayout,
|
|
13
|
+
Buffer,
|
|
9
14
|
CommandBuffer,
|
|
10
15
|
RenderPipeline,
|
|
11
16
|
RhiCommandEncoder,
|
|
17
|
+
Sampler,
|
|
12
18
|
Texture,
|
|
13
19
|
TextureFormat,
|
|
14
20
|
TextureView,
|
|
@@ -28,10 +34,13 @@ import type {
|
|
|
28
34
|
RenderFeatureGraphTargetResolver,
|
|
29
35
|
} from '../features/render-graph-raster';
|
|
30
36
|
import { isRenderFeatureTargetHandle } from '../features/targets';
|
|
37
|
+
import type { PostProcessShaderEntry } from '../fullscreen-post-process-pass';
|
|
31
38
|
import {
|
|
32
39
|
buildFullscreenPostProcessPass,
|
|
33
40
|
createFullscreenBindGroup,
|
|
34
41
|
isTemporalFullscreenBinding,
|
|
42
|
+
postProcessShaderEntrySignature,
|
|
43
|
+
postProcessShaderModuleLabel,
|
|
35
44
|
} from '../fullscreen-post-process-pass';
|
|
36
45
|
import type { PreparedGpuDrivenFrame } from '../gpu-driven/production-raster';
|
|
37
46
|
import {
|
|
@@ -40,14 +49,21 @@ import {
|
|
|
40
49
|
GPU_TEXTURE_USAGE_RENDER_ATTACHMENT,
|
|
41
50
|
GPU_TEXTURE_USAGE_TEXTURE_BINDING,
|
|
42
51
|
} from '../gpu-texture-usage';
|
|
43
|
-
import {
|
|
52
|
+
import {
|
|
53
|
+
type StandardTopologyInputValue,
|
|
54
|
+
standardLightingTopologySignature,
|
|
55
|
+
} from '../pipeline/standard-lighting/topology';
|
|
56
|
+
import { resolveVolumetricFogProfile, STANDARD_PIPELINE_ID } from '../pipeline/standard-profile';
|
|
44
57
|
import type { CameraSnapshot } from '../render-contract';
|
|
45
58
|
import type {
|
|
46
59
|
RenderPipelineFeatureTarget,
|
|
47
60
|
RenderPipelineFrame,
|
|
48
61
|
RenderPipelineTopology,
|
|
49
62
|
} from '../render-pipeline';
|
|
50
|
-
import type { ExtractedLights } from '../render-system-extract';
|
|
63
|
+
import type { ExtractedLights, ExtractedVolumetricFog } from '../render-system-extract';
|
|
64
|
+
import { SHADOW_ATLAS_DEFAULT_FACE_SIZE, SHADOW_ATLAS_DEFAULT_LAYERS } from '../shadow-atlas';
|
|
65
|
+
import type { RenderTarget } from '../targets/contracts';
|
|
66
|
+
import type { RenderTargetPhysical } from '../targets/physical';
|
|
51
67
|
import {
|
|
52
68
|
abortTemporalGpuSubmit,
|
|
53
69
|
commitTemporalGpuSubmit,
|
|
@@ -60,9 +76,19 @@ import {
|
|
|
60
76
|
} from '../temporal/gpu';
|
|
61
77
|
import { isSceneDataTarget } from '../temporal/scene-data';
|
|
62
78
|
import type { TransmissionDemand } from '../transmission/projection';
|
|
79
|
+
import { hasVolumetricFogCapability } from '../volume/capability';
|
|
80
|
+
import { deriveVolumetricFogExtent, deriveVolumetricFogResolvedExtent } from '../volume/resources';
|
|
63
81
|
import { buildPerFrameBindGroups } from './frame-lighting';
|
|
64
82
|
import { getTextureIdentity, type RenderFrameState } from './frame-snapshot';
|
|
65
|
-
import type {
|
|
83
|
+
import type { GpuPassTimingPassIdentity } from './gpu-pass-timing/contract.js';
|
|
84
|
+
import type { GpuPassTimingCapture, GpuPassTimingSession } from './gpu-pass-timing/session.js';
|
|
85
|
+
import type { GpuTimingCapture, VolumeTimingTimestampWrites } from './gpu-timing';
|
|
86
|
+
import { encodeMainPass } from './main-pass';
|
|
87
|
+
import type {
|
|
88
|
+
_InternalRenderPipelineContext,
|
|
89
|
+
PipelineState,
|
|
90
|
+
RenderSystemInternals,
|
|
91
|
+
} from './render-context';
|
|
66
92
|
import { resolveSurfaceFormatPair, resolveSurfaceProfile } from './render-context';
|
|
67
93
|
|
|
68
94
|
export interface TemporalGraphCapabilities {
|
|
@@ -203,6 +229,465 @@ export function createTemporalGraphRoster(input: {
|
|
|
203
229
|
};
|
|
204
230
|
}
|
|
205
231
|
|
|
232
|
+
export interface CubeCaptureGraphWork {
|
|
233
|
+
readonly target: RenderTarget;
|
|
234
|
+
readonly faceIndex: number;
|
|
235
|
+
readonly physical: RenderTargetPhysical;
|
|
236
|
+
readonly faceCamera: import('../render-contract').CameraSnapshot;
|
|
237
|
+
readonly viewBindGroupDynamicOffset: number;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
export interface CubeCaptureGraphState {
|
|
241
|
+
work: readonly CubeCaptureGraphWork[];
|
|
242
|
+
reflectionProbes?: ReflectionProbeGraphState;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
export interface ReflectionProbeFilterGraphWork {
|
|
246
|
+
readonly probeIndex: number;
|
|
247
|
+
readonly faceIndex: number;
|
|
248
|
+
readonly mipLevel: number;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
export interface ReflectionProbeFilterGraphState {
|
|
252
|
+
readonly work: readonly ReflectionProbeFilterGraphWork[];
|
|
253
|
+
readonly maxStepsPerFrame: number;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
export interface ReflectionProbeGraphWork {
|
|
257
|
+
readonly probeIndex: number;
|
|
258
|
+
readonly rawTexture: Texture;
|
|
259
|
+
readonly rawCubeView: TextureView;
|
|
260
|
+
readonly rawFaceViews: readonly TextureView[];
|
|
261
|
+
readonly rawDepthTexture: Texture;
|
|
262
|
+
readonly rawCaptureFace: number | undefined;
|
|
263
|
+
readonly rawDepthView: TextureView;
|
|
264
|
+
readonly rawSize: number;
|
|
265
|
+
readonly faceCamera?: import('../render-contract').CameraSnapshot;
|
|
266
|
+
readonly viewBindGroupDynamicOffset?: number;
|
|
267
|
+
readonly filteredTexture: Texture;
|
|
268
|
+
readonly filteredCubeView: TextureView;
|
|
269
|
+
readonly filteredFaceViewsByMip: readonly (readonly TextureView[])[];
|
|
270
|
+
readonly outputFormat: TextureFormat;
|
|
271
|
+
readonly sampler: Sampler;
|
|
272
|
+
readonly filterPipeline: RenderPipeline;
|
|
273
|
+
readonly filterGroup0: BindGroup | undefined;
|
|
274
|
+
readonly filterGroup1: BindGroup;
|
|
275
|
+
readonly cubeVertexBuffer: Buffer;
|
|
276
|
+
readonly filteredSize: number;
|
|
277
|
+
readonly step: ReflectionProbeFilterGraphWork | undefined;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
export interface ReflectionProbeGraphState {
|
|
281
|
+
readonly work: readonly ReflectionProbeGraphWork[];
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
export function boundedReflectionProbeFilterWork(
|
|
285
|
+
state: ReflectionProbeFilterGraphState,
|
|
286
|
+
): readonly ReflectionProbeFilterGraphWork[] {
|
|
287
|
+
return state.work.slice(0, Math.max(0, state.maxStepsPerFrame));
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
function renderTargetMipCount(work: CubeCaptureGraphWork): number {
|
|
291
|
+
const { descriptor } = work.physical;
|
|
292
|
+
return descriptor.mipLevels === 1
|
|
293
|
+
? 1
|
|
294
|
+
: Math.floor(Math.log2(Math.max(descriptor.width, descriptor.height))) + 1;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
function addCubeCaptureGraphPasses(
|
|
298
|
+
builder: RenderGraphBuilder<RenderPipelineFrame>,
|
|
299
|
+
state: CubeCaptureGraphState,
|
|
300
|
+
): Result<void, RenderGraphError> {
|
|
301
|
+
for (let index = 0; index < state.work.length; index += 1) {
|
|
302
|
+
const slot = index;
|
|
303
|
+
const initial = state.work[slot];
|
|
304
|
+
if (initial === undefined) continue;
|
|
305
|
+
const current = (): CubeCaptureGraphWork => state.work[slot] ?? initial;
|
|
306
|
+
const texture = builder.importTexture(
|
|
307
|
+
`cube-capture.${slot}.texture`,
|
|
308
|
+
{
|
|
309
|
+
format: initial.physical.descriptor.format,
|
|
310
|
+
size: {
|
|
311
|
+
width: initial.physical.descriptor.width,
|
|
312
|
+
height: initial.physical.descriptor.height,
|
|
313
|
+
depthOrArrayLayers: initial.physical.descriptor.sampleCount === 4 ? 1 : 6,
|
|
314
|
+
},
|
|
315
|
+
mipLevelCount:
|
|
316
|
+
initial.physical.descriptor.sampleCount === 4 ? 1 : renderTargetMipCount(initial),
|
|
317
|
+
sampleCount: initial.physical.descriptor.sampleCount,
|
|
318
|
+
dimension: '2d',
|
|
319
|
+
usage: 0x10 | 0x04 | 0x01,
|
|
320
|
+
},
|
|
321
|
+
() => current().physical.colorTextures[current().faceIndex] ?? initial.physical.texture,
|
|
322
|
+
);
|
|
323
|
+
if (!texture.ok) return texture;
|
|
324
|
+
const color = builder.importView(
|
|
325
|
+
texture.value,
|
|
326
|
+
{
|
|
327
|
+
label: `cube-capture.${slot}.color`,
|
|
328
|
+
dimension: '2d',
|
|
329
|
+
baseMipLevel: 0,
|
|
330
|
+
mipLevelCount: 1,
|
|
331
|
+
baseArrayLayer: initial.physical.descriptor.sampleCount === 4 ? 0 : initial.faceIndex,
|
|
332
|
+
arrayLayerCount: 1,
|
|
333
|
+
},
|
|
334
|
+
() =>
|
|
335
|
+
current().physical.faceViews[current().faceIndex] ??
|
|
336
|
+
initial.physical.faceViews[initial.faceIndex] ??
|
|
337
|
+
initial.physical.view,
|
|
338
|
+
);
|
|
339
|
+
if (!color.ok) return color;
|
|
340
|
+
const depthTexture = builder.importTexture(
|
|
341
|
+
`cube-capture.${slot}.depth-texture`,
|
|
342
|
+
{
|
|
343
|
+
format: 'depth24plus-stencil8',
|
|
344
|
+
size: {
|
|
345
|
+
width: initial.physical.descriptor.width,
|
|
346
|
+
height: initial.physical.descriptor.height,
|
|
347
|
+
depthOrArrayLayers: initial.physical.descriptor.sampleCount === 4 ? 1 : 6,
|
|
348
|
+
},
|
|
349
|
+
mipLevelCount: 1,
|
|
350
|
+
sampleCount: initial.physical.descriptor.sampleCount,
|
|
351
|
+
dimension: '2d',
|
|
352
|
+
usage: 0x10,
|
|
353
|
+
},
|
|
354
|
+
() => current().physical.depthTextures[current().faceIndex] as Texture,
|
|
355
|
+
);
|
|
356
|
+
if (!depthTexture.ok) return depthTexture;
|
|
357
|
+
const depth = builder.importView(
|
|
358
|
+
depthTexture.value,
|
|
359
|
+
{
|
|
360
|
+
label: `cube-capture.${slot}.depth`,
|
|
361
|
+
dimension: '2d',
|
|
362
|
+
baseArrayLayer: initial.physical.descriptor.sampleCount === 4 ? 0 : initial.faceIndex,
|
|
363
|
+
arrayLayerCount: 1,
|
|
364
|
+
},
|
|
365
|
+
() => current().physical.depthViews[current().faceIndex] as TextureView,
|
|
366
|
+
);
|
|
367
|
+
if (!depth.ok) return depth;
|
|
368
|
+
const resolveTexture =
|
|
369
|
+
initial.physical.descriptor.sampleCount === 4
|
|
370
|
+
? builder.importTexture(
|
|
371
|
+
`cube-capture.${slot}.resolve-texture`,
|
|
372
|
+
{
|
|
373
|
+
format: initial.physical.descriptor.format,
|
|
374
|
+
size: {
|
|
375
|
+
width: initial.physical.descriptor.width,
|
|
376
|
+
height: initial.physical.descriptor.height,
|
|
377
|
+
depthOrArrayLayers: 6,
|
|
378
|
+
},
|
|
379
|
+
mipLevelCount: renderTargetMipCount(initial),
|
|
380
|
+
sampleCount: 1,
|
|
381
|
+
dimension: '2d',
|
|
382
|
+
usage: 0x10 | 0x04 | 0x01,
|
|
383
|
+
},
|
|
384
|
+
() =>
|
|
385
|
+
current().physical.resolveTexture ??
|
|
386
|
+
initial.physical.resolveTexture ??
|
|
387
|
+
initial.physical.texture,
|
|
388
|
+
)
|
|
389
|
+
: undefined;
|
|
390
|
+
if (resolveTexture !== undefined && !resolveTexture.ok) return resolveTexture;
|
|
391
|
+
const resolve =
|
|
392
|
+
resolveTexture === undefined
|
|
393
|
+
? undefined
|
|
394
|
+
: builder.importView(
|
|
395
|
+
resolveTexture.value,
|
|
396
|
+
{
|
|
397
|
+
label: `cube-capture.${slot}.resolve`,
|
|
398
|
+
dimension: '2d',
|
|
399
|
+
baseMipLevel: 0,
|
|
400
|
+
mipLevelCount: 1,
|
|
401
|
+
baseArrayLayer: initial.faceIndex,
|
|
402
|
+
arrayLayerCount: 1,
|
|
403
|
+
},
|
|
404
|
+
() =>
|
|
405
|
+
current().physical.resolveFaceViews[current().faceIndex] ??
|
|
406
|
+
initial.physical.resolveFaceViews[initial.faceIndex] ??
|
|
407
|
+
initial.physical.resolveView,
|
|
408
|
+
);
|
|
409
|
+
if (resolve !== undefined && !resolve.ok) return resolve;
|
|
410
|
+
const added = builder.addRasterPass(`cube-capture-face.${slot}`, {
|
|
411
|
+
accesses: [
|
|
412
|
+
{ resource: color.value, usage: 'color-attachment' },
|
|
413
|
+
{ resource: depth.value, usage: 'depth-stencil-write' },
|
|
414
|
+
...(resolve === undefined
|
|
415
|
+
? []
|
|
416
|
+
: [{ resource: resolve.value, usage: 'color-attachment' as const }]),
|
|
417
|
+
],
|
|
418
|
+
colorAttachments: [
|
|
419
|
+
{
|
|
420
|
+
view: color.value,
|
|
421
|
+
...(resolve === undefined ? {} : { resolveTarget: resolve.value }),
|
|
422
|
+
loadOp: 'clear',
|
|
423
|
+
storeOp: 'store',
|
|
424
|
+
clearValue: () => {
|
|
425
|
+
return { r: 0, g: 0, b: 0, a: 1 };
|
|
426
|
+
},
|
|
427
|
+
},
|
|
428
|
+
],
|
|
429
|
+
depthStencilAttachment: {
|
|
430
|
+
view: depth.value,
|
|
431
|
+
depthClearValue: 1,
|
|
432
|
+
depthLoadOp: 'clear',
|
|
433
|
+
depthStoreOp: 'store',
|
|
434
|
+
stencilClearValue: 0,
|
|
435
|
+
stencilLoadOp: 'clear',
|
|
436
|
+
stencilStoreOp: 'store',
|
|
437
|
+
},
|
|
438
|
+
encode: ({ pass, frame, resources }) => {
|
|
439
|
+
const internal = frame as _InternalRenderPipelineContext;
|
|
440
|
+
const captureColor = resources.textureView(color.value);
|
|
441
|
+
if (!captureColor.ok) return;
|
|
442
|
+
const captureDepth = resources.textureView(depth.value);
|
|
443
|
+
if (!captureDepth.ok) return;
|
|
444
|
+
const captureResolve =
|
|
445
|
+
resolve === undefined ? undefined : resources.textureView(resolve.value);
|
|
446
|
+
if (resolve !== undefined && (captureResolve === undefined || !captureResolve.ok)) return;
|
|
447
|
+
const captureResolveView = captureResolve?.ok ? captureResolve.value : null;
|
|
448
|
+
const captureContext = {
|
|
449
|
+
...internal,
|
|
450
|
+
gpuDrivenEntityKeys: new Set<number>(),
|
|
451
|
+
camera: current().faceCamera,
|
|
452
|
+
// Cube faces are raw scene captures, not display-camera HDR output.
|
|
453
|
+
// Select the PSO against the actual target attachment so an LDR
|
|
454
|
+
// cube target is rendered by a compatible forward pipeline.
|
|
455
|
+
tonemapActive: false,
|
|
456
|
+
skyboxActive: false,
|
|
457
|
+
transparentColorFormat: initial.physical.descriptor.format as GPUTextureFormat,
|
|
458
|
+
msaaActive: initial.physical.descriptor.sampleCount === 4,
|
|
459
|
+
viewBindGroupDynamicOffset: current().viewBindGroupDynamicOffset,
|
|
460
|
+
geometryColorView: captureColor.value,
|
|
461
|
+
geometryDepthView: captureDepth.value,
|
|
462
|
+
geometryColorResolveView: captureResolveView,
|
|
463
|
+
splitLdrSprite: false,
|
|
464
|
+
ldrSpritePassView: null,
|
|
465
|
+
};
|
|
466
|
+
encodeMainPass(captureContext, pass, undefined, {
|
|
467
|
+
colorViews: [captureColor.value],
|
|
468
|
+
colorFormats: [initial.physical.descriptor.format as GPUTextureFormat],
|
|
469
|
+
depthView: captureDepth.value,
|
|
470
|
+
passKind: 'forward',
|
|
471
|
+
clearColor: [0, 0, 0, 1],
|
|
472
|
+
});
|
|
473
|
+
},
|
|
474
|
+
});
|
|
475
|
+
if (!added.ok) return added;
|
|
476
|
+
}
|
|
477
|
+
return ok(undefined);
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
export function addReflectionProbeGraphPasses(
|
|
481
|
+
builder: RenderGraphBuilder<RenderPipelineFrame>,
|
|
482
|
+
state: ReflectionProbeGraphState,
|
|
483
|
+
): Result<readonly import('@forgeax/engine-render-graph').GraphAccess[], RenderGraphError> {
|
|
484
|
+
const accesses: import('@forgeax/engine-render-graph').GraphAccess[] = [];
|
|
485
|
+
for (const work of state.work) {
|
|
486
|
+
const raw = builder.importTexture(
|
|
487
|
+
`reflection-probe.${work.probeIndex}.raw`,
|
|
488
|
+
{
|
|
489
|
+
format: work.outputFormat,
|
|
490
|
+
size: { width: work.rawSize, height: work.rawSize, depthOrArrayLayers: 6 },
|
|
491
|
+
mipLevelCount: 1,
|
|
492
|
+
sampleCount: 1,
|
|
493
|
+
dimension: '2d',
|
|
494
|
+
usage: 0x10 | 0x04 | 0x01,
|
|
495
|
+
},
|
|
496
|
+
() => work.rawTexture,
|
|
497
|
+
);
|
|
498
|
+
if (!raw.ok) return raw;
|
|
499
|
+
const rawCube = builder.importView(
|
|
500
|
+
raw.value,
|
|
501
|
+
{
|
|
502
|
+
label: `reflection-probe.${work.probeIndex}.raw-cube`,
|
|
503
|
+
dimension: 'cube',
|
|
504
|
+
arrayLayerCount: 6,
|
|
505
|
+
},
|
|
506
|
+
() => work.rawCubeView,
|
|
507
|
+
);
|
|
508
|
+
if (!rawCube.ok) return rawCube;
|
|
509
|
+
const filtered = builder.importTexture(
|
|
510
|
+
`reflection-probe.${work.probeIndex}.filtered`,
|
|
511
|
+
{
|
|
512
|
+
format: work.outputFormat,
|
|
513
|
+
size: { width: work.filteredSize, height: work.filteredSize, depthOrArrayLayers: 6 },
|
|
514
|
+
mipLevelCount: work.filteredFaceViewsByMip.length,
|
|
515
|
+
sampleCount: 1,
|
|
516
|
+
dimension: '2d',
|
|
517
|
+
usage: 0x10 | 0x04 | 0x01,
|
|
518
|
+
},
|
|
519
|
+
() => work.filteredTexture,
|
|
520
|
+
);
|
|
521
|
+
if (!filtered.ok) return filtered;
|
|
522
|
+
const filteredCube = builder.importView(
|
|
523
|
+
filtered.value,
|
|
524
|
+
{
|
|
525
|
+
label: `reflection-probe.${work.probeIndex}.filtered-cube`,
|
|
526
|
+
dimension: 'cube',
|
|
527
|
+
baseMipLevel: 0,
|
|
528
|
+
mipLevelCount: work.filteredFaceViewsByMip.length,
|
|
529
|
+
arrayLayerCount: 6,
|
|
530
|
+
},
|
|
531
|
+
() => work.filteredCubeView,
|
|
532
|
+
);
|
|
533
|
+
if (!filteredCube.ok) return filteredCube;
|
|
534
|
+
if (work.rawCaptureFace !== undefined) {
|
|
535
|
+
const face = work.rawCaptureFace;
|
|
536
|
+
const view = builder.importView(
|
|
537
|
+
raw.value,
|
|
538
|
+
{
|
|
539
|
+
label: `reflection-probe.${work.probeIndex}.capture-face-${face}`,
|
|
540
|
+
dimension: '2d',
|
|
541
|
+
baseArrayLayer: face,
|
|
542
|
+
arrayLayerCount: 1,
|
|
543
|
+
},
|
|
544
|
+
() => work.rawFaceViews[face] as TextureView,
|
|
545
|
+
);
|
|
546
|
+
if (!view.ok) return view;
|
|
547
|
+
const depthTexture = builder.importTexture(
|
|
548
|
+
`reflection-probe.${work.probeIndex}.capture-depth`,
|
|
549
|
+
{
|
|
550
|
+
format: 'depth24plus-stencil8',
|
|
551
|
+
size: { width: work.rawSize, height: work.rawSize, depthOrArrayLayers: 1 },
|
|
552
|
+
mipLevelCount: 1,
|
|
553
|
+
sampleCount: 1,
|
|
554
|
+
dimension: '2d',
|
|
555
|
+
usage: 0x10,
|
|
556
|
+
},
|
|
557
|
+
() => work.rawDepthTexture,
|
|
558
|
+
);
|
|
559
|
+
if (!depthTexture.ok) return depthTexture;
|
|
560
|
+
const depth = builder.importView(
|
|
561
|
+
depthTexture.value,
|
|
562
|
+
{ label: `reflection-probe.${work.probeIndex}.capture-depth-view`, dimension: '2d' },
|
|
563
|
+
() => work.rawDepthView,
|
|
564
|
+
);
|
|
565
|
+
if (!depth.ok) return depth;
|
|
566
|
+
const added = builder.addRasterPass(`reflection-probe.${work.probeIndex}.capture.${face}`, {
|
|
567
|
+
accesses: [
|
|
568
|
+
{ resource: view.value, usage: 'color-attachment' },
|
|
569
|
+
{ resource: depth.value, usage: 'depth-stencil-write' },
|
|
570
|
+
],
|
|
571
|
+
colorAttachments: [
|
|
572
|
+
{
|
|
573
|
+
view: view.value,
|
|
574
|
+
loadOp: 'clear',
|
|
575
|
+
storeOp: 'store',
|
|
576
|
+
clearValue: { r: 0, g: 0, b: 0, a: 1 },
|
|
577
|
+
},
|
|
578
|
+
],
|
|
579
|
+
depthStencilAttachment: {
|
|
580
|
+
view: depth.value,
|
|
581
|
+
depthClearValue: 1,
|
|
582
|
+
depthLoadOp: 'clear',
|
|
583
|
+
depthStoreOp: 'store',
|
|
584
|
+
stencilClearValue: 0,
|
|
585
|
+
stencilLoadOp: 'clear',
|
|
586
|
+
stencilStoreOp: 'store',
|
|
587
|
+
},
|
|
588
|
+
encode: ({ pass, frame, resources }) => {
|
|
589
|
+
const internal = frame as _InternalRenderPipelineContext;
|
|
590
|
+
const captureColor = resources.textureView(view.value);
|
|
591
|
+
const captureDepth = resources.textureView(depth.value);
|
|
592
|
+
if (!captureColor.ok || !captureDepth.ok) return;
|
|
593
|
+
if (work.faceCamera === undefined || work.viewBindGroupDynamicOffset === undefined)
|
|
594
|
+
return;
|
|
595
|
+
encodeMainPass(
|
|
596
|
+
{
|
|
597
|
+
...internal,
|
|
598
|
+
camera: work.faceCamera,
|
|
599
|
+
viewBindGroupDynamicOffset: work.viewBindGroupDynamicOffset,
|
|
600
|
+
geometryColorView: captureColor.value,
|
|
601
|
+
geometryDepthView: captureDepth.value,
|
|
602
|
+
geometryColorResolveView: null,
|
|
603
|
+
transparentColorFormat: work.outputFormat as GPUTextureFormat,
|
|
604
|
+
msaaActive: false,
|
|
605
|
+
splitLdrSprite: false,
|
|
606
|
+
ldrSpritePassView: null,
|
|
607
|
+
},
|
|
608
|
+
pass,
|
|
609
|
+
undefined,
|
|
610
|
+
{
|
|
611
|
+
colorViews: [captureColor.value],
|
|
612
|
+
colorFormats: [work.outputFormat as GPUTextureFormat],
|
|
613
|
+
depthView: captureDepth.value,
|
|
614
|
+
passKind: 'forward',
|
|
615
|
+
clearColor: [0, 0, 0, 1],
|
|
616
|
+
},
|
|
617
|
+
);
|
|
618
|
+
},
|
|
619
|
+
});
|
|
620
|
+
if (!added.ok) return added;
|
|
621
|
+
}
|
|
622
|
+
const step = work.step;
|
|
623
|
+
if (step !== undefined) {
|
|
624
|
+
const mipViews = work.filteredFaceViewsByMip[step.mipLevel];
|
|
625
|
+
const outputView = mipViews?.[step.faceIndex];
|
|
626
|
+
if (outputView === undefined) {
|
|
627
|
+
return err(
|
|
628
|
+
new RenderGraphError({
|
|
629
|
+
code: 'resource-resolution-failed',
|
|
630
|
+
expected: 'every scheduled probe mip has a filtered face view',
|
|
631
|
+
hint: 'rebuild the renderer-owned probe output before compiling the Standard graph',
|
|
632
|
+
detail: {
|
|
633
|
+
resourceLabel: `reflection-probe.${work.probeIndex}.filtered`,
|
|
634
|
+
passName: 'pmrem',
|
|
635
|
+
},
|
|
636
|
+
}),
|
|
637
|
+
);
|
|
638
|
+
}
|
|
639
|
+
const output = builder.importView(
|
|
640
|
+
filtered.value,
|
|
641
|
+
{
|
|
642
|
+
label: `reflection-probe.${work.probeIndex}.filtered-mip${step.mipLevel}-face${step.faceIndex}`,
|
|
643
|
+
dimension: '2d',
|
|
644
|
+
baseMipLevel: step.mipLevel,
|
|
645
|
+
mipLevelCount: 1,
|
|
646
|
+
baseArrayLayer: step.faceIndex,
|
|
647
|
+
arrayLayerCount: 1,
|
|
648
|
+
},
|
|
649
|
+
() => outputView,
|
|
650
|
+
);
|
|
651
|
+
if (!output.ok) return output;
|
|
652
|
+
const added = builder.addRasterPass(
|
|
653
|
+
`reflection-probe.${work.probeIndex}.pmrem.${step.mipLevel}.${step.faceIndex}`,
|
|
654
|
+
{
|
|
655
|
+
accesses: [
|
|
656
|
+
{ resource: rawCube.value, usage: 'sampled-read' },
|
|
657
|
+
{ resource: output.value, usage: 'color-attachment' },
|
|
658
|
+
],
|
|
659
|
+
colorAttachments: [
|
|
660
|
+
{
|
|
661
|
+
view: output.value,
|
|
662
|
+
loadOp: 'clear',
|
|
663
|
+
storeOp: 'store',
|
|
664
|
+
clearValue: { r: 0, g: 0, b: 0, a: 1 },
|
|
665
|
+
},
|
|
666
|
+
],
|
|
667
|
+
encode: ({ pass }) => {
|
|
668
|
+
if (work.filterGroup0 === undefined) return;
|
|
669
|
+
pass.setPipeline(work.filterPipeline);
|
|
670
|
+
pass.setBindGroup(0, work.filterGroup0);
|
|
671
|
+
pass.setBindGroup(1, work.filterGroup1);
|
|
672
|
+
pass.setVertexBuffer(0, work.cubeVertexBuffer);
|
|
673
|
+
pass.draw(6, 1, step.faceIndex * 6, 0);
|
|
674
|
+
},
|
|
675
|
+
},
|
|
676
|
+
);
|
|
677
|
+
if (!added.ok) return added;
|
|
678
|
+
}
|
|
679
|
+
accesses.push({ resource: filteredCube.value, usage: 'sampled-read' });
|
|
680
|
+
}
|
|
681
|
+
return ok(accesses);
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
export {
|
|
685
|
+
projectRenderTargetGraph,
|
|
686
|
+
type RenderTargetGraphInput,
|
|
687
|
+
type RenderTargetGraphProjection,
|
|
688
|
+
type RenderTargetGraphSubresource,
|
|
689
|
+
} from '../targets/graph-projection';
|
|
690
|
+
|
|
206
691
|
export interface RenderFeatureGraphRuntimeState {
|
|
207
692
|
plans: readonly RenderFeaturePlannedFrame[];
|
|
208
693
|
fullscreenEffects: ReadonlyMap<
|
|
@@ -227,10 +712,34 @@ export interface RenderFeatureGraphCandidate {
|
|
|
227
712
|
readonly preparedResourceKey?: string;
|
|
228
713
|
/** Release candidate-owned prepared resources when graph promotion fails. */
|
|
229
714
|
readonly onRejected?: () => void;
|
|
715
|
+
/** Publish candidate-owned runtime declarations only after graph promotion. */
|
|
716
|
+
readonly onAccepted?: () => void;
|
|
717
|
+
/** Discard candidate-only resources when a base graph is kept as fallback. */
|
|
718
|
+
readonly onAbandoned?: () => void;
|
|
230
719
|
}
|
|
231
720
|
|
|
232
721
|
const featureGraphStates = new WeakMap<RenderSystemInternals, RenderFeatureGraphRuntimeState>();
|
|
233
722
|
|
|
723
|
+
interface TimingInstrumentationState {
|
|
724
|
+
readonly instrumentation: RenderGraphPassInstrumentation<RenderPipelineFrame>;
|
|
725
|
+
setCapture(capture: GpuPassTimingCapture | undefined): void;
|
|
726
|
+
}
|
|
727
|
+
|
|
728
|
+
const timingInstrumentationStates = new WeakMap<
|
|
729
|
+
RenderSystemInternals,
|
|
730
|
+
TimingInstrumentationState
|
|
731
|
+
>();
|
|
732
|
+
|
|
733
|
+
interface VolumeTimingInstrumentationState {
|
|
734
|
+
readonly instrumentation: RenderGraphPassInstrumentation<RenderPipelineFrame>;
|
|
735
|
+
setCapture(capture: GpuTimingCapture | undefined): void;
|
|
736
|
+
}
|
|
737
|
+
|
|
738
|
+
const volumeTimingInstrumentationStates = new WeakMap<
|
|
739
|
+
RenderSystemInternals,
|
|
740
|
+
VolumeTimingInstrumentationState
|
|
741
|
+
>();
|
|
742
|
+
|
|
234
743
|
type CompiledGraphTargetAccess = CompiledRenderGraph<RenderPipelineFrame> & {
|
|
235
744
|
readonly getColorTargetDescriptor: (
|
|
236
745
|
name: string,
|
|
@@ -281,6 +790,31 @@ export function renderFeatureGraphPlanSignature(
|
|
|
281
790
|
);
|
|
282
791
|
}
|
|
283
792
|
|
|
793
|
+
/**
|
|
794
|
+
* Admit fullscreen post-processes as one chain, never as independent passes.
|
|
795
|
+
* A pass whose shader module is still compiling cannot clear a graph target and
|
|
796
|
+
* leave the remainder of the chain sampling an undefined intermediate. The
|
|
797
|
+
* renderer therefore keeps the base output-transform graph until every
|
|
798
|
+
* requested effect is ready, then admits the complete ordered chain together.
|
|
799
|
+
*/
|
|
800
|
+
export function resolvePostProcessChainAdmission(
|
|
801
|
+
effects: readonly string[],
|
|
802
|
+
isReady: (identity: string) => boolean,
|
|
803
|
+
): { readonly admitted: readonly string[]; readonly pending: boolean } {
|
|
804
|
+
// Probe every declaration even after the first miss. A single frame may
|
|
805
|
+
// introduce several effects; evaluating all of them lets the shared cache
|
|
806
|
+
// start every independent compile together instead of serialising warmup on
|
|
807
|
+
// array order.
|
|
808
|
+
let ready = true;
|
|
809
|
+
for (const identity of effects) {
|
|
810
|
+
if (!isReady(identity)) ready = false;
|
|
811
|
+
}
|
|
812
|
+
return {
|
|
813
|
+
admitted: ready ? effects : [],
|
|
814
|
+
pending: !ready,
|
|
815
|
+
};
|
|
816
|
+
}
|
|
817
|
+
|
|
284
818
|
function validateRenderFeaturePlans(
|
|
285
819
|
plans: readonly RenderFeaturePlannedFrame[],
|
|
286
820
|
): Result<readonly RenderFeaturePlanExecution[], RenderError> {
|
|
@@ -311,6 +845,10 @@ function commitFeatureCandidate(
|
|
|
311
845
|
internals: RenderSystemInternals,
|
|
312
846
|
candidate: RenderFeatureGraphCandidate,
|
|
313
847
|
): void {
|
|
848
|
+
// Publish renderer-owned declarations only after their device resources have
|
|
849
|
+
// been admitted. If the acceptance hook throws, the previously accepted
|
|
850
|
+
// graph/state pair remains visible to the caller.
|
|
851
|
+
candidate.onAccepted?.();
|
|
314
852
|
const state = getRenderFeatureGraphState(internals);
|
|
315
853
|
state.plans = candidate.plans;
|
|
316
854
|
state.fullscreenEffects = candidate.fullscreenEffects;
|
|
@@ -328,7 +866,10 @@ function topologyOf(
|
|
|
328
866
|
shadowMapSize: number | undefined,
|
|
329
867
|
gpuDriven: PreparedGpuDrivenFrame | undefined,
|
|
330
868
|
featureGraphCandidate: RenderFeatureGraphCandidate | undefined,
|
|
869
|
+
cubeCaptureState: CubeCaptureGraphState | undefined,
|
|
331
870
|
transmissionDemand: TransmissionDemand | undefined,
|
|
871
|
+
volumetricFog: ExtractedVolumetricFog | undefined,
|
|
872
|
+
standardLighting: StandardTopologyInputValue | undefined,
|
|
332
873
|
): Result<RenderPipelineTopology, RhiError> {
|
|
333
874
|
const cascadeCount = Math.max(1, Math.min(4, Math.round(lights.cascadeCount ?? 1))) as
|
|
334
875
|
| 1
|
|
@@ -353,6 +894,10 @@ function topologyOf(
|
|
|
353
894
|
...(featureGraphCandidate?.fullscreenEffects ??
|
|
354
895
|
getRenderFeatureGraphState(internals).fullscreenEffects),
|
|
355
896
|
].map(([id]) => id);
|
|
897
|
+
const featurePostEffectDeclarations = [
|
|
898
|
+
...(featureGraphCandidate?.fullscreenEffects ??
|
|
899
|
+
getRenderFeatureGraphState(internals).fullscreenEffects),
|
|
900
|
+
].map(([id, entry]) => [id, postProcessShaderEntrySignature(entry)] as const);
|
|
356
901
|
const config =
|
|
357
902
|
featurePostEffects.length === 0
|
|
358
903
|
? frameState.installedPipelineConfig
|
|
@@ -365,6 +910,21 @@ function topologyOf(
|
|
|
365
910
|
]),
|
|
366
911
|
],
|
|
367
912
|
};
|
|
913
|
+
const volumeCapability = hasVolumetricFogCapability(
|
|
914
|
+
internals.device.caps,
|
|
915
|
+
internals.volumetricFogShaders,
|
|
916
|
+
);
|
|
917
|
+
const selectedVolumeLight =
|
|
918
|
+
volumetricFog?.lightKind === 'spot'
|
|
919
|
+
? lights.spot.find((light) => light.entity === volumetricFog.lightEntity)
|
|
920
|
+
: volumetricFog?.lightKind === 'point'
|
|
921
|
+
? lights.point.find((light) => light.entity === volumetricFog.lightEntity)
|
|
922
|
+
: volumetricFog?.lightKind === 'directional' &&
|
|
923
|
+
lights.directional?.entity === volumetricFog.lightEntity
|
|
924
|
+
? lights.directional
|
|
925
|
+
: volumetricFog?.lightKind === undefined
|
|
926
|
+
? lights.directional
|
|
927
|
+
: undefined;
|
|
368
928
|
return ok({
|
|
369
929
|
pipelineId: STANDARD_PIPELINE_ID,
|
|
370
930
|
standardProfile: internals.standardProfile,
|
|
@@ -387,10 +947,13 @@ function topologyOf(
|
|
|
387
947
|
motionBlur: isMotionBlurTemporalDemand(camera.motionBlur),
|
|
388
948
|
},
|
|
389
949
|
shadow: {
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
950
|
+
directional:
|
|
951
|
+
shadowMapSize === undefined || lights.cascadeCount === undefined
|
|
952
|
+
? 'disabled'
|
|
953
|
+
: { mapSize: shadowMapSize, cascadeCount },
|
|
954
|
+
spotMapSize: shadowMapSize ?? 1024,
|
|
955
|
+
pointCount: Math.min(SHADOW_ATLAS_DEFAULT_LAYERS, lights.pointShadow.length),
|
|
956
|
+
pointFaceSize: lights.pointShadow[0]?.mapSize ?? SHADOW_ATLAS_DEFAULT_FACE_SIZE,
|
|
394
957
|
spotCount: Math.min(
|
|
395
958
|
4,
|
|
396
959
|
lights.spot.filter(
|
|
@@ -398,6 +961,47 @@ function topologyOf(
|
|
|
398
961
|
).length,
|
|
399
962
|
),
|
|
400
963
|
},
|
|
964
|
+
volumetricFog:
|
|
965
|
+
volumetricFog?.status === 'available' &&
|
|
966
|
+
volumetricFog.densityAsset?.shape.viewDimension === '3d' &&
|
|
967
|
+
camera.tonemap !== 'none' &&
|
|
968
|
+
selectedVolumeLight !== undefined &&
|
|
969
|
+
volumeCapability
|
|
970
|
+
? (() => {
|
|
971
|
+
const volumeProfile = resolveVolumetricFogProfile(internals.standardProfile ?? {});
|
|
972
|
+
return {
|
|
973
|
+
enabled: true,
|
|
974
|
+
format: volumetricFog.densityAsset.format,
|
|
975
|
+
extent: {
|
|
976
|
+
width: volumetricFog.densityAsset.shape.extent.width,
|
|
977
|
+
height: volumetricFog.densityAsset.shape.extent.height,
|
|
978
|
+
depth: volumetricFog.densityAsset.shape.extent.depth,
|
|
979
|
+
},
|
|
980
|
+
froxelExtent: deriveVolumetricFogExtent(
|
|
981
|
+
{ width, height },
|
|
982
|
+
volumeProfile.depth,
|
|
983
|
+
volumeProfile.tileSize,
|
|
984
|
+
),
|
|
985
|
+
resolvedExtent: deriveVolumetricFogResolvedExtent(
|
|
986
|
+
{ width, height },
|
|
987
|
+
volumeProfile.tileSize,
|
|
988
|
+
),
|
|
989
|
+
lightKind: volumetricFog.lightKind,
|
|
990
|
+
lightEntity: volumetricFog.lightEntity,
|
|
991
|
+
pointLightEntity: volumetricFog.pointLightEntity,
|
|
992
|
+
spotLightEntity: volumetricFog.spotLightEntity,
|
|
993
|
+
...(volumetricFog.projector === undefined
|
|
994
|
+
? {}
|
|
995
|
+
: {
|
|
996
|
+
projector: {
|
|
997
|
+
guid: volumetricFog.projector.guid,
|
|
998
|
+
generation: volumetricFog.projector.generation,
|
|
999
|
+
revision: volumetricFog.projector.revision,
|
|
1000
|
+
},
|
|
1001
|
+
}),
|
|
1002
|
+
};
|
|
1003
|
+
})()
|
|
1004
|
+
: { enabled: false },
|
|
401
1005
|
lane: {
|
|
402
1006
|
compute: internals.device.caps.compute,
|
|
403
1007
|
storageBuffer: internals.device.caps.storageBuffer,
|
|
@@ -408,10 +1012,12 @@ function topologyOf(
|
|
|
408
1012
|
plans: renderFeatureGraphPlanSignature(
|
|
409
1013
|
featureGraphCandidate?.plans ?? getRenderFeatureGraphState(internals).plans,
|
|
410
1014
|
),
|
|
411
|
-
fullscreenEffects:
|
|
1015
|
+
fullscreenEffects: featurePostEffectDeclarations,
|
|
412
1016
|
preparedResourceKey: featureGraphCandidate?.preparedResourceKey ?? '',
|
|
1017
|
+
cubeCaptureSlots: cubeCaptureState?.work.length ?? 0,
|
|
413
1018
|
}),
|
|
414
1019
|
gpuDrivenTopologySignature: gpuDriven?.topologySignature ?? '',
|
|
1020
|
+
standardLightingTopologySignature: standardLightingTopologySignature(standardLighting),
|
|
415
1021
|
transmissionDemand: transmissionDemand ?? {
|
|
416
1022
|
activeCount: 0,
|
|
417
1023
|
needsRoughMips: false,
|
|
@@ -467,14 +1073,17 @@ function targetResolver(
|
|
|
467
1073
|
};
|
|
468
1074
|
}
|
|
469
1075
|
|
|
470
|
-
function resolveTargetBindings(
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
readonly
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
1076
|
+
function resolveTargetBindings(
|
|
1077
|
+
input: {
|
|
1078
|
+
readonly frame: RenderPipelineFrame;
|
|
1079
|
+
readonly binding: import('../prepare/prepared-graphics-resolver').PreparedGraphicsResolvedResource & {
|
|
1080
|
+
readonly kind: 'bindings';
|
|
1081
|
+
};
|
|
1082
|
+
readonly resources: GraphResourceResolver;
|
|
1083
|
+
readonly resolveTarget: RenderFeatureGraphTargetResolver;
|
|
1084
|
+
},
|
|
1085
|
+
featurePostProcessEntries?: ReadonlyMap<string, PostProcessShaderEntry>,
|
|
1086
|
+
): RenderFeatureGraphBindingsResolution | undefined {
|
|
478
1087
|
const frame = input.frame as import('./render-context')._InternalRenderPipelineContext;
|
|
479
1088
|
const descriptor = input.binding.descriptor;
|
|
480
1089
|
const pipeline = input.binding.pipeline as
|
|
@@ -486,7 +1095,8 @@ function resolveTargetBindings(input: {
|
|
|
486
1095
|
if (descriptor?.values.fullscreen === true && isTemporalFullscreenBinding(descriptor.values)) {
|
|
487
1096
|
const shader = descriptor.values.shader;
|
|
488
1097
|
if (typeof shader !== 'string') return undefined;
|
|
489
|
-
const entry =
|
|
1098
|
+
const entry =
|
|
1099
|
+
featurePostProcessEntries?.get(shader) ?? frame.runtime.lookupPostProcess?.(shader);
|
|
490
1100
|
if (entry === undefined) return undefined;
|
|
491
1101
|
const fullscreen = buildFullscreenPostProcessPass(
|
|
492
1102
|
{ device: frame.runtime.device, errorRegistry: frame.runtime.errorRegistry },
|
|
@@ -576,8 +1186,10 @@ function resolveTargetBindings(input: {
|
|
|
576
1186
|
directionalShadow: frame.frameState.currentDirectionalShadowView ?? undefined,
|
|
577
1187
|
spotShadow: frame.frameState.currentSpotShadowView ?? undefined,
|
|
578
1188
|
},
|
|
1189
|
+
true,
|
|
1190
|
+
frame.standardLighting,
|
|
579
1191
|
).viewBindGroup;
|
|
580
|
-
return viewBindGroup === null ? undefined : { handle: viewBindGroup, dynamicOffsets: [0] };
|
|
1192
|
+
return viewBindGroup === null ? undefined : { handle: viewBindGroup, dynamicOffsets: [0, 0] };
|
|
581
1193
|
}
|
|
582
1194
|
const target = input.resolveTarget(sceneDepth);
|
|
583
1195
|
if (target === undefined) return undefined;
|
|
@@ -610,6 +1222,32 @@ function retire(
|
|
|
610
1222
|
.catch(() => undefined);
|
|
611
1223
|
}
|
|
612
1224
|
|
|
1225
|
+
/**
|
|
1226
|
+
* Settle a volume topology candidate after the command buffer outcome is
|
|
1227
|
+
* known. A graph that failed to encode, finish, or submit must never become
|
|
1228
|
+
* the next frame's accepted graph: retire it and restore the prior graph (or
|
|
1229
|
+
* leave the renderer without a graph when this was the first attempt).
|
|
1230
|
+
*/
|
|
1231
|
+
export function settleVolumetricFogGraphCandidate(
|
|
1232
|
+
frameState: RenderFrameState,
|
|
1233
|
+
submitted: boolean,
|
|
1234
|
+
): void {
|
|
1235
|
+
const candidate = frameState.volumetricFogCandidateGraph ?? null;
|
|
1236
|
+
if (candidate === null) return;
|
|
1237
|
+
const previous = frameState.volumetricFogPreviousGraph ?? null;
|
|
1238
|
+
const previousKey = frameState.volumetricFogPreviousGraphKey ?? null;
|
|
1239
|
+
if (submitted) {
|
|
1240
|
+
if (previous !== null && previous !== candidate) retire(frameState, previous);
|
|
1241
|
+
} else {
|
|
1242
|
+
if (candidate !== previous) retire(frameState, candidate);
|
|
1243
|
+
frameState.compiledFrameGraph = previous;
|
|
1244
|
+
frameState.compiledFrameGraphTopologyKey = previousKey;
|
|
1245
|
+
}
|
|
1246
|
+
frameState.volumetricFogPreviousGraph = null;
|
|
1247
|
+
frameState.volumetricFogPreviousGraphKey = null;
|
|
1248
|
+
frameState.volumetricFogCandidateGraph = null;
|
|
1249
|
+
}
|
|
1250
|
+
|
|
613
1251
|
export function ensureCompiledFrameGraph(
|
|
614
1252
|
internals: RenderSystemInternals,
|
|
615
1253
|
frameState: RenderFrameState,
|
|
@@ -621,9 +1259,19 @@ export function ensureCompiledFrameGraph(
|
|
|
621
1259
|
shadowMapSize: number | undefined,
|
|
622
1260
|
gpuDriven?: PreparedGpuDrivenFrame,
|
|
623
1261
|
featureGraphCandidate?: RenderFeatureGraphCandidate,
|
|
1262
|
+
cubeCaptureState?: CubeCaptureGraphState,
|
|
624
1263
|
clearOnly = false,
|
|
625
1264
|
transmissionDemand?: TransmissionDemand,
|
|
1265
|
+
volumetricFog?: ExtractedVolumetricFog,
|
|
1266
|
+
volumeTopologyCandidate = false,
|
|
1267
|
+
standardLighting?: StandardTopologyInputValue,
|
|
626
1268
|
): CompiledRenderGraph<RenderPipelineFrame> | null {
|
|
1269
|
+
const requestedStandardLightingSignature = standardLightingTopologySignature(standardLighting);
|
|
1270
|
+
const lastKnownGood = (): CompiledRenderGraph<RenderPipelineFrame> | null =>
|
|
1271
|
+
frameState.compiledFrameGraph !== null &&
|
|
1272
|
+
frameState.standardLightingGraphSignature === requestedStandardLightingSignature
|
|
1273
|
+
? frameState.compiledFrameGraph
|
|
1274
|
+
: null;
|
|
627
1275
|
const surfaceWidth = Math.max(1, width);
|
|
628
1276
|
const surfaceHeight = Math.max(1, height);
|
|
629
1277
|
const featurePlans = featureGraphCandidate?.plans ?? getRenderFeatureGraphState(internals).plans;
|
|
@@ -631,7 +1279,7 @@ export function ensureCompiledFrameGraph(
|
|
|
631
1279
|
if (!projectedFeaturePlans.ok) {
|
|
632
1280
|
reportRenderFeatureGraphError(internals, projectedFeaturePlans.error);
|
|
633
1281
|
featureGraphCandidate?.onRejected?.();
|
|
634
|
-
return
|
|
1282
|
+
return volumeTopologyCandidate ? null : lastKnownGood();
|
|
635
1283
|
}
|
|
636
1284
|
const topologyResult = topologyOf(
|
|
637
1285
|
internals,
|
|
@@ -645,19 +1293,86 @@ export function ensureCompiledFrameGraph(
|
|
|
645
1293
|
shadowMapSize,
|
|
646
1294
|
gpuDriven,
|
|
647
1295
|
featureGraphCandidate,
|
|
1296
|
+
cubeCaptureState,
|
|
648
1297
|
transmissionDemand,
|
|
1298
|
+
volumetricFog,
|
|
1299
|
+
standardLighting,
|
|
649
1300
|
);
|
|
650
1301
|
if (!topologyResult.ok) {
|
|
651
1302
|
internals.errorRegistry.fire(topologyResult.error);
|
|
652
1303
|
featureGraphCandidate?.onRejected?.();
|
|
653
|
-
return
|
|
1304
|
+
return volumeTopologyCandidate ? null : lastKnownGood();
|
|
1305
|
+
}
|
|
1306
|
+
const requestedPostEffects = topologyResult.value.config?.postEffects ?? [];
|
|
1307
|
+
const featurePostProcessEntries =
|
|
1308
|
+
featureGraphCandidate?.fullscreenEffects ??
|
|
1309
|
+
getRenderFeatureGraphState(internals).fullscreenEffects;
|
|
1310
|
+
const postProcessAdmission = resolvePostProcessChainAdmission(
|
|
1311
|
+
requestedPostEffects,
|
|
1312
|
+
(identity) => {
|
|
1313
|
+
const entry =
|
|
1314
|
+
featurePostProcessEntries.get(identity) ?? internals.lookupPostProcess?.(identity);
|
|
1315
|
+
// Preserve the existing missing-entry failure contract. The graph will
|
|
1316
|
+
// report post-process-not-found during record instead of silently
|
|
1317
|
+
// removing an authored id from the topology.
|
|
1318
|
+
if (entry === undefined) return true;
|
|
1319
|
+
const buildPipeline = internals.buildPostProcessPipeline;
|
|
1320
|
+
const getPipeline = internals.getPostProcessPipeline;
|
|
1321
|
+
if (buildPipeline === undefined || getPipeline === undefined) return true;
|
|
1322
|
+
const built = buildFullscreenPostProcessPass(
|
|
1323
|
+
{ device: internals.device, errorRegistry: internals.errorRegistry },
|
|
1324
|
+
entry,
|
|
1325
|
+
camera.antialias === 'msaa' && topologyResult.value.lane.multisample,
|
|
1326
|
+
);
|
|
1327
|
+
if (built === null) return false;
|
|
1328
|
+
return (
|
|
1329
|
+
getPipeline(
|
|
1330
|
+
identity,
|
|
1331
|
+
built.bindGroupLayout,
|
|
1332
|
+
topologyResult.value.surface.storageFormat as GPUTextureFormat,
|
|
1333
|
+
entry,
|
|
1334
|
+
) !== null
|
|
1335
|
+
);
|
|
1336
|
+
},
|
|
1337
|
+
);
|
|
1338
|
+
const acceptedLkg = lastKnownGood();
|
|
1339
|
+
if (postProcessAdmission.pending && acceptedLkg !== null) {
|
|
1340
|
+
// Do not publish a candidate whose fullscreen chain is only partially
|
|
1341
|
+
// ready. Keep the accepted graph (including its prior post-effect chain)
|
|
1342
|
+
// and retry the same feature candidate on the next frame.
|
|
1343
|
+
featureGraphCandidate?.onRejected?.();
|
|
1344
|
+
return acceptedLkg;
|
|
654
1345
|
}
|
|
655
|
-
const topology =
|
|
656
|
-
|
|
1346
|
+
const topology = postProcessAdmission.pending
|
|
1347
|
+
? {
|
|
1348
|
+
...topologyResult.value,
|
|
1349
|
+
config: {
|
|
1350
|
+
...(topologyResult.value.config ?? {}),
|
|
1351
|
+
postEffects: [],
|
|
1352
|
+
},
|
|
1353
|
+
}
|
|
1354
|
+
: topologyResult.value;
|
|
1355
|
+
const key = JSON.stringify({
|
|
1356
|
+
topology,
|
|
1357
|
+
cubeCaptureSlots: cubeCaptureState?.work.length ?? 0,
|
|
1358
|
+
reflectionProbeSlots: cubeCaptureState?.reflectionProbes?.work.map((work) => [
|
|
1359
|
+
work.probeIndex,
|
|
1360
|
+
work.rawCaptureFace ?? -1,
|
|
1361
|
+
work.step?.faceIndex ?? -1,
|
|
1362
|
+
work.step?.mipLevel ?? -1,
|
|
1363
|
+
]),
|
|
1364
|
+
});
|
|
657
1365
|
if (frameState.compiledFrameGraph !== null && frameState.compiledFrameGraphTopologyKey === key) {
|
|
658
|
-
|
|
1366
|
+
frameState.standardLightingGraphSignature = requestedStandardLightingSignature;
|
|
1367
|
+
if (featureGraphCandidate !== undefined && !postProcessAdmission.pending) {
|
|
659
1368
|
commitFeatureCandidate(internals, featureGraphCandidate);
|
|
1369
|
+
} else if (featureGraphCandidate !== undefined) {
|
|
1370
|
+
featureGraphCandidate.onAbandoned?.();
|
|
660
1371
|
}
|
|
1372
|
+
// A candidate flag only describes a possible topology replacement. When
|
|
1373
|
+
// the derived key is unchanged there is no replacement to stage: reuse the
|
|
1374
|
+
// accepted graph so dynamic volume history/imported views can advance and
|
|
1375
|
+
// a queue-submit failure can still publish the LKG diagnostic.
|
|
661
1376
|
return frameState.compiledFrameGraph;
|
|
662
1377
|
}
|
|
663
1378
|
|
|
@@ -668,6 +1383,7 @@ export function ensureCompiledFrameGraph(
|
|
|
668
1383
|
const built = frameState.activePipeline.build(
|
|
669
1384
|
{
|
|
670
1385
|
graph: builder,
|
|
1386
|
+
...(standardLighting === undefined ? {} : { standardLighting }),
|
|
671
1387
|
capabilities: { rgba16floatRenderable: internals.device.caps.rgba16floatRenderable },
|
|
672
1388
|
...(taaHistory === undefined ? {} : { taaHistory }),
|
|
673
1389
|
encodeTransmissionMip: ({ pass, resources, source }) => {
|
|
@@ -688,11 +1404,21 @@ export function ensureCompiledFrameGraph(
|
|
|
688
1404
|
const resolveTarget = targetResolver(targets, semanticTargets, namedTargets);
|
|
689
1405
|
const projected = projectPlanExecutions(builder, projectedFeaturePlans.value, {
|
|
690
1406
|
resolveTarget,
|
|
691
|
-
resolveBindings: resolveTargetBindings,
|
|
1407
|
+
resolveBindings: (input) => resolveTargetBindings(input, featurePostProcessEntries),
|
|
692
1408
|
reportError: (error) => reportRenderFeatureGraphError(internals, error),
|
|
693
1409
|
});
|
|
694
1410
|
return projected.ok ? ok(undefined) : projected;
|
|
695
1411
|
},
|
|
1412
|
+
contributeCubeCaptures: () => {
|
|
1413
|
+
const reflectionProbes = addReflectionProbeGraphPasses(
|
|
1414
|
+
builder,
|
|
1415
|
+
cubeCaptureState?.reflectionProbes ?? { work: [] },
|
|
1416
|
+
);
|
|
1417
|
+
if (!reflectionProbes.ok) return reflectionProbes;
|
|
1418
|
+
return cubeCaptureState === undefined
|
|
1419
|
+
? ok(undefined)
|
|
1420
|
+
: addCubeCaptureGraphPasses(builder, cubeCaptureState);
|
|
1421
|
+
},
|
|
696
1422
|
hasFeature: (identity) =>
|
|
697
1423
|
projectedFeaturePlans.value.some((execution) => execution.featureIdentity === identity),
|
|
698
1424
|
},
|
|
@@ -701,7 +1427,7 @@ export function ensureCompiledFrameGraph(
|
|
|
701
1427
|
if (!built.ok) {
|
|
702
1428
|
internals.errorRegistry.fire(built.error);
|
|
703
1429
|
featureGraphCandidate?.onRejected?.();
|
|
704
|
-
return
|
|
1430
|
+
return volumeTopologyCandidate ? null : lastKnownGood();
|
|
705
1431
|
}
|
|
706
1432
|
const compiled = builder.compile({
|
|
707
1433
|
device: internals.device,
|
|
@@ -710,11 +1436,18 @@ export function ensureCompiledFrameGraph(
|
|
|
710
1436
|
if (!compiled.ok) {
|
|
711
1437
|
internals.errorRegistry.fire(compiled.error);
|
|
712
1438
|
featureGraphCandidate?.onRejected?.();
|
|
713
|
-
return
|
|
1439
|
+
return lastKnownGood();
|
|
714
1440
|
}
|
|
715
1441
|
const previous = frameState.compiledFrameGraph;
|
|
1442
|
+
if (volumeTopologyCandidate) {
|
|
1443
|
+
frameState.volumetricFogPreviousGraph = previous;
|
|
1444
|
+
frameState.volumetricFogPreviousGraphKey = frameState.compiledFrameGraphTopologyKey;
|
|
1445
|
+
frameState.volumetricFogCandidateGraph = compiled.value;
|
|
1446
|
+
}
|
|
716
1447
|
frameState.compiledFrameGraph = compiled.value;
|
|
717
1448
|
frameState.compiledFrameGraphTopologyKey = key;
|
|
1449
|
+
frameState.standardLightingGraphSignature = requestedStandardLightingSignature;
|
|
1450
|
+
frameState.compiledFrameGraphGeneration += 1;
|
|
718
1451
|
const compiledTargets = compiled.value as CompiledGraphTargetAccess;
|
|
719
1452
|
frameState.graphGeneration += 1;
|
|
720
1453
|
frameState.perFrameGraph = {
|
|
@@ -724,10 +1457,12 @@ export function ensureCompiledFrameGraph(
|
|
|
724
1457
|
graphGeneration: frameState.graphGeneration,
|
|
725
1458
|
};
|
|
726
1459
|
gpuDriven?._commitResourceReplacement();
|
|
727
|
-
if (featureGraphCandidate !== undefined) {
|
|
1460
|
+
if (featureGraphCandidate !== undefined && !postProcessAdmission.pending) {
|
|
728
1461
|
commitFeatureCandidate(internals, featureGraphCandidate);
|
|
1462
|
+
} else if (featureGraphCandidate !== undefined) {
|
|
1463
|
+
featureGraphCandidate.onAbandoned?.();
|
|
729
1464
|
}
|
|
730
|
-
if (previous !== null) retire(frameState, previous);
|
|
1465
|
+
if (!volumeTopologyCandidate && previous !== null) retire(frameState, previous);
|
|
731
1466
|
return compiled.value;
|
|
732
1467
|
}
|
|
733
1468
|
|
|
@@ -737,16 +1472,69 @@ export function executeCompiledFrameGraph(
|
|
|
737
1472
|
frame: RenderPipelineFrame,
|
|
738
1473
|
encoder: RhiCommandEncoder,
|
|
739
1474
|
runPass?: import('@forgeax/engine-render-graph').RenderGraphPassRunner,
|
|
1475
|
+
readbackFaces?: readonly number[],
|
|
1476
|
+
onSubmitted?: (completed: Promise<unknown>) => void,
|
|
1477
|
+
timingCapture?: GpuTimingCapture,
|
|
740
1478
|
): boolean {
|
|
741
1479
|
const graph = frameState.compiledFrameGraph;
|
|
742
|
-
|
|
1480
|
+
const invalidatePostProcessModule = (id: string): void => {
|
|
1481
|
+
const entry = internals.lookupPostProcess?.(id);
|
|
1482
|
+
if (entry !== undefined) {
|
|
1483
|
+
internals.invalidateShaderModule?.(postProcessShaderModuleLabel(id, entry.source));
|
|
1484
|
+
}
|
|
1485
|
+
};
|
|
1486
|
+
const rejectTemporalFrame = (): void => {
|
|
1487
|
+
if (frameState.temporalFrameInput === undefined) return;
|
|
1488
|
+
frameState.temporalFrameTransaction.commit({ accepted: false });
|
|
1489
|
+
frameState.temporalFrameInput = undefined;
|
|
1490
|
+
};
|
|
1491
|
+
if (graph === null) {
|
|
1492
|
+
timingCapture?.discard();
|
|
1493
|
+
settleVolumetricFogGraphCandidate(frameState, false);
|
|
1494
|
+
rejectTemporalFrame();
|
|
1495
|
+
return false;
|
|
1496
|
+
}
|
|
1497
|
+
const timingHost = internals as RenderSystemInternals & {
|
|
1498
|
+
gpuPassTimingSession?: GpuPassTimingSession | undefined;
|
|
1499
|
+
gpuPassTimingCapture?: GpuPassTimingCapture | undefined;
|
|
1500
|
+
gpuPassTimingSubmittedWork?: Promise<void> | undefined;
|
|
1501
|
+
gpuPassTimingFrameIdentity?:
|
|
1502
|
+
| import('./gpu-pass-timing/session.js').GpuPassTimingFrameIdentity
|
|
1503
|
+
| undefined;
|
|
1504
|
+
gpuPassTimingBeginReason?:
|
|
1505
|
+
| import('./gpu-pass-timing/errors.js').GpuPassTimingReason
|
|
1506
|
+
| undefined;
|
|
1507
|
+
};
|
|
1508
|
+
timingHost.gpuPassTimingCapture = undefined;
|
|
1509
|
+
timingHost.gpuPassTimingSubmittedWork = undefined;
|
|
1510
|
+
timingHost.gpuPassTimingBeginReason = undefined;
|
|
1511
|
+
const timingIdentity = timingHost.gpuPassTimingFrameIdentity;
|
|
1512
|
+
const passTimingResult =
|
|
1513
|
+
timingIdentity === undefined
|
|
1514
|
+
? undefined
|
|
1515
|
+
: timingHost.gpuPassTimingSession?.beginFrame({
|
|
1516
|
+
...timingIdentity,
|
|
1517
|
+
graphGeneration: frameState.compiledFrameGraphGeneration,
|
|
1518
|
+
});
|
|
1519
|
+
const capture = passTimingResult?.ok === true ? passTimingResult.value : undefined;
|
|
1520
|
+
if (passTimingResult?.ok === false) timingHost.gpuPassTimingBeginReason = passTimingResult.error;
|
|
1521
|
+
const passTimingCapture = capture;
|
|
1522
|
+
timingHost.gpuPassTimingCapture = passTimingCapture;
|
|
1523
|
+
const timingInstrumentationState =
|
|
1524
|
+
passTimingCapture !== undefined
|
|
1525
|
+
? getTimingInstrumentationState(internals, passTimingCapture)
|
|
1526
|
+
: timingCapture === undefined
|
|
1527
|
+
? undefined
|
|
1528
|
+
: getVolumeTimingInstrumentationState(internals, timingCapture);
|
|
743
1529
|
type PreparedCommand = { readonly command: CommandBuffer };
|
|
744
1530
|
let preparedCommand: PreparedCommand = { command: undefined as never };
|
|
745
1531
|
const transaction = executeRendererFrameTransaction<PreparedCommand>({
|
|
746
1532
|
build: () => ({ ok: true, value: { command: undefined as never } }),
|
|
747
1533
|
execute: () => {
|
|
748
|
-
const executed = graph.execute(frame, runPass);
|
|
1534
|
+
const executed = graph.execute(frame, runPass, timingInstrumentationState?.instrumentation);
|
|
1535
|
+
timingInstrumentationState?.setCapture(undefined);
|
|
749
1536
|
if (!executed.ok) {
|
|
1537
|
+
passTimingCapture?.abort({ code: executed.error.code });
|
|
750
1538
|
internals.errorRegistry.fire(executed.error);
|
|
751
1539
|
return { ok: false, stage: 'execute' };
|
|
752
1540
|
}
|
|
@@ -876,6 +1664,7 @@ export function executeCompiledFrameGraph(
|
|
|
876
1664
|
);
|
|
877
1665
|
}
|
|
878
1666
|
}
|
|
1667
|
+
internals.encodeRenderTargetReadbacks?.(encoder, readbackFaces);
|
|
879
1668
|
const stagedGpuState = frameState.temporalGpuState;
|
|
880
1669
|
if (stagedGpuState !== undefined && !hasPendingTemporalGpuSubmit(stagedGpuState)) {
|
|
881
1670
|
internals.errorRegistry.fire(
|
|
@@ -887,8 +1676,19 @@ export function executeCompiledFrameGraph(
|
|
|
887
1676
|
);
|
|
888
1677
|
return { ok: false, stage: 'finish' };
|
|
889
1678
|
}
|
|
1679
|
+
if (passTimingCapture !== undefined) {
|
|
1680
|
+
const tail = passTimingCapture.encodeTail(encoder);
|
|
1681
|
+
if (!tail.ok) passTimingCapture.abort({ code: tail.error.code });
|
|
1682
|
+
}
|
|
1683
|
+
const resolved = timingCapture?.resolve(encoder);
|
|
1684
|
+
if (resolved !== undefined && !resolved.ok) {
|
|
1685
|
+
timingCapture?.discard();
|
|
1686
|
+
return { ok: false, stage: 'finish' };
|
|
1687
|
+
}
|
|
890
1688
|
const finished = encoder.finish();
|
|
891
1689
|
if (!finished.ok) {
|
|
1690
|
+
passTimingCapture?.abort({ code: finished.error.code });
|
|
1691
|
+
timingCapture?.discard();
|
|
892
1692
|
internals.errorRegistry.fire(finished.error);
|
|
893
1693
|
return { ok: false, stage: 'finish' };
|
|
894
1694
|
}
|
|
@@ -898,12 +1698,20 @@ export function executeCompiledFrameGraph(
|
|
|
898
1698
|
submit: () => {
|
|
899
1699
|
const submitted = internals.device.queue.submit([preparedCommand.command]);
|
|
900
1700
|
if (!submitted.ok) {
|
|
1701
|
+
passTimingCapture?.abort({ code: submitted.error.code });
|
|
1702
|
+
timingCapture?.discard();
|
|
901
1703
|
internals.errorRegistry.fire(submitted.error);
|
|
902
1704
|
return { ok: false, stage: 'submit' };
|
|
903
1705
|
}
|
|
1706
|
+
timingCapture?.markSubmitted();
|
|
904
1707
|
return { ok: true, value: undefined };
|
|
905
1708
|
},
|
|
906
1709
|
commit: () => {
|
|
1710
|
+
if (passTimingCapture !== undefined) {
|
|
1711
|
+
const completion = internals.device.queue.onSubmittedWorkDone();
|
|
1712
|
+
timingHost.gpuPassTimingSubmittedWork = completion;
|
|
1713
|
+
passTimingCapture.markSubmitted(completion);
|
|
1714
|
+
}
|
|
907
1715
|
if (frameState.bloomFrameReceipts !== undefined) {
|
|
908
1716
|
internals
|
|
909
1717
|
.getPipelineState()
|
|
@@ -917,7 +1725,7 @@ export function executeCompiledFrameGraph(
|
|
|
917
1725
|
frameState.activeTemporalGpuState = stagedGpuState;
|
|
918
1726
|
if (previousGpuState !== undefined && previousGpuState !== stagedGpuState) {
|
|
919
1727
|
internals.clearPostProcessPipelineCache?.('forgeax.taa-resolve');
|
|
920
|
-
|
|
1728
|
+
invalidatePostProcessModule('forgeax.taa-resolve');
|
|
921
1729
|
retireTemporalGpuStateAfterFence(
|
|
922
1730
|
previousGpuState,
|
|
923
1731
|
internals.device.queue,
|
|
@@ -947,7 +1755,7 @@ export function executeCompiledFrameGraph(
|
|
|
947
1755
|
}
|
|
948
1756
|
if (stagedTemporalCommit.kind === 'off') {
|
|
949
1757
|
internals.clearPostProcessPipelineCache?.('forgeax.taa-resolve');
|
|
950
|
-
|
|
1758
|
+
invalidatePostProcessModule('forgeax.taa-resolve');
|
|
951
1759
|
const activeGpuState = frameState.activeTemporalGpuState;
|
|
952
1760
|
if (activeGpuState !== undefined) {
|
|
953
1761
|
retireTemporalGpuStateAfterFence(
|
|
@@ -972,8 +1780,13 @@ export function executeCompiledFrameGraph(
|
|
|
972
1780
|
frameState.environmentLifecycle?.publish(frameState.environmentGeneration);
|
|
973
1781
|
frameState.environmentGeneration = undefined;
|
|
974
1782
|
}
|
|
1783
|
+
onSubmitted?.(internals.device.queue.onSubmittedWorkDone());
|
|
975
1784
|
},
|
|
976
1785
|
abort: (failure) => {
|
|
1786
|
+
passTimingCapture?.abort({ code: failure.stage });
|
|
1787
|
+
timingHost.gpuPassTimingCapture = undefined;
|
|
1788
|
+
timingHost.gpuPassTimingSubmittedWork = undefined;
|
|
1789
|
+
timingCapture?.discard();
|
|
977
1790
|
frameState.bloomFrameReceipts = undefined;
|
|
978
1791
|
if (frameState.environmentGeneration !== undefined) {
|
|
979
1792
|
frameState.environmentLifecycle?.recordStageFailure(
|
|
@@ -996,5 +1809,176 @@ export function executeCompiledFrameGraph(
|
|
|
996
1809
|
}
|
|
997
1810
|
},
|
|
998
1811
|
});
|
|
1812
|
+
settleVolumetricFogGraphCandidate(frameState, transaction.ok);
|
|
1813
|
+
if (!transaction.ok) rejectTemporalFrame();
|
|
999
1814
|
return transaction.ok;
|
|
1000
1815
|
}
|
|
1816
|
+
|
|
1817
|
+
function getTimingInstrumentationState(
|
|
1818
|
+
internals: RenderSystemInternals,
|
|
1819
|
+
capture: GpuPassTimingCapture,
|
|
1820
|
+
): TimingInstrumentationState {
|
|
1821
|
+
const existing = timingInstrumentationStates.get(internals);
|
|
1822
|
+
if (existing !== undefined) {
|
|
1823
|
+
existing.setCapture(capture);
|
|
1824
|
+
return existing;
|
|
1825
|
+
}
|
|
1826
|
+
type TimestampWrites = NonNullable<ReturnType<GpuPassTimingCapture['timestampWrites']>>;
|
|
1827
|
+
const activeIdentity: {
|
|
1828
|
+
passName: string;
|
|
1829
|
+
passKind: GpuPassTimingPassIdentity['passKind'];
|
|
1830
|
+
executionIndex: number;
|
|
1831
|
+
} = {
|
|
1832
|
+
passName: '',
|
|
1833
|
+
passKind: 'raster',
|
|
1834
|
+
executionIndex: 0,
|
|
1835
|
+
};
|
|
1836
|
+
let activeWrites: TimestampWrites | undefined;
|
|
1837
|
+
let activeCapture: GpuPassTimingCapture | undefined = capture;
|
|
1838
|
+
const rasterScope: RenderGraphPassInstrumentationScope = {
|
|
1839
|
+
renderPassDescriptor: (descriptor) => {
|
|
1840
|
+
const capture = activeCapture;
|
|
1841
|
+
const identity = activeIdentity;
|
|
1842
|
+
const writes = activeWrites;
|
|
1843
|
+
if (capture === undefined || identity === undefined || writes === undefined) {
|
|
1844
|
+
return descriptor;
|
|
1845
|
+
}
|
|
1846
|
+
if (descriptor.timestampWrites !== undefined) {
|
|
1847
|
+
capture.markOwnerConflict(identity);
|
|
1848
|
+
return descriptor;
|
|
1849
|
+
}
|
|
1850
|
+
(descriptor as { timestampWrites?: TimestampWrites }).timestampWrites = writes;
|
|
1851
|
+
return descriptor;
|
|
1852
|
+
},
|
|
1853
|
+
};
|
|
1854
|
+
const computeScope: RenderGraphPassInstrumentationScope = {
|
|
1855
|
+
computePassDescriptor: (descriptor) => {
|
|
1856
|
+
const capture = activeCapture;
|
|
1857
|
+
const identity = activeIdentity;
|
|
1858
|
+
const writes = activeWrites;
|
|
1859
|
+
if (capture === undefined || identity === undefined || writes === undefined) {
|
|
1860
|
+
return descriptor;
|
|
1861
|
+
}
|
|
1862
|
+
if (descriptor.timestampWrites !== undefined) {
|
|
1863
|
+
capture.markOwnerConflict(identity);
|
|
1864
|
+
return descriptor;
|
|
1865
|
+
}
|
|
1866
|
+
(descriptor as { timestampWrites?: TimestampWrites }).timestampWrites = writes;
|
|
1867
|
+
return descriptor;
|
|
1868
|
+
},
|
|
1869
|
+
};
|
|
1870
|
+
const copyScope: RenderGraphPassInstrumentationScope = {
|
|
1871
|
+
beforeCopy: (encoder) => {
|
|
1872
|
+
const capture = activeCapture;
|
|
1873
|
+
const identity = activeIdentity;
|
|
1874
|
+
if (capture === undefined || identity === undefined) return;
|
|
1875
|
+
capture.copyBoundaryBefore(identity, encoder);
|
|
1876
|
+
},
|
|
1877
|
+
afterCopy: (encoder) => {
|
|
1878
|
+
const capture = activeCapture;
|
|
1879
|
+
const identity = activeIdentity;
|
|
1880
|
+
if (capture === undefined || identity === undefined) return;
|
|
1881
|
+
capture.copyBoundaryAfter(identity, encoder);
|
|
1882
|
+
},
|
|
1883
|
+
};
|
|
1884
|
+
const instrumentation: RenderGraphPassInstrumentation<RenderPipelineFrame> = {
|
|
1885
|
+
begin: (pass) => {
|
|
1886
|
+
const capture = activeCapture;
|
|
1887
|
+
if (capture === undefined) return undefined;
|
|
1888
|
+
activeIdentity.passName = pass.name;
|
|
1889
|
+
activeIdentity.passKind = pass.kind;
|
|
1890
|
+
activeIdentity.executionIndex = pass.executionIndex;
|
|
1891
|
+
activeWrites = capture.recordPass(activeIdentity);
|
|
1892
|
+
if (activeWrites === undefined) return undefined;
|
|
1893
|
+
switch (pass.kind) {
|
|
1894
|
+
case 'raster':
|
|
1895
|
+
return rasterScope;
|
|
1896
|
+
case 'compute':
|
|
1897
|
+
return computeScope;
|
|
1898
|
+
case 'copy':
|
|
1899
|
+
return copyScope;
|
|
1900
|
+
}
|
|
1901
|
+
},
|
|
1902
|
+
};
|
|
1903
|
+
const state: TimingInstrumentationState = {
|
|
1904
|
+
instrumentation,
|
|
1905
|
+
setCapture: (capture) => {
|
|
1906
|
+
activeCapture = capture;
|
|
1907
|
+
if (capture === undefined) {
|
|
1908
|
+
activeWrites = undefined;
|
|
1909
|
+
}
|
|
1910
|
+
},
|
|
1911
|
+
};
|
|
1912
|
+
timingInstrumentationStates.set(internals, state);
|
|
1913
|
+
return state;
|
|
1914
|
+
}
|
|
1915
|
+
|
|
1916
|
+
function getVolumeTimingInstrumentationState(
|
|
1917
|
+
internals: RenderSystemInternals,
|
|
1918
|
+
capture: GpuTimingCapture,
|
|
1919
|
+
): VolumeTimingInstrumentationState {
|
|
1920
|
+
const existing = volumeTimingInstrumentationStates.get(internals);
|
|
1921
|
+
if (existing !== undefined) {
|
|
1922
|
+
existing.setCapture(capture);
|
|
1923
|
+
return existing;
|
|
1924
|
+
}
|
|
1925
|
+
let activeCapture: GpuTimingCapture | undefined = capture;
|
|
1926
|
+
let activePassName: string | undefined;
|
|
1927
|
+
let activeWrites: VolumeTimingTimestampWrites | undefined;
|
|
1928
|
+
const rasterScope: RenderGraphPassInstrumentationScope = {
|
|
1929
|
+
renderPassDescriptor: (descriptor) => {
|
|
1930
|
+
const currentCapture = activeCapture;
|
|
1931
|
+
const passName = activePassName;
|
|
1932
|
+
const writes = activeWrites;
|
|
1933
|
+
if (currentCapture === undefined || passName === undefined || writes === undefined) {
|
|
1934
|
+
return descriptor;
|
|
1935
|
+
}
|
|
1936
|
+
if (descriptor.timestampWrites !== undefined) {
|
|
1937
|
+
currentCapture.skipPass(passName);
|
|
1938
|
+
activeWrites = undefined;
|
|
1939
|
+
return descriptor;
|
|
1940
|
+
}
|
|
1941
|
+
return { ...descriptor, timestampWrites: writes };
|
|
1942
|
+
},
|
|
1943
|
+
};
|
|
1944
|
+
const computeScope: RenderGraphPassInstrumentationScope = {
|
|
1945
|
+
computePassDescriptor: (descriptor) => {
|
|
1946
|
+
const currentCapture = activeCapture;
|
|
1947
|
+
const passName = activePassName;
|
|
1948
|
+
const writes = activeWrites;
|
|
1949
|
+
if (currentCapture === undefined || passName === undefined || writes === undefined) {
|
|
1950
|
+
return descriptor;
|
|
1951
|
+
}
|
|
1952
|
+
if (descriptor.timestampWrites !== undefined) {
|
|
1953
|
+
currentCapture.skipPass(passName);
|
|
1954
|
+
activeWrites = undefined;
|
|
1955
|
+
return descriptor;
|
|
1956
|
+
}
|
|
1957
|
+
return { ...descriptor, timestampWrites: writes };
|
|
1958
|
+
},
|
|
1959
|
+
};
|
|
1960
|
+
const instrumentation: RenderGraphPassInstrumentation<RenderPipelineFrame> = {
|
|
1961
|
+
begin: (pass) => {
|
|
1962
|
+
const currentCapture = activeCapture;
|
|
1963
|
+
if (currentCapture === undefined) return undefined;
|
|
1964
|
+
activePassName = pass.name;
|
|
1965
|
+
activeWrites = currentCapture.recordPass(pass.name);
|
|
1966
|
+
if (activeWrites === undefined) return undefined;
|
|
1967
|
+
if (pass.kind === 'raster') return rasterScope;
|
|
1968
|
+
if (pass.kind === 'compute') return computeScope;
|
|
1969
|
+
currentCapture.skipPass(pass.name);
|
|
1970
|
+
activeWrites = undefined;
|
|
1971
|
+
return undefined;
|
|
1972
|
+
},
|
|
1973
|
+
};
|
|
1974
|
+
const state: VolumeTimingInstrumentationState = {
|
|
1975
|
+
instrumentation,
|
|
1976
|
+
setCapture: (nextCapture) => {
|
|
1977
|
+
activeCapture = nextCapture;
|
|
1978
|
+
activePassName = undefined;
|
|
1979
|
+
activeWrites = undefined;
|
|
1980
|
+
},
|
|
1981
|
+
};
|
|
1982
|
+
volumeTimingInstrumentationStates.set(internals, state);
|
|
1983
|
+
return state;
|
|
1984
|
+
}
|