@forgeax/engine-render 0.1.20 → 0.1.23
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 +365 -29
- package/dist/assembly/backend-contract.d.ts +13 -0
- package/dist/assembly/backend-contract.d.ts.map +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 +30 -19
- package/dist/assembly/factory.d.ts.map +1 -1
- package/dist/assembly/host-contract.d.ts +19 -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 +4 -1
- 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-PCHBPYML.mjs → chunk-4L3P6DT5.mjs} +2 -2
- package/dist/chunk-4L3P6DT5.mjs.map +1 -0
- package/dist/{chunk-VFPLTKCU.mjs → chunk-4NPUASZR.mjs} +15 -4
- package/dist/chunk-4NPUASZR.mjs.map +1 -0
- package/dist/chunk-DIYW3M5D.mjs +5085 -0
- package/dist/chunk-DIYW3M5D.mjs.map +1 -0
- package/dist/chunk-FBC4R44J.mjs +1003 -0
- package/dist/chunk-FBC4R44J.mjs.map +1 -0
- package/dist/{chunk-CDTWTHZR.mjs → chunk-FF7K3FSO.mjs} +474 -168
- package/dist/chunk-FF7K3FSO.mjs.map +1 -0
- package/dist/chunk-HZUPSYW7.mjs +1104 -0
- package/dist/chunk-HZUPSYW7.mjs.map +1 -0
- package/dist/{chunk-TBQJOK2L.mjs → chunk-QODA5UKU.mjs} +321 -269
- package/dist/chunk-QODA5UKU.mjs.map +1 -0
- package/dist/chunk-YALPS44A.mjs +296 -0
- package/dist/chunk-YALPS44A.mjs.map +1 -0
- package/dist/{chunk-4XINDLAY.mjs → chunk-ZUWKAZ2I.mjs} +1963 -2178
- package/dist/chunk-ZUWKAZ2I.mjs.map +1 -0
- package/dist/cluster-binner.d.ts +5 -0
- package/dist/cluster-binner.d.ts.map +1 -1
- 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 +5 -0
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/light-helpers.d.ts +4 -0
- package/dist/components/light-helpers.d.ts.map +1 -1
- package/dist/components/light-probe.d.ts +9 -0
- package/dist/components/light-probe.d.ts.map +1 -0
- package/dist/components/rect-area-light.d.ts +12 -0
- package/dist/components/rect-area-light.d.ts.map +1 -0
- package/dist/components/reflection-probe.d.ts +17 -0
- package/dist/components/reflection-probe.d.ts.map +1 -0
- package/dist/components/scene-instance.d.ts +4 -0
- package/dist/components/scene-instance.d.ts.map +1 -1
- package/dist/components/spot-light.d.ts +3 -0
- package/dist/components/spot-light.d.ts.map +1 -1
- package/dist/construct-renderer.mjs +14836 -9620
- package/dist/construct-renderer.mjs.map +1 -1
- package/dist/device/gpu-residency.d.ts +8 -1
- package/dist/device/gpu-residency.d.ts.map +1 -1
- package/dist/device/lifecycle-transaction.d.ts +2 -0
- package/dist/device/lifecycle-transaction.d.ts.map +1 -0
- 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/gpu-driven.d.ts +26 -0
- package/dist/errors/gpu-driven.d.ts.map +1 -0
- package/dist/errors/index.d.ts +1 -0
- package/dist/errors/index.d.ts.map +1 -1
- package/dist/errors/recover.d.ts +9 -1
- package/dist/errors/recover.d.ts.map +1 -1
- package/dist/errors/render.d.ts +166 -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/gpu-driven.d.ts +50 -0
- package/dist/extract/gpu-driven.d.ts.map +1 -0
- 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 +34 -0
- package/dist/gpu-driven/batch-topology.d.ts.map +1 -1
- package/dist/gpu-driven/prepared-draw.d.ts +63 -0
- package/dist/gpu-driven/prepared-draw.d.ts.map +1 -0
- package/dist/gpu-driven/production-raster.d.ts +97 -2
- package/dist/gpu-driven/production-raster.d.ts.map +1 -1
- package/dist/gpu-driven/view-gpu.d.ts +64 -1
- package/dist/gpu-driven/view-gpu.d.ts.map +1 -1
- package/dist/gpu-scene-schema.d.ts +14 -0
- package/dist/gpu-scene-schema.d.ts.map +1 -1
- package/dist/gpu-scene.d.ts +8 -1
- package/dist/gpu-scene.d.ts.map +1 -1
- package/dist/gpu-usage.d.ts +0 -1
- package/dist/gpu-usage.d.ts.map +1 -1
- package/dist/hdrp-buffers.d.ts +21 -19
- 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 +39 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.mjs +91 -6
- package/dist/index.mjs.map +1 -1
- package/dist/inspection-types.d.ts +214 -1
- 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.d.ts +9 -0
- package/dist/internal.d.ts.map +1 -1
- package/dist/internal.mjs +23 -2
- package/dist/internal.mjs.map +1 -1
- package/dist/light-buffer-layout.d.ts +58 -140
- package/dist/light-buffer-layout.d.ts.map +1 -1
- package/dist/materials.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 +38 -14
- 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 +5 -26
- package/dist/pipeline/standard-profile.d.ts.map +1 -1
- package/dist/pipeline-builder.d.ts +2 -0
- package/dist/pipeline-builder.d.ts.map +1 -1
- package/dist/pipeline-spec.d.ts +40 -7
- package/dist/pipeline-spec.d.ts.map +1 -1
- package/dist/plugin.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/prepare/extended-lighting/ltc-resources.d.ts +31 -0
- package/dist/prepare/extended-lighting/ltc-resources.d.ts.map +1 -0
- package/dist/prepare/extended-lighting/resources.d.ts +72 -0
- package/dist/prepare/extended-lighting/resources.d.ts.map +1 -0
- package/dist/prepare/extended-lighting/spot-modifiers.d.ts +42 -0
- package/dist/prepare/extended-lighting/spot-modifiers.d.ts.map +1 -0
- package/dist/prepare/extended-lighting/state.d.ts +24 -0
- package/dist/prepare/extended-lighting/state.d.ts.map +1 -0
- package/dist/record/frame-lighting.d.ts +33 -36
- package/dist/record/frame-lighting.d.ts.map +1 -1
- package/dist/record/frame-snapshot.d.ts +78 -24
- 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 +16 -6
- 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 +20 -3
- package/dist/record/gpu-timing.d.ts.map +1 -1
- package/dist/record/helpers.d.ts +0 -20
- package/dist/record/helpers.d.ts.map +1 -1
- package/dist/record/main-pass-geometry.d.ts +6 -1
- package/dist/record/main-pass-geometry.d.ts.map +1 -1
- package/dist/record/main-pass-material.d.ts +25 -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/mesh-ssbo.d.ts.map +1 -1
- package/dist/record/render-context.d.ts +98 -6
- 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 +119 -4
- package/dist/record/typed-frame-graph.d.ts.map +1 -1
- package/dist/record/view-ubo.d.ts +7 -5
- 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/inspection.d.ts +10 -0
- package/dist/reflection/inspection.d.ts.map +1 -0
- package/dist/reflection/projection.d.ts +140 -0
- package/dist/reflection/projection.d.ts.map +1 -0
- package/dist/reflection/record-owner.d.ts +60 -0
- package/dist/reflection/record-owner.d.ts.map +1 -0
- package/dist/render-contract.d.ts +62 -14
- package/dist/render-contract.d.ts.map +1 -1
- package/dist/render-graph-primitives.d.ts +1 -0
- package/dist/render-graph-primitives.d.ts.map +1 -1
- package/dist/render-pipeline.d.ts +49 -2
- package/dist/render-pipeline.d.ts.map +1 -1
- package/dist/render-system-extract.d.ts +160 -31
- package/dist/render-system-extract.d.ts.map +1 -1
- package/dist/render-system.d.ts +28 -2
- package/dist/render-system.d.ts.map +1 -1
- package/dist/renderer.d.ts +43 -0
- package/dist/renderer.d.ts.map +1 -0
- package/dist/scene/probe-blend-record.d.ts +22 -0
- package/dist/scene/probe-blend-record.d.ts.map +1 -0
- package/dist/scene/probe-blend.d.ts +142 -0
- package/dist/scene/probe-blend.d.ts.map +1 -0
- package/dist/scene/render-scene-types.d.ts +0 -6
- package/dist/scene/render-scene-types.d.ts.map +1 -1
- package/dist/scene/render-scene.d.ts +117 -9
- package/dist/scene/render-scene.d.ts.map +1 -1
- package/dist/scene/visibility/bounds.d.ts +20 -0
- package/dist/scene/visibility/bounds.d.ts.map +1 -0
- package/dist/scene/visibility/budget.d.ts +16 -0
- package/dist/scene/visibility/budget.d.ts.map +1 -0
- package/dist/scene/visibility/facet.d.ts +73 -0
- package/dist/scene/visibility/facet.d.ts.map +1 -0
- package/dist/scene/visibility/gpu-frame-timing.d.ts +41 -0
- package/dist/scene/visibility/gpu-frame-timing.d.ts.map +1 -0
- package/dist/scene/visibility/gpu-lod.d.ts +46 -0
- package/dist/scene/visibility/gpu-lod.d.ts.map +1 -0
- package/dist/scene/visibility/inspection.d.ts +132 -0
- package/dist/scene/visibility/inspection.d.ts.map +1 -0
- package/dist/scene/visibility/lod-selector.d.ts +25 -0
- package/dist/scene/visibility/lod-selector.d.ts.map +1 -0
- package/dist/scene/visibility/occlusion-confidence.d.ts +81 -0
- package/dist/scene/visibility/occlusion-confidence.d.ts.map +1 -0
- package/dist/scene/visibility/occlusion-pass.d.ts +57 -0
- package/dist/scene/visibility/occlusion-pass.d.ts.map +1 -0
- package/dist/scene/visibility/occlusion-query-pool.d.ts +57 -0
- package/dist/scene/visibility/occlusion-query-pool.d.ts.map +1 -0
- package/dist/scene/visibility/occlusion-runtime.d.ts +96 -0
- package/dist/scene/visibility/occlusion-runtime.d.ts.map +1 -0
- package/dist/scene/visibility/types.d.ts +34 -0
- package/dist/scene/visibility/types.d.ts.map +1 -0
- 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/ssr/admission.d.ts +122 -0
- package/dist/ssr/admission.d.ts.map +1 -0
- package/dist/ssr/composition.d.ts +32 -0
- package/dist/ssr/composition.d.ts.map +1 -0
- package/dist/ssr/errors.d.ts +39 -0
- package/dist/ssr/errors.d.ts.map +1 -0
- package/dist/ssr/identity.d.ts +13 -0
- package/dist/ssr/identity.d.ts.map +1 -0
- package/dist/systems/skin-palette-allocator.d.ts +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-coordinator.d.ts +13 -0
- package/dist/temporal/frame-coordinator.d.ts.map +1 -1
- package/dist/temporal/frame.d.ts +2 -0
- package/dist/temporal/frame.d.ts.map +1 -1
- package/dist/temporal/index.mjs +6 -5
- package/dist/temporal/view.d.ts +7 -0
- package/dist/temporal/view.d.ts.map +1 -1
- package/dist/tilemap-chunk-extract-system.d.ts +1 -1
- package/dist/typed-render-graph-primitives.d.ts +5 -1
- package/dist/typed-render-graph-primitives.d.ts.map +1 -1
- package/dist/typed-shadow-passes.d.ts +1 -1
- package/dist/typed-shadow-passes.d.ts.map +1 -1
- package/dist/volume/passes.d.ts +9 -5
- package/dist/volume/passes.d.ts.map +1 -1
- 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 +12 -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__/detached-inspection.integration.test.ts +6 -0
- package/src/__tests__/device-feature-admission.unit.test.ts +85 -0
- package/src/__tests__/direct-light-snapshot.unit.test.ts +62 -6
- package/src/__tests__/docs-gate-green.unit.test.ts +38 -0
- package/src/__tests__/environment-generation.integration.test.ts +16 -0
- package/src/__tests__/evidence-identity.ts +13 -0
- package/src/__tests__/evidence-identity.unit.test.ts +24 -0
- package/src/__tests__/extended-lighting-recovery.browser.test.ts +14 -0
- package/src/__tests__/extended-lighting-recovery.dawn.test.ts +14 -0
- package/src/__tests__/extended-lighting-recovery.integration.test.ts +81 -0
- package/src/__tests__/extended-lighting-resources.unit.test.ts +51 -0
- package/src/__tests__/extended-lighting-zero-feature.integration.test.ts +52 -0
- package/src/__tests__/factory-contract.integration.test.ts +288 -29
- package/src/__tests__/fog-component.unit.test.ts +67 -0
- package/src/__tests__/fog.integration.test.ts +86 -0
- package/src/__tests__/frame-observation.contract.test.ts +15 -0
- package/src/__tests__/fullscreen-feature-plan.unit.test.ts +37 -0
- package/src/__tests__/gpu-driven-batch-topology-pbr.unit.test.ts +146 -0
- package/src/__tests__/gpu-driven-indirect-raster-evidence.ts +10 -8
- package/src/__tests__/gpu-driven-indirect-raster.dawn.test.ts +18 -1
- package/src/__tests__/gpu-driven-production.integration.test.ts +579 -17
- package/src/__tests__/gpu-driven-scaling.unit.test.ts +66 -2
- package/src/__tests__/gpu-driven-view-gpu-evidence.ts +26 -1
- package/src/__tests__/gpu-driven-view-graph.integration.test.ts +101 -6
- package/src/__tests__/gpu-driven-view.browser.test.ts +3 -3
- package/src/__tests__/gpu-driven-view.dawn.test.ts +3 -3
- package/src/__tests__/gpu-driven-view.unit.test.ts +50 -0
- package/src/__tests__/gpu-lod-evidence.ts +188 -0
- package/src/__tests__/gpu-lod-fallback.integration.test.ts +10 -0
- package/src/__tests__/gpu-lod-indirect.integration.test.ts +40 -0
- package/src/__tests__/gpu-lod-parity.dawn.test.ts +29 -0
- package/src/__tests__/gpu-lod-readiness.integration.test.ts +52 -0
- package/src/__tests__/gpu-lod-schema.unit.test.ts +66 -0
- package/src/__tests__/gpu-lod-selector.unit.test.ts +28 -0
- package/src/__tests__/gpu-lod-silhouette.browser.test.ts +13 -0
- 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__/gpu-resource-store-stride.unit.test.ts +66 -1
- package/src/__tests__/gpu-scene.dawn.test.ts +8 -1
- package/src/__tests__/gpu-scene.unit.test.ts +49 -3
- 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__/light-buffer-layout.unit.test.ts +113 -3
- package/src/__tests__/light-inspection.unit.test.ts +55 -0
- package/src/__tests__/light-resource-error.unit.test.ts +43 -0
- package/src/__tests__/lighting-scene-roundtrip.integration.test.ts +109 -0
- package/src/__tests__/lod-bounds.unit.test.ts +42 -0
- package/src/__tests__/lod-cpu-lane.integration.test.ts +55 -0
- package/src/__tests__/lod-cpu-no-change.perf.test.ts +19 -0
- package/src/__tests__/lod-gpu-frame-timing.unit.test.ts +49 -0
- package/src/__tests__/lod-multi-view.integration.test.ts +63 -0
- package/src/__tests__/lod-occlusion-device-loss.integration.test.ts +27 -0
- package/src/__tests__/lod-occlusion-final-decision.integration.test.ts +47 -0
- package/src/__tests__/lod-occlusion-inspection.integration.test.ts +217 -0
- package/src/__tests__/lod-occlusion-inspection.schema.test-d.ts +14 -0
- package/src/__tests__/lod-occlusion-inspection.unit.test.ts +72 -0
- package/src/__tests__/lod-occlusion-visual-evidence.ts +91 -0
- package/src/__tests__/lod-occlusion.browser.test.ts +15 -0
- package/src/__tests__/lod-occlusion.dawn.test.ts +20 -0
- package/src/__tests__/lod-selector.profile.test.ts +35 -0
- package/src/__tests__/lod-selector.unit.test.ts +68 -0
- package/src/__tests__/lod-visibility-identity.unit.test.ts +198 -0
- package/src/__tests__/lod-visibility-lifecycle.integration.test.ts +132 -0
- package/src/__tests__/ltc-resources.unit.test.ts +32 -0
- package/src/__tests__/material-contract-inventory.unit.test.ts +17 -0
- package/src/__tests__/material-observation.integration.test.ts +101 -0
- package/src/__tests__/occlusion-confidence.unit.test.ts +168 -0
- package/src/__tests__/occlusion-invalidation.integration.test.ts +37 -0
- package/src/__tests__/occlusion-pass-routing.unit.test.ts +16 -0
- package/src/__tests__/occlusion-pass.dawn.test.ts +20 -0
- package/src/__tests__/occlusion-pass.integration.test.ts +43 -0
- package/src/__tests__/occlusion-pass.rhi-null.test.ts +22 -0
- package/src/__tests__/occlusion-query-pool.rhi-null.test.ts +21 -0
- package/src/__tests__/occlusion-query-pool.unit.test.ts +95 -0
- package/src/__tests__/occlusion-query-ticket.integration.test.ts +47 -0
- package/src/__tests__/occlusion-query.dawn.test.ts +16 -0
- package/src/__tests__/occlusion-query.evidence.ts +178 -0
- package/src/__tests__/occlusion-query.rhi-null.test.ts +31 -0
- package/src/__tests__/occlusion-runtime.unit.test.ts +120 -0
- 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__/prepared-gpu-driven-pbr.integration.test.ts +196 -0
- package/src/__tests__/probe-bindings.unit.test.ts +200 -0
- package/src/__tests__/probe-blend-numeric.unit.test.ts +67 -0
- package/src/__tests__/probe-blend-oracle.unit.test.ts +136 -0
- package/src/__tests__/probe-capacity.integration.test.ts +97 -0
- package/src/__tests__/probe-recovery.integration.test.ts +104 -0
- package/src/__tests__/probe-scene-dirty.integration.test.ts +211 -0
- package/src/__tests__/profiler-phase-catalog.test.ts +4 -1
- package/src/__tests__/profiler-phase-token.test.ts +1 -0
- package/src/__tests__/public-surface.test-d.ts +10 -0
- package/src/__tests__/rect-area-boundary.unit.test.ts +24 -0
- package/src/__tests__/reflection-fallback-graph.unit.test.ts +67 -0
- package/src/__tests__/reflection-fallback-inspection.unit.test.ts +77 -0
- package/src/__tests__/reflection-fallback-lifecycle.integration.test.ts +21 -0
- package/src/__tests__/reflection-fallback-projection.unit.test.ts +90 -0
- package/src/__tests__/reflection-fallback-source.unit.test.ts +32 -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-owner-placement.unit.test.ts +39 -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-record-owner.characterization.unit.test.ts +120 -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 +19 -3
- package/src/__tests__/render-feature-docs.unit.test.ts +12 -7
- package/src/__tests__/render-graph-fallback.integration.test.ts +24 -0
- package/src/__tests__/render-perf/extended-lighting.bench.test.ts +66 -0
- package/src/__tests__/render-scene-projection.unit.test.ts +447 -18
- 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 +124 -0
- 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 +154 -0
- package/src/__tests__/skinned-shadow-caster.test.ts +13 -4
- package/src/__tests__/spot-modifier-projection.unit.test.ts +70 -0
- package/src/__tests__/ssr-admission-matrix.integration.test.ts +206 -0
- package/src/__tests__/ssr-composition.unit.test.ts +46 -0
- package/src/__tests__/ssr-fallback-zero-work.bench.test.ts +94 -0
- package/src/__tests__/ssr-recovery-errors.unit.test.ts +58 -0
- 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 +299 -0
- package/src/__tests__/standard-clustered-pipeline.unit.test.ts +15 -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 +441 -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 -38
- package/src/__tests__/temporal-fallback-generation.integration.test.ts +16 -0
- package/src/__tests__/temporal-view.unit.test.ts +3 -3
- package/src/__tests__/transmission-prewarm.unit.test.ts +69 -0
- 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-budget.integration.test.ts +140 -0
- package/src/__tests__/visibility-budget.unit.test.ts +70 -0
- package/src/__tests__/visibility-extract.integration.test.ts +11 -6
- package/src/__tests__/visibility-resolver.unit.test.ts +15 -0
- package/src/__tests__/volumetric-fog-point-spot-accumulation.integration.test.ts +6 -3
- package/src/__tests__/volumetric-fog-stage-readback.dawn.test.ts +31 -28
- package/src/assembly/backend-contract.ts +13 -0
- package/src/assembly/device-feature-admission.ts +80 -0
- package/src/assembly/directional-shadow-inspection.ts +122 -0
- package/src/assembly/factory.ts +1411 -366
- package/src/assembly/host-contract.ts +35 -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/cluster-binner.ts +31 -0
- package/src/components/__tests__/lighting-authoring.unit.test.ts +39 -0
- package/src/components/__tests__/rect-area-light.unit.test.ts +33 -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 +5 -0
- package/src/components/light-helpers.ts +133 -8
- package/src/components/light-probe.ts +13 -0
- package/src/components/rect-area-light.ts +15 -0
- package/src/components/reflection-probe.ts +49 -0
- package/src/components/scene-instance.ts +6 -0
- package/src/components/spot-light.ts +3 -0
- package/src/device/__tests__/extended-lighting-recovery.unit.test.ts +24 -0
- package/src/device/gpu-residency.ts +140 -9
- package/src/device/lifecycle-transaction.ts +12 -0
- package/src/environment/frame.ts +6 -24
- package/src/environment/lifecycle.ts +20 -1
- package/src/errors/gpu-driven.ts +92 -0
- package/src/errors/index.ts +1 -0
- package/src/errors/recover.ts +32 -0
- package/src/errors/render.ts +341 -143
- package/src/extract/camera.ts +3 -3
- package/src/extract/directional-shadow-projection.ts +61 -0
- package/src/extract/environment.ts +57 -0
- package/src/extract/gpu-driven.ts +108 -0
- package/src/extract/visibility.ts +2 -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 +207 -28
- package/src/gpu-driven/prepared-draw.ts +208 -0
- package/src/gpu-driven/production-raster.ts +953 -43
- package/src/gpu-driven/view-gpu.ts +411 -29
- package/src/gpu-scene-schema.ts +13 -0
- package/src/gpu-scene.ts +140 -64
- package/src/gpu-usage.ts +0 -1
- package/src/hdrp-buffers.ts +169 -63
- package/src/ibl/IblPipelineCache.ts +11 -0
- package/src/ibl/kernel-cache.ts +88 -0
- package/src/index.ts +222 -0
- package/src/inspection-types.ts +276 -1
- package/src/instances-derived-bounds.ts +171 -0
- package/src/internal.ts +38 -0
- package/src/light-buffer-layout.ts +155 -310
- package/src/materials.ts +16 -2
- package/src/mesh-material-bindings.ts +132 -0
- package/src/pbr-pipeline.ts +255 -60
- package/src/pipeline/standard-forward-lane.ts +93 -16
- package/src/pipeline/standard-lighting/errors.ts +6 -0
- package/src/pipeline/standard-lighting/graph.ts +158 -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 +35 -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 +78 -0
- package/src/pipeline/standard-pipeline.ts +124 -193
- package/src/pipeline/standard-post.ts +26 -7
- package/src/pipeline/standard-profile.ts +17 -47
- package/src/pipeline-builder.ts +5 -2
- package/src/pipeline-spec.ts +95 -21
- package/src/plugin.ts +4 -0
- package/src/point-shadow-inspection.ts +55 -0
- package/src/prepare/__tests__/extended-lighting-capability.unit.test.ts +56 -0
- package/src/prepare/extended-lighting/ltc-resources.ts +136 -0
- package/src/prepare/extended-lighting/resources.ts +389 -0
- package/src/prepare/extended-lighting/spot-modifiers.ts +194 -0
- package/src/prepare/extended-lighting/state.ts +92 -0
- package/src/record/__tests__/gpu-timing.unit.test.ts +177 -0
- package/src/record/__tests__/temporal-payload.unit.test.ts +64 -1
- package/src/record/__tests__/transparent-group2-selection.unit.test.ts +73 -0
- package/src/record/__tests__/typed-frame-graph-plan.unit.test.ts +20 -1
- package/src/record/__tests__/view-ubo-layout.unit.test.ts +40 -0
- package/src/record/frame-lighting.ts +591 -452
- package/src/record/frame-snapshot.ts +92 -39
- package/src/record/frame-targets.ts +17 -0
- package/src/record/frame.ts +662 -158
- 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 +112 -39
- package/src/record/helpers.ts +0 -58
- package/src/record/main-pass-geometry.ts +324 -119
- package/src/record/main-pass-material.ts +103 -10
- package/src/record/main-pass-sprite-draws.ts +99 -103
- package/src/record/main-pass.ts +71 -15
- package/src/record/mesh-ssbo.ts +47 -36
- package/src/record/render-context.ts +136 -3
- package/src/record/shadow-pass.ts +83 -68
- package/src/record/skybox-post-pass.ts +20 -4
- package/src/record/typed-frame-graph.ts +1034 -43
- package/src/record/view-ubo.ts +72 -47
- package/src/reflection/filter.ts +81 -0
- package/src/reflection/gpu-table.ts +44 -0
- package/src/reflection/inspection.ts +67 -0
- package/src/reflection/projection.ts +476 -0
- package/src/reflection/record-owner.ts +1283 -0
- package/src/render-contract.ts +93 -10
- package/src/render-graph-primitives.ts +9 -4
- package/src/render-pipeline.ts +122 -2
- package/src/render-system-extract.ts +1041 -225
- package/src/render-system.ts +1310 -85
- package/src/renderer.ts +222 -0
- package/src/scene/__tests__/changed-block-summary.candidate.test.ts +36 -0
- package/src/scene/probe-blend-record.ts +54 -0
- package/src/scene/probe-blend.ts +813 -0
- package/src/scene/render-scene-types.ts +0 -7
- package/src/scene/render-scene.ts +942 -171
- package/src/scene/visibility/bounds.ts +57 -0
- package/src/scene/visibility/budget.ts +40 -0
- package/src/scene/visibility/facet.ts +400 -0
- package/src/scene/visibility/gpu-frame-timing.ts +101 -0
- package/src/scene/visibility/gpu-lod.ts +119 -0
- package/src/scene/visibility/inspection.ts +313 -0
- package/src/scene/visibility/lod-selector.ts +84 -0
- package/src/scene/visibility/occlusion-confidence.ts +478 -0
- package/src/scene/visibility/occlusion-pass.ts +165 -0
- package/src/scene/visibility/occlusion-query-pool.ts +178 -0
- package/src/scene/visibility/occlusion-runtime.ts +672 -0
- package/src/scene/visibility/types.ts +50 -0
- package/src/shadow-atlas.ts +5 -5
- package/src/ssao-buffers.ts +9 -2
- package/src/ssr/admission.ts +451 -0
- package/src/ssr/composition.ts +73 -0
- package/src/ssr/errors.ts +76 -0
- package/src/ssr/identity.ts +12 -0
- package/src/systems/skin-palette-allocator.ts +1 -1
- 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-coordinator.ts +26 -0
- package/src/temporal/frame.ts +14 -1
- package/src/temporal/view.ts +11 -0
- package/src/tilemap-chunk-extract-system.ts +4 -4
- package/src/transmission/__tests__/standard-transmission.dawn.test.ts +59 -20
- package/src/typed-render-graph-primitives.ts +53 -3
- package/src/typed-shadow-passes.ts +46 -40
- package/src/volume/passes.ts +61 -58
- package/dist/.tsbuildinfo +0 -1
- package/dist/chunk-4XINDLAY.mjs.map +0 -1
- package/dist/chunk-CDTWTHZR.mjs.map +0 -1
- package/dist/chunk-M2MP4ZOU.mjs +0 -73
- package/dist/chunk-M2MP4ZOU.mjs.map +0 -1
- package/dist/chunk-PCHBPYML.mjs.map +0 -1
- package/dist/chunk-TBQJOK2L.mjs.map +0 -1
- package/dist/chunk-VFPLTKCU.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,6 +49,10 @@ import {
|
|
|
40
49
|
GPU_TEXTURE_USAGE_RENDER_ATTACHMENT,
|
|
41
50
|
GPU_TEXTURE_USAGE_TEXTURE_BINDING,
|
|
42
51
|
} from '../gpu-texture-usage';
|
|
52
|
+
import {
|
|
53
|
+
type StandardTopologyInputValue,
|
|
54
|
+
standardLightingTopologySignature,
|
|
55
|
+
} from '../pipeline/standard-lighting/topology';
|
|
43
56
|
import { resolveVolumetricFogProfile, STANDARD_PIPELINE_ID } from '../pipeline/standard-profile';
|
|
44
57
|
import type { CameraSnapshot } from '../render-contract';
|
|
45
58
|
import type {
|
|
@@ -48,6 +61,10 @@ import type {
|
|
|
48
61
|
RenderPipelineTopology,
|
|
49
62
|
} from '../render-pipeline';
|
|
50
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 { SsrAdmissionResult } from '../ssr/admission';
|
|
66
|
+
import type { RenderTarget } from '../targets/contracts';
|
|
67
|
+
import type { RenderTargetPhysical } from '../targets/physical';
|
|
51
68
|
import {
|
|
52
69
|
abortTemporalGpuSubmit,
|
|
53
70
|
commitTemporalGpuSubmit,
|
|
@@ -64,8 +81,15 @@ import { hasVolumetricFogCapability } from '../volume/capability';
|
|
|
64
81
|
import { deriveVolumetricFogExtent, deriveVolumetricFogResolvedExtent } from '../volume/resources';
|
|
65
82
|
import { buildPerFrameBindGroups } from './frame-lighting';
|
|
66
83
|
import { getTextureIdentity, type RenderFrameState } from './frame-snapshot';
|
|
84
|
+
import type { GpuPassTimingPassIdentity } from './gpu-pass-timing/contract.js';
|
|
85
|
+
import type { GpuPassTimingCapture, GpuPassTimingSession } from './gpu-pass-timing/session.js';
|
|
67
86
|
import type { GpuTimingCapture } from './gpu-timing';
|
|
68
|
-
import
|
|
87
|
+
import { encodeMainPass } from './main-pass';
|
|
88
|
+
import type {
|
|
89
|
+
_InternalRenderPipelineContext,
|
|
90
|
+
PipelineState,
|
|
91
|
+
RenderSystemInternals,
|
|
92
|
+
} from './render-context';
|
|
69
93
|
import { resolveSurfaceFormatPair, resolveSurfaceProfile } from './render-context';
|
|
70
94
|
|
|
71
95
|
export interface TemporalGraphCapabilities {
|
|
@@ -81,6 +105,97 @@ export interface TemporalGraphRoster {
|
|
|
81
105
|
readonly uploads: number;
|
|
82
106
|
}
|
|
83
107
|
|
|
108
|
+
export interface ReflectionFallbackGraphRoster {
|
|
109
|
+
readonly enabled: boolean;
|
|
110
|
+
readonly attachments: readonly string[];
|
|
111
|
+
readonly passes: readonly string[];
|
|
112
|
+
readonly bindings: readonly string[];
|
|
113
|
+
readonly historyCount: 0;
|
|
114
|
+
readonly temporalDemand: 0;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
export interface ReflectionFallbackGraphCandidate {
|
|
118
|
+
readonly generation: number;
|
|
119
|
+
readonly source: 'probe' | 'skylight' | 'neutral';
|
|
120
|
+
readonly roster: ReflectionFallbackGraphRoster;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
export interface SsrAdmissionGraphRoster {
|
|
124
|
+
readonly enabled: boolean;
|
|
125
|
+
readonly attachments: readonly string[];
|
|
126
|
+
readonly passes: readonly string[];
|
|
127
|
+
readonly bindings: readonly string[];
|
|
128
|
+
readonly historyCount: 0;
|
|
129
|
+
readonly temporalDemand: 0;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Admission is the sole switch for parent SSR graph work. A blocked result
|
|
134
|
+
* projects to an empty roster, so missing receipts cannot allocate or bind
|
|
135
|
+
* any SSR resource.
|
|
136
|
+
*/
|
|
137
|
+
export function createSsrAdmissionGraphRoster(
|
|
138
|
+
admission: Pick<SsrAdmissionResult, 'status'>,
|
|
139
|
+
): SsrAdmissionGraphRoster {
|
|
140
|
+
if (admission.status !== 'admitted') {
|
|
141
|
+
return {
|
|
142
|
+
enabled: false,
|
|
143
|
+
attachments: [],
|
|
144
|
+
passes: [],
|
|
145
|
+
bindings: [],
|
|
146
|
+
historyCount: 0,
|
|
147
|
+
temporalDemand: 0,
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
return {
|
|
151
|
+
enabled: true,
|
|
152
|
+
attachments: ['ssr-reflection-admission'],
|
|
153
|
+
passes: ['ssr-m0-admission'],
|
|
154
|
+
bindings: ['ssr-reflection-admission'],
|
|
155
|
+
historyCount: 0,
|
|
156
|
+
temporalDemand: 0,
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
export type ReflectionFallbackGraphFailure = 'compile-failed' | 'encode-failed' | 'submit-failed';
|
|
161
|
+
|
|
162
|
+
export function createReflectionFallbackGraphRoster(input: {
|
|
163
|
+
readonly fallbackDemand: boolean;
|
|
164
|
+
}): ReflectionFallbackGraphRoster {
|
|
165
|
+
if (!input.fallbackDemand) {
|
|
166
|
+
return {
|
|
167
|
+
enabled: false,
|
|
168
|
+
attachments: [],
|
|
169
|
+
passes: [],
|
|
170
|
+
bindings: [],
|
|
171
|
+
historyCount: 0,
|
|
172
|
+
temporalDemand: 0,
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
return {
|
|
176
|
+
enabled: true,
|
|
177
|
+
attachments: ['reflection-fallback-linear-hdr'],
|
|
178
|
+
passes: ['standard-main'],
|
|
179
|
+
bindings: ['reflection-fallback-output'],
|
|
180
|
+
historyCount: 0,
|
|
181
|
+
temporalDemand: 0,
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
export function commitReflectionFallbackGraph(
|
|
186
|
+
candidate: ReflectionFallbackGraphCandidate,
|
|
187
|
+
result:
|
|
188
|
+
| { readonly ok: true }
|
|
189
|
+
| { readonly ok: false; readonly reason: ReflectionFallbackGraphFailure },
|
|
190
|
+
): {
|
|
191
|
+
readonly visible: boolean;
|
|
192
|
+
readonly generation: number;
|
|
193
|
+
readonly source?: ReflectionFallbackGraphCandidate['source'];
|
|
194
|
+
} {
|
|
195
|
+
if (!result.ok || !candidate.roster.enabled) return { visible: false, generation: 0 };
|
|
196
|
+
return { visible: true, generation: candidate.generation, source: candidate.source };
|
|
197
|
+
}
|
|
198
|
+
|
|
84
199
|
function importTemporalHistoryTarget(
|
|
85
200
|
graph: RenderGraphBuilder<RenderPipelineFrame>,
|
|
86
201
|
label: string,
|
|
@@ -206,6 +321,465 @@ export function createTemporalGraphRoster(input: {
|
|
|
206
321
|
};
|
|
207
322
|
}
|
|
208
323
|
|
|
324
|
+
export interface CubeCaptureGraphWork {
|
|
325
|
+
readonly target: RenderTarget;
|
|
326
|
+
readonly faceIndex: number;
|
|
327
|
+
readonly physical: RenderTargetPhysical;
|
|
328
|
+
readonly faceCamera: import('../render-contract').CameraSnapshot;
|
|
329
|
+
readonly viewBindGroupDynamicOffset: number;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
export interface CubeCaptureGraphState {
|
|
333
|
+
work: readonly CubeCaptureGraphWork[];
|
|
334
|
+
reflectionProbes?: ReflectionProbeGraphState;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
export interface ReflectionProbeFilterGraphWork {
|
|
338
|
+
readonly probeIndex: number;
|
|
339
|
+
readonly faceIndex: number;
|
|
340
|
+
readonly mipLevel: number;
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
export interface ReflectionProbeFilterGraphState {
|
|
344
|
+
readonly work: readonly ReflectionProbeFilterGraphWork[];
|
|
345
|
+
readonly maxStepsPerFrame: number;
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
export interface ReflectionProbeGraphWork {
|
|
349
|
+
readonly probeIndex: number;
|
|
350
|
+
readonly rawTexture: Texture;
|
|
351
|
+
readonly rawCubeView: TextureView;
|
|
352
|
+
readonly rawFaceViews: readonly TextureView[];
|
|
353
|
+
readonly rawDepthTexture: Texture;
|
|
354
|
+
readonly rawCaptureFace: number | undefined;
|
|
355
|
+
readonly rawDepthView: TextureView;
|
|
356
|
+
readonly rawSize: number;
|
|
357
|
+
readonly faceCamera?: import('../render-contract').CameraSnapshot;
|
|
358
|
+
readonly viewBindGroupDynamicOffset?: number;
|
|
359
|
+
readonly filteredTexture: Texture;
|
|
360
|
+
readonly filteredCubeView: TextureView;
|
|
361
|
+
readonly filteredFaceViewsByMip: readonly (readonly TextureView[])[];
|
|
362
|
+
readonly outputFormat: TextureFormat;
|
|
363
|
+
readonly sampler: Sampler;
|
|
364
|
+
readonly filterPipeline: RenderPipeline;
|
|
365
|
+
readonly filterGroup0: BindGroup | undefined;
|
|
366
|
+
readonly filterGroup1: BindGroup;
|
|
367
|
+
readonly cubeVertexBuffer: Buffer;
|
|
368
|
+
readonly filteredSize: number;
|
|
369
|
+
readonly step: ReflectionProbeFilterGraphWork | undefined;
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
export interface ReflectionProbeGraphState {
|
|
373
|
+
readonly work: readonly ReflectionProbeGraphWork[];
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
export function boundedReflectionProbeFilterWork(
|
|
377
|
+
state: ReflectionProbeFilterGraphState,
|
|
378
|
+
): readonly ReflectionProbeFilterGraphWork[] {
|
|
379
|
+
return state.work.slice(0, Math.max(0, state.maxStepsPerFrame));
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
function renderTargetMipCount(work: CubeCaptureGraphWork): number {
|
|
383
|
+
const { descriptor } = work.physical;
|
|
384
|
+
return descriptor.mipLevels === 1
|
|
385
|
+
? 1
|
|
386
|
+
: Math.floor(Math.log2(Math.max(descriptor.width, descriptor.height))) + 1;
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
function addCubeCaptureGraphPasses(
|
|
390
|
+
builder: RenderGraphBuilder<RenderPipelineFrame>,
|
|
391
|
+
state: CubeCaptureGraphState,
|
|
392
|
+
): Result<void, RenderGraphError> {
|
|
393
|
+
for (let index = 0; index < state.work.length; index += 1) {
|
|
394
|
+
const slot = index;
|
|
395
|
+
const initial = state.work[slot];
|
|
396
|
+
if (initial === undefined) continue;
|
|
397
|
+
const current = (): CubeCaptureGraphWork => state.work[slot] ?? initial;
|
|
398
|
+
const texture = builder.importTexture(
|
|
399
|
+
`cube-capture.${slot}.texture`,
|
|
400
|
+
{
|
|
401
|
+
format: initial.physical.descriptor.format,
|
|
402
|
+
size: {
|
|
403
|
+
width: initial.physical.descriptor.width,
|
|
404
|
+
height: initial.physical.descriptor.height,
|
|
405
|
+
depthOrArrayLayers: initial.physical.descriptor.sampleCount === 4 ? 1 : 6,
|
|
406
|
+
},
|
|
407
|
+
mipLevelCount:
|
|
408
|
+
initial.physical.descriptor.sampleCount === 4 ? 1 : renderTargetMipCount(initial),
|
|
409
|
+
sampleCount: initial.physical.descriptor.sampleCount,
|
|
410
|
+
dimension: '2d',
|
|
411
|
+
usage: 0x10 | 0x04 | 0x01,
|
|
412
|
+
},
|
|
413
|
+
() => current().physical.colorTextures[current().faceIndex] ?? initial.physical.texture,
|
|
414
|
+
);
|
|
415
|
+
if (!texture.ok) return texture;
|
|
416
|
+
const color = builder.importView(
|
|
417
|
+
texture.value,
|
|
418
|
+
{
|
|
419
|
+
label: `cube-capture.${slot}.color`,
|
|
420
|
+
dimension: '2d',
|
|
421
|
+
baseMipLevel: 0,
|
|
422
|
+
mipLevelCount: 1,
|
|
423
|
+
baseArrayLayer: initial.physical.descriptor.sampleCount === 4 ? 0 : initial.faceIndex,
|
|
424
|
+
arrayLayerCount: 1,
|
|
425
|
+
},
|
|
426
|
+
() =>
|
|
427
|
+
current().physical.faceViews[current().faceIndex] ??
|
|
428
|
+
initial.physical.faceViews[initial.faceIndex] ??
|
|
429
|
+
initial.physical.view,
|
|
430
|
+
);
|
|
431
|
+
if (!color.ok) return color;
|
|
432
|
+
const depthTexture = builder.importTexture(
|
|
433
|
+
`cube-capture.${slot}.depth-texture`,
|
|
434
|
+
{
|
|
435
|
+
format: 'depth24plus-stencil8',
|
|
436
|
+
size: {
|
|
437
|
+
width: initial.physical.descriptor.width,
|
|
438
|
+
height: initial.physical.descriptor.height,
|
|
439
|
+
depthOrArrayLayers: initial.physical.descriptor.sampleCount === 4 ? 1 : 6,
|
|
440
|
+
},
|
|
441
|
+
mipLevelCount: 1,
|
|
442
|
+
sampleCount: initial.physical.descriptor.sampleCount,
|
|
443
|
+
dimension: '2d',
|
|
444
|
+
usage: 0x10,
|
|
445
|
+
},
|
|
446
|
+
() => current().physical.depthTextures[current().faceIndex] as Texture,
|
|
447
|
+
);
|
|
448
|
+
if (!depthTexture.ok) return depthTexture;
|
|
449
|
+
const depth = builder.importView(
|
|
450
|
+
depthTexture.value,
|
|
451
|
+
{
|
|
452
|
+
label: `cube-capture.${slot}.depth`,
|
|
453
|
+
dimension: '2d',
|
|
454
|
+
baseArrayLayer: initial.physical.descriptor.sampleCount === 4 ? 0 : initial.faceIndex,
|
|
455
|
+
arrayLayerCount: 1,
|
|
456
|
+
},
|
|
457
|
+
() => current().physical.depthViews[current().faceIndex] as TextureView,
|
|
458
|
+
);
|
|
459
|
+
if (!depth.ok) return depth;
|
|
460
|
+
const resolveTexture =
|
|
461
|
+
initial.physical.descriptor.sampleCount === 4
|
|
462
|
+
? builder.importTexture(
|
|
463
|
+
`cube-capture.${slot}.resolve-texture`,
|
|
464
|
+
{
|
|
465
|
+
format: initial.physical.descriptor.format,
|
|
466
|
+
size: {
|
|
467
|
+
width: initial.physical.descriptor.width,
|
|
468
|
+
height: initial.physical.descriptor.height,
|
|
469
|
+
depthOrArrayLayers: 6,
|
|
470
|
+
},
|
|
471
|
+
mipLevelCount: renderTargetMipCount(initial),
|
|
472
|
+
sampleCount: 1,
|
|
473
|
+
dimension: '2d',
|
|
474
|
+
usage: 0x10 | 0x04 | 0x01,
|
|
475
|
+
},
|
|
476
|
+
() =>
|
|
477
|
+
current().physical.resolveTexture ??
|
|
478
|
+
initial.physical.resolveTexture ??
|
|
479
|
+
initial.physical.texture,
|
|
480
|
+
)
|
|
481
|
+
: undefined;
|
|
482
|
+
if (resolveTexture !== undefined && !resolveTexture.ok) return resolveTexture;
|
|
483
|
+
const resolve =
|
|
484
|
+
resolveTexture === undefined
|
|
485
|
+
? undefined
|
|
486
|
+
: builder.importView(
|
|
487
|
+
resolveTexture.value,
|
|
488
|
+
{
|
|
489
|
+
label: `cube-capture.${slot}.resolve`,
|
|
490
|
+
dimension: '2d',
|
|
491
|
+
baseMipLevel: 0,
|
|
492
|
+
mipLevelCount: 1,
|
|
493
|
+
baseArrayLayer: initial.faceIndex,
|
|
494
|
+
arrayLayerCount: 1,
|
|
495
|
+
},
|
|
496
|
+
() =>
|
|
497
|
+
current().physical.resolveFaceViews[current().faceIndex] ??
|
|
498
|
+
initial.physical.resolveFaceViews[initial.faceIndex] ??
|
|
499
|
+
initial.physical.resolveView,
|
|
500
|
+
);
|
|
501
|
+
if (resolve !== undefined && !resolve.ok) return resolve;
|
|
502
|
+
const added = builder.addRasterPass(`cube-capture-face.${slot}`, {
|
|
503
|
+
accesses: [
|
|
504
|
+
{ resource: color.value, usage: 'color-attachment' },
|
|
505
|
+
{ resource: depth.value, usage: 'depth-stencil-write' },
|
|
506
|
+
...(resolve === undefined
|
|
507
|
+
? []
|
|
508
|
+
: [{ resource: resolve.value, usage: 'color-attachment' as const }]),
|
|
509
|
+
],
|
|
510
|
+
colorAttachments: [
|
|
511
|
+
{
|
|
512
|
+
view: color.value,
|
|
513
|
+
...(resolve === undefined ? {} : { resolveTarget: resolve.value }),
|
|
514
|
+
loadOp: 'clear',
|
|
515
|
+
storeOp: 'store',
|
|
516
|
+
clearValue: () => {
|
|
517
|
+
return { r: 0, g: 0, b: 0, a: 1 };
|
|
518
|
+
},
|
|
519
|
+
},
|
|
520
|
+
],
|
|
521
|
+
depthStencilAttachment: {
|
|
522
|
+
view: depth.value,
|
|
523
|
+
depthClearValue: 1,
|
|
524
|
+
depthLoadOp: 'clear',
|
|
525
|
+
depthStoreOp: 'store',
|
|
526
|
+
stencilClearValue: 0,
|
|
527
|
+
stencilLoadOp: 'clear',
|
|
528
|
+
stencilStoreOp: 'store',
|
|
529
|
+
},
|
|
530
|
+
encode: ({ pass, frame, resources }) => {
|
|
531
|
+
const internal = frame as _InternalRenderPipelineContext;
|
|
532
|
+
const captureColor = resources.textureView(color.value);
|
|
533
|
+
if (!captureColor.ok) return;
|
|
534
|
+
const captureDepth = resources.textureView(depth.value);
|
|
535
|
+
if (!captureDepth.ok) return;
|
|
536
|
+
const captureResolve =
|
|
537
|
+
resolve === undefined ? undefined : resources.textureView(resolve.value);
|
|
538
|
+
if (resolve !== undefined && (captureResolve === undefined || !captureResolve.ok)) return;
|
|
539
|
+
const captureResolveView = captureResolve?.ok ? captureResolve.value : null;
|
|
540
|
+
const captureContext = {
|
|
541
|
+
...internal,
|
|
542
|
+
gpuDrivenEntityKeys: new Set<number>(),
|
|
543
|
+
camera: current().faceCamera,
|
|
544
|
+
// Cube faces are raw scene captures, not display-camera HDR output.
|
|
545
|
+
// Select the PSO against the actual target attachment so an LDR
|
|
546
|
+
// cube target is rendered by a compatible forward pipeline.
|
|
547
|
+
tonemapActive: false,
|
|
548
|
+
skyboxActive: false,
|
|
549
|
+
transparentColorFormat: initial.physical.descriptor.format as GPUTextureFormat,
|
|
550
|
+
msaaActive: initial.physical.descriptor.sampleCount === 4,
|
|
551
|
+
viewBindGroupDynamicOffset: current().viewBindGroupDynamicOffset,
|
|
552
|
+
geometryColorView: captureColor.value,
|
|
553
|
+
geometryDepthView: captureDepth.value,
|
|
554
|
+
geometryColorResolveView: captureResolveView,
|
|
555
|
+
splitLdrSprite: false,
|
|
556
|
+
ldrSpritePassView: null,
|
|
557
|
+
};
|
|
558
|
+
encodeMainPass(captureContext, pass, undefined, {
|
|
559
|
+
colorViews: [captureColor.value],
|
|
560
|
+
colorFormats: [initial.physical.descriptor.format as GPUTextureFormat],
|
|
561
|
+
depthView: captureDepth.value,
|
|
562
|
+
passKind: 'forward',
|
|
563
|
+
clearColor: [0, 0, 0, 1],
|
|
564
|
+
});
|
|
565
|
+
},
|
|
566
|
+
});
|
|
567
|
+
if (!added.ok) return added;
|
|
568
|
+
}
|
|
569
|
+
return ok(undefined);
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
export function addReflectionProbeGraphPasses(
|
|
573
|
+
builder: RenderGraphBuilder<RenderPipelineFrame>,
|
|
574
|
+
state: ReflectionProbeGraphState,
|
|
575
|
+
): Result<readonly import('@forgeax/engine-render-graph').GraphAccess[], RenderGraphError> {
|
|
576
|
+
const accesses: import('@forgeax/engine-render-graph').GraphAccess[] = [];
|
|
577
|
+
for (const work of state.work) {
|
|
578
|
+
const raw = builder.importTexture(
|
|
579
|
+
`reflection-probe.${work.probeIndex}.raw`,
|
|
580
|
+
{
|
|
581
|
+
format: work.outputFormat,
|
|
582
|
+
size: { width: work.rawSize, height: work.rawSize, depthOrArrayLayers: 6 },
|
|
583
|
+
mipLevelCount: 1,
|
|
584
|
+
sampleCount: 1,
|
|
585
|
+
dimension: '2d',
|
|
586
|
+
usage: 0x10 | 0x04 | 0x01,
|
|
587
|
+
},
|
|
588
|
+
() => work.rawTexture,
|
|
589
|
+
);
|
|
590
|
+
if (!raw.ok) return raw;
|
|
591
|
+
const rawCube = builder.importView(
|
|
592
|
+
raw.value,
|
|
593
|
+
{
|
|
594
|
+
label: `reflection-probe.${work.probeIndex}.raw-cube`,
|
|
595
|
+
dimension: 'cube',
|
|
596
|
+
arrayLayerCount: 6,
|
|
597
|
+
},
|
|
598
|
+
() => work.rawCubeView,
|
|
599
|
+
);
|
|
600
|
+
if (!rawCube.ok) return rawCube;
|
|
601
|
+
const filtered = builder.importTexture(
|
|
602
|
+
`reflection-probe.${work.probeIndex}.filtered`,
|
|
603
|
+
{
|
|
604
|
+
format: work.outputFormat,
|
|
605
|
+
size: { width: work.filteredSize, height: work.filteredSize, depthOrArrayLayers: 6 },
|
|
606
|
+
mipLevelCount: work.filteredFaceViewsByMip.length,
|
|
607
|
+
sampleCount: 1,
|
|
608
|
+
dimension: '2d',
|
|
609
|
+
usage: 0x10 | 0x04 | 0x01,
|
|
610
|
+
},
|
|
611
|
+
() => work.filteredTexture,
|
|
612
|
+
);
|
|
613
|
+
if (!filtered.ok) return filtered;
|
|
614
|
+
const filteredCube = builder.importView(
|
|
615
|
+
filtered.value,
|
|
616
|
+
{
|
|
617
|
+
label: `reflection-probe.${work.probeIndex}.filtered-cube`,
|
|
618
|
+
dimension: 'cube',
|
|
619
|
+
baseMipLevel: 0,
|
|
620
|
+
mipLevelCount: work.filteredFaceViewsByMip.length,
|
|
621
|
+
arrayLayerCount: 6,
|
|
622
|
+
},
|
|
623
|
+
() => work.filteredCubeView,
|
|
624
|
+
);
|
|
625
|
+
if (!filteredCube.ok) return filteredCube;
|
|
626
|
+
if (work.rawCaptureFace !== undefined) {
|
|
627
|
+
const face = work.rawCaptureFace;
|
|
628
|
+
const view = builder.importView(
|
|
629
|
+
raw.value,
|
|
630
|
+
{
|
|
631
|
+
label: `reflection-probe.${work.probeIndex}.capture-face-${face}`,
|
|
632
|
+
dimension: '2d',
|
|
633
|
+
baseArrayLayer: face,
|
|
634
|
+
arrayLayerCount: 1,
|
|
635
|
+
},
|
|
636
|
+
() => work.rawFaceViews[face] as TextureView,
|
|
637
|
+
);
|
|
638
|
+
if (!view.ok) return view;
|
|
639
|
+
const depthTexture = builder.importTexture(
|
|
640
|
+
`reflection-probe.${work.probeIndex}.capture-depth`,
|
|
641
|
+
{
|
|
642
|
+
format: 'depth24plus-stencil8',
|
|
643
|
+
size: { width: work.rawSize, height: work.rawSize, depthOrArrayLayers: 1 },
|
|
644
|
+
mipLevelCount: 1,
|
|
645
|
+
sampleCount: 1,
|
|
646
|
+
dimension: '2d',
|
|
647
|
+
usage: 0x10,
|
|
648
|
+
},
|
|
649
|
+
() => work.rawDepthTexture,
|
|
650
|
+
);
|
|
651
|
+
if (!depthTexture.ok) return depthTexture;
|
|
652
|
+
const depth = builder.importView(
|
|
653
|
+
depthTexture.value,
|
|
654
|
+
{ label: `reflection-probe.${work.probeIndex}.capture-depth-view`, dimension: '2d' },
|
|
655
|
+
() => work.rawDepthView,
|
|
656
|
+
);
|
|
657
|
+
if (!depth.ok) return depth;
|
|
658
|
+
const added = builder.addRasterPass(`reflection-probe.${work.probeIndex}.capture.${face}`, {
|
|
659
|
+
accesses: [
|
|
660
|
+
{ resource: view.value, usage: 'color-attachment' },
|
|
661
|
+
{ resource: depth.value, usage: 'depth-stencil-write' },
|
|
662
|
+
],
|
|
663
|
+
colorAttachments: [
|
|
664
|
+
{
|
|
665
|
+
view: view.value,
|
|
666
|
+
loadOp: 'clear',
|
|
667
|
+
storeOp: 'store',
|
|
668
|
+
clearValue: { r: 0, g: 0, b: 0, a: 1 },
|
|
669
|
+
},
|
|
670
|
+
],
|
|
671
|
+
depthStencilAttachment: {
|
|
672
|
+
view: depth.value,
|
|
673
|
+
depthClearValue: 1,
|
|
674
|
+
depthLoadOp: 'clear',
|
|
675
|
+
depthStoreOp: 'store',
|
|
676
|
+
stencilClearValue: 0,
|
|
677
|
+
stencilLoadOp: 'clear',
|
|
678
|
+
stencilStoreOp: 'store',
|
|
679
|
+
},
|
|
680
|
+
encode: ({ pass, frame, resources }) => {
|
|
681
|
+
const internal = frame as _InternalRenderPipelineContext;
|
|
682
|
+
const captureColor = resources.textureView(view.value);
|
|
683
|
+
const captureDepth = resources.textureView(depth.value);
|
|
684
|
+
if (!captureColor.ok || !captureDepth.ok) return;
|
|
685
|
+
if (work.faceCamera === undefined || work.viewBindGroupDynamicOffset === undefined)
|
|
686
|
+
return;
|
|
687
|
+
encodeMainPass(
|
|
688
|
+
{
|
|
689
|
+
...internal,
|
|
690
|
+
camera: work.faceCamera,
|
|
691
|
+
viewBindGroupDynamicOffset: work.viewBindGroupDynamicOffset,
|
|
692
|
+
geometryColorView: captureColor.value,
|
|
693
|
+
geometryDepthView: captureDepth.value,
|
|
694
|
+
geometryColorResolveView: null,
|
|
695
|
+
transparentColorFormat: work.outputFormat as GPUTextureFormat,
|
|
696
|
+
msaaActive: false,
|
|
697
|
+
splitLdrSprite: false,
|
|
698
|
+
ldrSpritePassView: null,
|
|
699
|
+
},
|
|
700
|
+
pass,
|
|
701
|
+
undefined,
|
|
702
|
+
{
|
|
703
|
+
colorViews: [captureColor.value],
|
|
704
|
+
colorFormats: [work.outputFormat as GPUTextureFormat],
|
|
705
|
+
depthView: captureDepth.value,
|
|
706
|
+
passKind: 'forward',
|
|
707
|
+
clearColor: [0, 0, 0, 1],
|
|
708
|
+
},
|
|
709
|
+
);
|
|
710
|
+
},
|
|
711
|
+
});
|
|
712
|
+
if (!added.ok) return added;
|
|
713
|
+
}
|
|
714
|
+
const step = work.step;
|
|
715
|
+
if (step !== undefined) {
|
|
716
|
+
const mipViews = work.filteredFaceViewsByMip[step.mipLevel];
|
|
717
|
+
const outputView = mipViews?.[step.faceIndex];
|
|
718
|
+
if (outputView === undefined) {
|
|
719
|
+
return err(
|
|
720
|
+
new RenderGraphError({
|
|
721
|
+
code: 'resource-resolution-failed',
|
|
722
|
+
expected: 'every scheduled probe mip has a filtered face view',
|
|
723
|
+
hint: 'rebuild the renderer-owned probe output before compiling the Standard graph',
|
|
724
|
+
detail: {
|
|
725
|
+
resourceLabel: `reflection-probe.${work.probeIndex}.filtered`,
|
|
726
|
+
passName: 'pmrem',
|
|
727
|
+
},
|
|
728
|
+
}),
|
|
729
|
+
);
|
|
730
|
+
}
|
|
731
|
+
const output = builder.importView(
|
|
732
|
+
filtered.value,
|
|
733
|
+
{
|
|
734
|
+
label: `reflection-probe.${work.probeIndex}.filtered-mip${step.mipLevel}-face${step.faceIndex}`,
|
|
735
|
+
dimension: '2d',
|
|
736
|
+
baseMipLevel: step.mipLevel,
|
|
737
|
+
mipLevelCount: 1,
|
|
738
|
+
baseArrayLayer: step.faceIndex,
|
|
739
|
+
arrayLayerCount: 1,
|
|
740
|
+
},
|
|
741
|
+
() => outputView,
|
|
742
|
+
);
|
|
743
|
+
if (!output.ok) return output;
|
|
744
|
+
const added = builder.addRasterPass(
|
|
745
|
+
`reflection-probe.${work.probeIndex}.pmrem.${step.mipLevel}.${step.faceIndex}`,
|
|
746
|
+
{
|
|
747
|
+
accesses: [
|
|
748
|
+
{ resource: rawCube.value, usage: 'sampled-read' },
|
|
749
|
+
{ resource: output.value, usage: 'color-attachment' },
|
|
750
|
+
],
|
|
751
|
+
colorAttachments: [
|
|
752
|
+
{
|
|
753
|
+
view: output.value,
|
|
754
|
+
loadOp: 'clear',
|
|
755
|
+
storeOp: 'store',
|
|
756
|
+
clearValue: { r: 0, g: 0, b: 0, a: 1 },
|
|
757
|
+
},
|
|
758
|
+
],
|
|
759
|
+
encode: ({ pass }) => {
|
|
760
|
+
if (work.filterGroup0 === undefined) return;
|
|
761
|
+
pass.setPipeline(work.filterPipeline);
|
|
762
|
+
pass.setBindGroup(0, work.filterGroup0);
|
|
763
|
+
pass.setBindGroup(1, work.filterGroup1);
|
|
764
|
+
pass.setVertexBuffer(0, work.cubeVertexBuffer);
|
|
765
|
+
pass.draw(6, 1, step.faceIndex * 6, 0);
|
|
766
|
+
},
|
|
767
|
+
},
|
|
768
|
+
);
|
|
769
|
+
if (!added.ok) return added;
|
|
770
|
+
}
|
|
771
|
+
accesses.push({ resource: filteredCube.value, usage: 'sampled-read' });
|
|
772
|
+
}
|
|
773
|
+
return ok(accesses);
|
|
774
|
+
}
|
|
775
|
+
|
|
776
|
+
export {
|
|
777
|
+
projectRenderTargetGraph,
|
|
778
|
+
type RenderTargetGraphInput,
|
|
779
|
+
type RenderTargetGraphProjection,
|
|
780
|
+
type RenderTargetGraphSubresource,
|
|
781
|
+
} from '../targets/graph-projection';
|
|
782
|
+
|
|
209
783
|
export interface RenderFeatureGraphRuntimeState {
|
|
210
784
|
plans: readonly RenderFeaturePlannedFrame[];
|
|
211
785
|
fullscreenEffects: ReadonlyMap<
|
|
@@ -230,10 +804,24 @@ export interface RenderFeatureGraphCandidate {
|
|
|
230
804
|
readonly preparedResourceKey?: string;
|
|
231
805
|
/** Release candidate-owned prepared resources when graph promotion fails. */
|
|
232
806
|
readonly onRejected?: () => void;
|
|
807
|
+
/** Publish candidate-owned runtime declarations only after graph promotion. */
|
|
808
|
+
readonly onAccepted?: () => void;
|
|
809
|
+
/** Discard candidate-only resources when a base graph is kept as fallback. */
|
|
810
|
+
readonly onAbandoned?: () => void;
|
|
233
811
|
}
|
|
234
812
|
|
|
235
813
|
const featureGraphStates = new WeakMap<RenderSystemInternals, RenderFeatureGraphRuntimeState>();
|
|
236
814
|
|
|
815
|
+
interface TimingInstrumentationState {
|
|
816
|
+
readonly instrumentation: RenderGraphPassInstrumentation<RenderPipelineFrame>;
|
|
817
|
+
setCapture(capture: GpuPassTimingCapture | undefined): void;
|
|
818
|
+
}
|
|
819
|
+
|
|
820
|
+
const timingInstrumentationStates = new WeakMap<
|
|
821
|
+
RenderSystemInternals,
|
|
822
|
+
TimingInstrumentationState
|
|
823
|
+
>();
|
|
824
|
+
|
|
237
825
|
type CompiledGraphTargetAccess = CompiledRenderGraph<RenderPipelineFrame> & {
|
|
238
826
|
readonly getColorTargetDescriptor: (
|
|
239
827
|
name: string,
|
|
@@ -284,6 +872,31 @@ export function renderFeatureGraphPlanSignature(
|
|
|
284
872
|
);
|
|
285
873
|
}
|
|
286
874
|
|
|
875
|
+
/**
|
|
876
|
+
* Admit fullscreen post-processes as one chain, never as independent passes.
|
|
877
|
+
* A pass whose shader module is still compiling cannot clear a graph target and
|
|
878
|
+
* leave the remainder of the chain sampling an undefined intermediate. The
|
|
879
|
+
* renderer therefore keeps the base output-transform graph until every
|
|
880
|
+
* requested effect is ready, then admits the complete ordered chain together.
|
|
881
|
+
*/
|
|
882
|
+
export function resolvePostProcessChainAdmission(
|
|
883
|
+
effects: readonly string[],
|
|
884
|
+
isReady: (identity: string) => boolean,
|
|
885
|
+
): { readonly admitted: readonly string[]; readonly pending: boolean } {
|
|
886
|
+
// Probe every declaration even after the first miss. A single frame may
|
|
887
|
+
// introduce several effects; evaluating all of them lets the shared cache
|
|
888
|
+
// start every independent compile together instead of serialising warmup on
|
|
889
|
+
// array order.
|
|
890
|
+
let ready = true;
|
|
891
|
+
for (const identity of effects) {
|
|
892
|
+
if (!isReady(identity)) ready = false;
|
|
893
|
+
}
|
|
894
|
+
return {
|
|
895
|
+
admitted: ready ? effects : [],
|
|
896
|
+
pending: !ready,
|
|
897
|
+
};
|
|
898
|
+
}
|
|
899
|
+
|
|
287
900
|
function validateRenderFeaturePlans(
|
|
288
901
|
plans: readonly RenderFeaturePlannedFrame[],
|
|
289
902
|
): Result<readonly RenderFeaturePlanExecution[], RenderError> {
|
|
@@ -314,6 +927,10 @@ function commitFeatureCandidate(
|
|
|
314
927
|
internals: RenderSystemInternals,
|
|
315
928
|
candidate: RenderFeatureGraphCandidate,
|
|
316
929
|
): void {
|
|
930
|
+
// Publish renderer-owned declarations only after their device resources have
|
|
931
|
+
// been admitted. If the acceptance hook throws, the previously accepted
|
|
932
|
+
// graph/state pair remains visible to the caller.
|
|
933
|
+
candidate.onAccepted?.();
|
|
317
934
|
const state = getRenderFeatureGraphState(internals);
|
|
318
935
|
state.plans = candidate.plans;
|
|
319
936
|
state.fullscreenEffects = candidate.fullscreenEffects;
|
|
@@ -331,8 +948,10 @@ function topologyOf(
|
|
|
331
948
|
shadowMapSize: number | undefined,
|
|
332
949
|
gpuDriven: PreparedGpuDrivenFrame | undefined,
|
|
333
950
|
featureGraphCandidate: RenderFeatureGraphCandidate | undefined,
|
|
951
|
+
cubeCaptureState: CubeCaptureGraphState | undefined,
|
|
334
952
|
transmissionDemand: TransmissionDemand | undefined,
|
|
335
953
|
volumetricFog: ExtractedVolumetricFog | undefined,
|
|
954
|
+
standardLighting: StandardTopologyInputValue | undefined,
|
|
336
955
|
): Result<RenderPipelineTopology, RhiError> {
|
|
337
956
|
const cascadeCount = Math.max(1, Math.min(4, Math.round(lights.cascadeCount ?? 1))) as
|
|
338
957
|
| 1
|
|
@@ -357,6 +976,10 @@ function topologyOf(
|
|
|
357
976
|
...(featureGraphCandidate?.fullscreenEffects ??
|
|
358
977
|
getRenderFeatureGraphState(internals).fullscreenEffects),
|
|
359
978
|
].map(([id]) => id);
|
|
979
|
+
const featurePostEffectDeclarations = [
|
|
980
|
+
...(featureGraphCandidate?.fullscreenEffects ??
|
|
981
|
+
getRenderFeatureGraphState(internals).fullscreenEffects),
|
|
982
|
+
].map(([id, entry]) => [id, postProcessShaderEntrySignature(entry)] as const);
|
|
360
983
|
const config =
|
|
361
984
|
featurePostEffects.length === 0
|
|
362
985
|
? frameState.installedPipelineConfig
|
|
@@ -389,6 +1012,7 @@ function topologyOf(
|
|
|
389
1012
|
standardProfile: internals.standardProfile,
|
|
390
1013
|
config,
|
|
391
1014
|
clearOnly,
|
|
1015
|
+
reflectionFallback: { enabled: frameState.reflectionFallbackDemand === true },
|
|
392
1016
|
surface: {
|
|
393
1017
|
width,
|
|
394
1018
|
height,
|
|
@@ -406,10 +1030,13 @@ function topologyOf(
|
|
|
406
1030
|
motionBlur: isMotionBlurTemporalDemand(camera.motionBlur),
|
|
407
1031
|
},
|
|
408
1032
|
shadow: {
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
1033
|
+
directional:
|
|
1034
|
+
shadowMapSize === undefined || lights.cascadeCount === undefined
|
|
1035
|
+
? 'disabled'
|
|
1036
|
+
: { mapSize: shadowMapSize, cascadeCount },
|
|
1037
|
+
spotMapSize: shadowMapSize ?? 1024,
|
|
1038
|
+
pointCount: Math.min(SHADOW_ATLAS_DEFAULT_LAYERS, lights.pointShadow.length),
|
|
1039
|
+
pointFaceSize: lights.pointShadow[0]?.mapSize ?? SHADOW_ATLAS_DEFAULT_FACE_SIZE,
|
|
413
1040
|
spotCount: Math.min(
|
|
414
1041
|
4,
|
|
415
1042
|
lights.spot.filter(
|
|
@@ -468,10 +1095,12 @@ function topologyOf(
|
|
|
468
1095
|
plans: renderFeatureGraphPlanSignature(
|
|
469
1096
|
featureGraphCandidate?.plans ?? getRenderFeatureGraphState(internals).plans,
|
|
470
1097
|
),
|
|
471
|
-
fullscreenEffects:
|
|
1098
|
+
fullscreenEffects: featurePostEffectDeclarations,
|
|
472
1099
|
preparedResourceKey: featureGraphCandidate?.preparedResourceKey ?? '',
|
|
1100
|
+
cubeCaptureSlots: cubeCaptureState?.work.length ?? 0,
|
|
473
1101
|
}),
|
|
474
1102
|
gpuDrivenTopologySignature: gpuDriven?.topologySignature ?? '',
|
|
1103
|
+
standardLightingTopologySignature: standardLightingTopologySignature(standardLighting),
|
|
475
1104
|
transmissionDemand: transmissionDemand ?? {
|
|
476
1105
|
activeCount: 0,
|
|
477
1106
|
needsRoughMips: false,
|
|
@@ -527,14 +1156,17 @@ function targetResolver(
|
|
|
527
1156
|
};
|
|
528
1157
|
}
|
|
529
1158
|
|
|
530
|
-
function resolveTargetBindings(
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
readonly
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
1159
|
+
function resolveTargetBindings(
|
|
1160
|
+
input: {
|
|
1161
|
+
readonly frame: RenderPipelineFrame;
|
|
1162
|
+
readonly binding: import('../prepare/prepared-graphics-resolver').PreparedGraphicsResolvedResource & {
|
|
1163
|
+
readonly kind: 'bindings';
|
|
1164
|
+
};
|
|
1165
|
+
readonly resources: GraphResourceResolver;
|
|
1166
|
+
readonly resolveTarget: RenderFeatureGraphTargetResolver;
|
|
1167
|
+
},
|
|
1168
|
+
featurePostProcessEntries?: ReadonlyMap<string, PostProcessShaderEntry>,
|
|
1169
|
+
): RenderFeatureGraphBindingsResolution | undefined {
|
|
538
1170
|
const frame = input.frame as import('./render-context')._InternalRenderPipelineContext;
|
|
539
1171
|
const descriptor = input.binding.descriptor;
|
|
540
1172
|
const pipeline = input.binding.pipeline as
|
|
@@ -546,7 +1178,8 @@ function resolveTargetBindings(input: {
|
|
|
546
1178
|
if (descriptor?.values.fullscreen === true && isTemporalFullscreenBinding(descriptor.values)) {
|
|
547
1179
|
const shader = descriptor.values.shader;
|
|
548
1180
|
if (typeof shader !== 'string') return undefined;
|
|
549
|
-
const entry =
|
|
1181
|
+
const entry =
|
|
1182
|
+
featurePostProcessEntries?.get(shader) ?? frame.runtime.lookupPostProcess?.(shader);
|
|
550
1183
|
if (entry === undefined) return undefined;
|
|
551
1184
|
const fullscreen = buildFullscreenPostProcessPass(
|
|
552
1185
|
{ device: frame.runtime.device, errorRegistry: frame.runtime.errorRegistry },
|
|
@@ -636,8 +1269,10 @@ function resolveTargetBindings(input: {
|
|
|
636
1269
|
directionalShadow: frame.frameState.currentDirectionalShadowView ?? undefined,
|
|
637
1270
|
spotShadow: frame.frameState.currentSpotShadowView ?? undefined,
|
|
638
1271
|
},
|
|
1272
|
+
true,
|
|
1273
|
+
frame.standardLighting,
|
|
639
1274
|
).viewBindGroup;
|
|
640
|
-
return viewBindGroup === null ? undefined : { handle: viewBindGroup, dynamicOffsets: [0] };
|
|
1275
|
+
return viewBindGroup === null ? undefined : { handle: viewBindGroup, dynamicOffsets: [0, 0] };
|
|
641
1276
|
}
|
|
642
1277
|
const target = input.resolveTarget(sceneDepth);
|
|
643
1278
|
if (target === undefined) return undefined;
|
|
@@ -707,11 +1342,20 @@ export function ensureCompiledFrameGraph(
|
|
|
707
1342
|
shadowMapSize: number | undefined,
|
|
708
1343
|
gpuDriven?: PreparedGpuDrivenFrame,
|
|
709
1344
|
featureGraphCandidate?: RenderFeatureGraphCandidate,
|
|
1345
|
+
cubeCaptureState?: CubeCaptureGraphState,
|
|
710
1346
|
clearOnly = false,
|
|
711
1347
|
transmissionDemand?: TransmissionDemand,
|
|
1348
|
+
occlusion?: import('../scene/visibility/occlusion-runtime').OcclusionFrameProjection,
|
|
712
1349
|
volumetricFog?: ExtractedVolumetricFog,
|
|
713
1350
|
volumeTopologyCandidate = false,
|
|
1351
|
+
standardLighting?: StandardTopologyInputValue,
|
|
714
1352
|
): CompiledRenderGraph<RenderPipelineFrame> | null {
|
|
1353
|
+
const requestedStandardLightingSignature = standardLightingTopologySignature(standardLighting);
|
|
1354
|
+
const lastKnownGood = (): CompiledRenderGraph<RenderPipelineFrame> | null =>
|
|
1355
|
+
frameState.compiledFrameGraph !== null &&
|
|
1356
|
+
frameState.standardLightingGraphSignature === requestedStandardLightingSignature
|
|
1357
|
+
? frameState.compiledFrameGraph
|
|
1358
|
+
: null;
|
|
715
1359
|
const surfaceWidth = Math.max(1, width);
|
|
716
1360
|
const surfaceHeight = Math.max(1, height);
|
|
717
1361
|
const featurePlans = featureGraphCandidate?.plans ?? getRenderFeatureGraphState(internals).plans;
|
|
@@ -719,7 +1363,7 @@ export function ensureCompiledFrameGraph(
|
|
|
719
1363
|
if (!projectedFeaturePlans.ok) {
|
|
720
1364
|
reportRenderFeatureGraphError(internals, projectedFeaturePlans.error);
|
|
721
1365
|
featureGraphCandidate?.onRejected?.();
|
|
722
|
-
return volumeTopologyCandidate ? null :
|
|
1366
|
+
return volumeTopologyCandidate ? null : lastKnownGood();
|
|
723
1367
|
}
|
|
724
1368
|
const topologyResult = topologyOf(
|
|
725
1369
|
internals,
|
|
@@ -733,19 +1377,92 @@ export function ensureCompiledFrameGraph(
|
|
|
733
1377
|
shadowMapSize,
|
|
734
1378
|
gpuDriven,
|
|
735
1379
|
featureGraphCandidate,
|
|
1380
|
+
cubeCaptureState,
|
|
736
1381
|
transmissionDemand,
|
|
737
1382
|
volumetricFog,
|
|
1383
|
+
standardLighting,
|
|
738
1384
|
);
|
|
739
1385
|
if (!topologyResult.ok) {
|
|
740
1386
|
internals.errorRegistry.fire(topologyResult.error);
|
|
741
1387
|
featureGraphCandidate?.onRejected?.();
|
|
742
|
-
return volumeTopologyCandidate ? null :
|
|
1388
|
+
return volumeTopologyCandidate ? null : lastKnownGood();
|
|
1389
|
+
}
|
|
1390
|
+
const requestedPostEffects = topologyResult.value.config?.postEffects ?? [];
|
|
1391
|
+
const featurePostProcessEntries =
|
|
1392
|
+
featureGraphCandidate?.fullscreenEffects ??
|
|
1393
|
+
getRenderFeatureGraphState(internals).fullscreenEffects;
|
|
1394
|
+
const postProcessAdmission = resolvePostProcessChainAdmission(
|
|
1395
|
+
requestedPostEffects,
|
|
1396
|
+
(identity) => {
|
|
1397
|
+
const entry =
|
|
1398
|
+
featurePostProcessEntries.get(identity) ?? internals.lookupPostProcess?.(identity);
|
|
1399
|
+
// Preserve the existing missing-entry failure contract. The graph will
|
|
1400
|
+
// report post-process-not-found during record instead of silently
|
|
1401
|
+
// removing an authored id from the topology.
|
|
1402
|
+
if (entry === undefined) return true;
|
|
1403
|
+
const buildPipeline = internals.buildPostProcessPipeline;
|
|
1404
|
+
const getPipeline = internals.getPostProcessPipeline;
|
|
1405
|
+
if (buildPipeline === undefined || getPipeline === undefined) return true;
|
|
1406
|
+
const built = buildFullscreenPostProcessPass(
|
|
1407
|
+
{ device: internals.device, errorRegistry: internals.errorRegistry },
|
|
1408
|
+
entry,
|
|
1409
|
+
camera.antialias === 'msaa' && topologyResult.value.lane.multisample,
|
|
1410
|
+
);
|
|
1411
|
+
if (built === null) return false;
|
|
1412
|
+
return (
|
|
1413
|
+
getPipeline(
|
|
1414
|
+
identity,
|
|
1415
|
+
built.bindGroupLayout,
|
|
1416
|
+
topologyResult.value.surface.storageFormat as GPUTextureFormat,
|
|
1417
|
+
entry,
|
|
1418
|
+
) !== null
|
|
1419
|
+
);
|
|
1420
|
+
},
|
|
1421
|
+
);
|
|
1422
|
+
const acceptedLkg = lastKnownGood();
|
|
1423
|
+
if (postProcessAdmission.pending && acceptedLkg !== null) {
|
|
1424
|
+
// Do not publish a candidate whose fullscreen chain is only partially
|
|
1425
|
+
// ready. Keep the accepted graph (including its prior post-effect chain)
|
|
1426
|
+
// and retry the same feature candidate on the next frame.
|
|
1427
|
+
featureGraphCandidate?.onRejected?.();
|
|
1428
|
+
return acceptedLkg;
|
|
743
1429
|
}
|
|
744
|
-
const topology =
|
|
745
|
-
|
|
1430
|
+
const topology = postProcessAdmission.pending
|
|
1431
|
+
? {
|
|
1432
|
+
...topologyResult.value,
|
|
1433
|
+
config: {
|
|
1434
|
+
...(topologyResult.value.config ?? {}),
|
|
1435
|
+
postEffects: [],
|
|
1436
|
+
},
|
|
1437
|
+
}
|
|
1438
|
+
: topologyResult.value;
|
|
1439
|
+
const key = JSON.stringify({
|
|
1440
|
+
topology,
|
|
1441
|
+
// GPU-driven residency can become available after the first record pass
|
|
1442
|
+
// (custom mesh handles are resolved into the per-frame projection). The
|
|
1443
|
+
// topology signature alone is intentionally stable across that lifecycle,
|
|
1444
|
+
// so include the prepared projection's presence to invalidate a cached
|
|
1445
|
+
// CPU-only graph when the GPU owner becomes ready, and vice versa.
|
|
1446
|
+
gpuDrivenProjectionActive: gpuDriven !== undefined,
|
|
1447
|
+
// Query reservations are frame-local transport state. The projection is
|
|
1448
|
+
// renderer-owned and read dynamically by the compiled pass, so a page
|
|
1449
|
+
// rotation must not invalidate the graph or its cached bind groups.
|
|
1450
|
+
occlusionQuery:
|
|
1451
|
+
occlusion === undefined ? undefined : { active: true, sampleCount: occlusion.sampleCount },
|
|
1452
|
+
cubeCaptureSlots: cubeCaptureState?.work.length ?? 0,
|
|
1453
|
+
reflectionProbeSlots: cubeCaptureState?.reflectionProbes?.work.map((work) => [
|
|
1454
|
+
work.probeIndex,
|
|
1455
|
+
work.rawCaptureFace ?? -1,
|
|
1456
|
+
work.step?.faceIndex ?? -1,
|
|
1457
|
+
work.step?.mipLevel ?? -1,
|
|
1458
|
+
]),
|
|
1459
|
+
});
|
|
746
1460
|
if (frameState.compiledFrameGraph !== null && frameState.compiledFrameGraphTopologyKey === key) {
|
|
747
|
-
|
|
1461
|
+
frameState.standardLightingGraphSignature = requestedStandardLightingSignature;
|
|
1462
|
+
if (featureGraphCandidate !== undefined && !postProcessAdmission.pending) {
|
|
748
1463
|
commitFeatureCandidate(internals, featureGraphCandidate);
|
|
1464
|
+
} else if (featureGraphCandidate !== undefined) {
|
|
1465
|
+
featureGraphCandidate.onAbandoned?.();
|
|
749
1466
|
}
|
|
750
1467
|
// A candidate flag only describes a possible topology replacement. When
|
|
751
1468
|
// the derived key is unchanged there is no replacement to stage: reuse the
|
|
@@ -761,7 +1478,9 @@ export function ensureCompiledFrameGraph(
|
|
|
761
1478
|
const built = frameState.activePipeline.build(
|
|
762
1479
|
{
|
|
763
1480
|
graph: builder,
|
|
1481
|
+
...(standardLighting === undefined ? {} : { standardLighting }),
|
|
764
1482
|
capabilities: { rgba16floatRenderable: internals.device.caps.rgba16floatRenderable },
|
|
1483
|
+
...(occlusion === undefined ? {} : { occlusion }),
|
|
765
1484
|
...(taaHistory === undefined ? {} : { taaHistory }),
|
|
766
1485
|
encodeTransmissionMip: ({ pass, resources, source }) => {
|
|
767
1486
|
const sourceView = resources.textureView(source);
|
|
@@ -781,11 +1500,21 @@ export function ensureCompiledFrameGraph(
|
|
|
781
1500
|
const resolveTarget = targetResolver(targets, semanticTargets, namedTargets);
|
|
782
1501
|
const projected = projectPlanExecutions(builder, projectedFeaturePlans.value, {
|
|
783
1502
|
resolveTarget,
|
|
784
|
-
resolveBindings: resolveTargetBindings,
|
|
1503
|
+
resolveBindings: (input) => resolveTargetBindings(input, featurePostProcessEntries),
|
|
785
1504
|
reportError: (error) => reportRenderFeatureGraphError(internals, error),
|
|
786
1505
|
});
|
|
787
1506
|
return projected.ok ? ok(undefined) : projected;
|
|
788
1507
|
},
|
|
1508
|
+
contributeCubeCaptures: () => {
|
|
1509
|
+
const reflectionProbes = addReflectionProbeGraphPasses(
|
|
1510
|
+
builder,
|
|
1511
|
+
cubeCaptureState?.reflectionProbes ?? { work: [] },
|
|
1512
|
+
);
|
|
1513
|
+
if (!reflectionProbes.ok) return reflectionProbes;
|
|
1514
|
+
return cubeCaptureState === undefined
|
|
1515
|
+
? ok(undefined)
|
|
1516
|
+
: addCubeCaptureGraphPasses(builder, cubeCaptureState);
|
|
1517
|
+
},
|
|
789
1518
|
hasFeature: (identity) =>
|
|
790
1519
|
projectedFeaturePlans.value.some((execution) => execution.featureIdentity === identity),
|
|
791
1520
|
},
|
|
@@ -794,7 +1523,7 @@ export function ensureCompiledFrameGraph(
|
|
|
794
1523
|
if (!built.ok) {
|
|
795
1524
|
internals.errorRegistry.fire(built.error);
|
|
796
1525
|
featureGraphCandidate?.onRejected?.();
|
|
797
|
-
return volumeTopologyCandidate ? null :
|
|
1526
|
+
return volumeTopologyCandidate ? null : lastKnownGood();
|
|
798
1527
|
}
|
|
799
1528
|
const compiled = builder.compile({
|
|
800
1529
|
device: internals.device,
|
|
@@ -803,7 +1532,7 @@ export function ensureCompiledFrameGraph(
|
|
|
803
1532
|
if (!compiled.ok) {
|
|
804
1533
|
internals.errorRegistry.fire(compiled.error);
|
|
805
1534
|
featureGraphCandidate?.onRejected?.();
|
|
806
|
-
return
|
|
1535
|
+
return lastKnownGood();
|
|
807
1536
|
}
|
|
808
1537
|
const previous = frameState.compiledFrameGraph;
|
|
809
1538
|
if (volumeTopologyCandidate) {
|
|
@@ -813,6 +1542,8 @@ export function ensureCompiledFrameGraph(
|
|
|
813
1542
|
}
|
|
814
1543
|
frameState.compiledFrameGraph = compiled.value;
|
|
815
1544
|
frameState.compiledFrameGraphTopologyKey = key;
|
|
1545
|
+
frameState.standardLightingGraphSignature = requestedStandardLightingSignature;
|
|
1546
|
+
frameState.compiledFrameGraphGeneration += 1;
|
|
816
1547
|
const compiledTargets = compiled.value as CompiledGraphTargetAccess;
|
|
817
1548
|
frameState.graphGeneration += 1;
|
|
818
1549
|
frameState.perFrameGraph = {
|
|
@@ -822,8 +1553,10 @@ export function ensureCompiledFrameGraph(
|
|
|
822
1553
|
graphGeneration: frameState.graphGeneration,
|
|
823
1554
|
};
|
|
824
1555
|
gpuDriven?._commitResourceReplacement();
|
|
825
|
-
if (featureGraphCandidate !== undefined) {
|
|
1556
|
+
if (featureGraphCandidate !== undefined && !postProcessAdmission.pending) {
|
|
826
1557
|
commitFeatureCandidate(internals, featureGraphCandidate);
|
|
1558
|
+
} else if (featureGraphCandidate !== undefined) {
|
|
1559
|
+
featureGraphCandidate.onAbandoned?.();
|
|
827
1560
|
}
|
|
828
1561
|
if (!volumeTopologyCandidate && previous !== null) retire(frameState, previous);
|
|
829
1562
|
return compiled.value;
|
|
@@ -835,9 +1568,22 @@ export function executeCompiledFrameGraph(
|
|
|
835
1568
|
frame: RenderPipelineFrame,
|
|
836
1569
|
encoder: RhiCommandEncoder,
|
|
837
1570
|
runPass?: import('@forgeax/engine-render-graph').RenderGraphPassRunner,
|
|
1571
|
+
frameHooks?: {
|
|
1572
|
+
readonly afterGraphExecute?: () => Result<void, RhiError>;
|
|
1573
|
+
readonly onSubmitted?: () => void;
|
|
1574
|
+
readonly onAborted?: () => void;
|
|
1575
|
+
},
|
|
1576
|
+
readbackFaces?: readonly number[],
|
|
1577
|
+
onSubmitted?: (completed: Promise<unknown>) => void,
|
|
838
1578
|
timingCapture?: GpuTimingCapture,
|
|
839
1579
|
): boolean {
|
|
840
1580
|
const graph = frameState.compiledFrameGraph;
|
|
1581
|
+
const invalidatePostProcessModule = (id: string): void => {
|
|
1582
|
+
const entry = internals.lookupPostProcess?.(id);
|
|
1583
|
+
if (entry !== undefined) {
|
|
1584
|
+
internals.invalidateShaderModule?.(postProcessShaderModuleLabel(id, entry.source));
|
|
1585
|
+
}
|
|
1586
|
+
};
|
|
841
1587
|
const rejectTemporalFrame = (): void => {
|
|
842
1588
|
if (frameState.temporalFrameInput === undefined) return;
|
|
843
1589
|
frameState.temporalFrameTransaction.commit({ accepted: false });
|
|
@@ -849,31 +1595,64 @@ export function executeCompiledFrameGraph(
|
|
|
849
1595
|
rejectTemporalFrame();
|
|
850
1596
|
return false;
|
|
851
1597
|
}
|
|
852
|
-
const
|
|
853
|
-
timingCapture === undefined
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
1598
|
+
const legacyTimingInstrumentation =
|
|
1599
|
+
timingCapture === undefined ? undefined : createTimingInstrumentation(timingCapture);
|
|
1600
|
+
const timingHost = internals as RenderSystemInternals & {
|
|
1601
|
+
gpuPassTimingSession?: GpuPassTimingSession | undefined;
|
|
1602
|
+
gpuPassTimingCapture?: GpuPassTimingCapture | undefined;
|
|
1603
|
+
gpuPassTimingSubmittedWork?: Promise<void> | undefined;
|
|
1604
|
+
gpuPassTimingFrameIdentity?:
|
|
1605
|
+
| import('./gpu-pass-timing/session.js').GpuPassTimingFrameIdentity
|
|
1606
|
+
| undefined;
|
|
1607
|
+
gpuPassTimingBeginReason?:
|
|
1608
|
+
| import('./gpu-pass-timing/errors.js').GpuPassTimingReason
|
|
1609
|
+
| undefined;
|
|
1610
|
+
};
|
|
1611
|
+
timingHost.gpuPassTimingCapture = undefined;
|
|
1612
|
+
timingHost.gpuPassTimingSubmittedWork = undefined;
|
|
1613
|
+
timingHost.gpuPassTimingBeginReason = undefined;
|
|
1614
|
+
const timingIdentity = timingHost.gpuPassTimingFrameIdentity;
|
|
1615
|
+
const passTimingResult =
|
|
1616
|
+
timingIdentity === undefined
|
|
1617
|
+
? undefined
|
|
1618
|
+
: timingHost.gpuPassTimingSession?.beginFrame({
|
|
1619
|
+
...timingIdentity,
|
|
1620
|
+
graphGeneration: frameState.compiledFrameGraphGeneration,
|
|
1621
|
+
});
|
|
1622
|
+
const capture = passTimingResult?.ok === true ? passTimingResult.value : undefined;
|
|
1623
|
+
if (passTimingResult?.ok === false) timingHost.gpuPassTimingBeginReason = passTimingResult.error;
|
|
1624
|
+
const passTimingCapture = capture;
|
|
1625
|
+
timingHost.gpuPassTimingCapture = passTimingCapture;
|
|
1626
|
+
const timingInstrumentationState =
|
|
1627
|
+
passTimingCapture !== undefined
|
|
1628
|
+
? getTimingInstrumentationState(internals, passTimingCapture)
|
|
1629
|
+
: timingCapture === undefined
|
|
1630
|
+
? undefined
|
|
1631
|
+
: undefined;
|
|
1632
|
+
const graphInstrumentation =
|
|
1633
|
+
passTimingCapture !== undefined
|
|
1634
|
+
? timingInstrumentationState?.instrumentation
|
|
1635
|
+
: legacyTimingInstrumentation;
|
|
867
1636
|
type PreparedCommand = { readonly command: CommandBuffer };
|
|
868
1637
|
let preparedCommand: PreparedCommand = { command: undefined as never };
|
|
869
1638
|
const transaction = executeRendererFrameTransaction<PreparedCommand>({
|
|
870
1639
|
build: () => ({ ok: true, value: { command: undefined as never } }),
|
|
871
1640
|
execute: () => {
|
|
872
|
-
const executed = graph.execute(frame,
|
|
1641
|
+
const executed = graph.execute(frame, runPass, graphInstrumentation);
|
|
1642
|
+
timingInstrumentationState?.setCapture(undefined);
|
|
873
1643
|
if (!executed.ok) {
|
|
1644
|
+
passTimingCapture?.abort({ code: executed.error.code });
|
|
874
1645
|
internals.errorRegistry.fire(executed.error);
|
|
875
1646
|
return { ok: false, stage: 'execute' };
|
|
876
1647
|
}
|
|
1648
|
+
const afterGraphExecute = frameHooks?.afterGraphExecute;
|
|
1649
|
+
if (afterGraphExecute !== undefined) {
|
|
1650
|
+
const recorded = afterGraphExecute();
|
|
1651
|
+
if (!recorded.ok) {
|
|
1652
|
+
internals.errorRegistry.fire(recorded.error);
|
|
1653
|
+
return { ok: false, stage: 'execute' };
|
|
1654
|
+
}
|
|
1655
|
+
}
|
|
877
1656
|
return { ok: true, value: undefined };
|
|
878
1657
|
},
|
|
879
1658
|
finish: () => {
|
|
@@ -1000,6 +1779,44 @@ export function executeCompiledFrameGraph(
|
|
|
1000
1779
|
);
|
|
1001
1780
|
}
|
|
1002
1781
|
}
|
|
1782
|
+
const fallbackReadback = frameState.reflectionFallbackReadback;
|
|
1783
|
+
frameState.reflectionFallbackReadback = undefined;
|
|
1784
|
+
if (fallbackReadback !== undefined) {
|
|
1785
|
+
const graphAccess = frameState.perFrameGraph;
|
|
1786
|
+
const graphTexture = graphAccess?.getColorTargetTexture(fallbackReadback.name);
|
|
1787
|
+
const descriptor = graphAccess?.getColorTargetDescriptor(fallbackReadback.name);
|
|
1788
|
+
const matches =
|
|
1789
|
+
graphAccess !== undefined &&
|
|
1790
|
+
graphAccess !== null &&
|
|
1791
|
+
graphTexture !== undefined &&
|
|
1792
|
+
descriptor !== undefined &&
|
|
1793
|
+
descriptor.format === fallbackReadback.expected.format &&
|
|
1794
|
+
descriptor.size.width === fallbackReadback.expected.width &&
|
|
1795
|
+
descriptor.size.height === fallbackReadback.expected.height &&
|
|
1796
|
+
descriptor.sample === 1 &&
|
|
1797
|
+
(descriptor.usage & fallbackReadback.expected.usage) ===
|
|
1798
|
+
fallbackReadback.expected.usage &&
|
|
1799
|
+
graphAccess.graphGeneration === fallbackReadback.expected.graphGeneration &&
|
|
1800
|
+
frameState.frameNumber === fallbackReadback.expected.frameId &&
|
|
1801
|
+
getTextureIdentity(graphTexture) === fallbackReadback.expected.textureIdentity;
|
|
1802
|
+
if (matches && graphTexture !== undefined) {
|
|
1803
|
+
encoder.copyTextureToBuffer(
|
|
1804
|
+
{ texture: graphTexture },
|
|
1805
|
+
{
|
|
1806
|
+
buffer: fallbackReadback.buffer,
|
|
1807
|
+
bytesPerRow: fallbackReadback.bytesPerRow,
|
|
1808
|
+
rowsPerImage: fallbackReadback.height,
|
|
1809
|
+
},
|
|
1810
|
+
{
|
|
1811
|
+
width: fallbackReadback.width,
|
|
1812
|
+
height: fallbackReadback.height,
|
|
1813
|
+
depthOrArrayLayers: 1,
|
|
1814
|
+
},
|
|
1815
|
+
);
|
|
1816
|
+
fallbackReadback.encoded = true;
|
|
1817
|
+
}
|
|
1818
|
+
}
|
|
1819
|
+
internals.encodeRenderTargetReadbacks?.(encoder, readbackFaces);
|
|
1003
1820
|
const stagedGpuState = frameState.temporalGpuState;
|
|
1004
1821
|
if (stagedGpuState !== undefined && !hasPendingTemporalGpuSubmit(stagedGpuState)) {
|
|
1005
1822
|
internals.errorRegistry.fire(
|
|
@@ -1011,6 +1828,10 @@ export function executeCompiledFrameGraph(
|
|
|
1011
1828
|
);
|
|
1012
1829
|
return { ok: false, stage: 'finish' };
|
|
1013
1830
|
}
|
|
1831
|
+
if (passTimingCapture !== undefined) {
|
|
1832
|
+
const tail = passTimingCapture.encodeTail(encoder);
|
|
1833
|
+
if (!tail.ok) passTimingCapture.abort({ code: tail.error.code });
|
|
1834
|
+
}
|
|
1014
1835
|
const resolved = timingCapture?.resolve(encoder);
|
|
1015
1836
|
if (resolved !== undefined && !resolved.ok) {
|
|
1016
1837
|
timingCapture?.discard();
|
|
@@ -1018,6 +1839,7 @@ export function executeCompiledFrameGraph(
|
|
|
1018
1839
|
}
|
|
1019
1840
|
const finished = encoder.finish();
|
|
1020
1841
|
if (!finished.ok) {
|
|
1842
|
+
passTimingCapture?.abort({ code: finished.error.code });
|
|
1021
1843
|
timingCapture?.discard();
|
|
1022
1844
|
internals.errorRegistry.fire(finished.error);
|
|
1023
1845
|
return { ok: false, stage: 'finish' };
|
|
@@ -1026,8 +1848,16 @@ export function executeCompiledFrameGraph(
|
|
|
1026
1848
|
return { ok: true, value: undefined };
|
|
1027
1849
|
},
|
|
1028
1850
|
submit: () => {
|
|
1851
|
+
const injectedFailure = internals.beforeSubmit?.(internals.device);
|
|
1852
|
+
if (injectedFailure !== undefined) {
|
|
1853
|
+
passTimingCapture?.abort({ code: injectedFailure.code });
|
|
1854
|
+
timingCapture?.discard();
|
|
1855
|
+
internals.errorRegistry.fire(injectedFailure);
|
|
1856
|
+
return { ok: false, stage: 'submit' };
|
|
1857
|
+
}
|
|
1029
1858
|
const submitted = internals.device.queue.submit([preparedCommand.command]);
|
|
1030
1859
|
if (!submitted.ok) {
|
|
1860
|
+
passTimingCapture?.abort({ code: submitted.error.code });
|
|
1031
1861
|
timingCapture?.discard();
|
|
1032
1862
|
internals.errorRegistry.fire(submitted.error);
|
|
1033
1863
|
return { ok: false, stage: 'submit' };
|
|
@@ -1036,6 +1866,28 @@ export function executeCompiledFrameGraph(
|
|
|
1036
1866
|
return { ok: true, value: undefined };
|
|
1037
1867
|
},
|
|
1038
1868
|
commit: () => {
|
|
1869
|
+
frameHooks?.onSubmitted?.();
|
|
1870
|
+
if (frameState.temporalFrameInput !== undefined) {
|
|
1871
|
+
const temporal = frameState.temporalFrameTransaction.commit({ accepted: true });
|
|
1872
|
+
if (temporal.ok) {
|
|
1873
|
+
frameState.temporalFrame = temporal.value;
|
|
1874
|
+
} else {
|
|
1875
|
+
internals.errorRegistry.fire(
|
|
1876
|
+
new RhiError({
|
|
1877
|
+
code: 'webgpu-runtime-error',
|
|
1878
|
+
expected: 'the staged temporal frame to commit after queue submission',
|
|
1879
|
+
hint: 'discard the temporal candidate and retry the next frame',
|
|
1880
|
+
detail: { error: temporal.error },
|
|
1881
|
+
}),
|
|
1882
|
+
);
|
|
1883
|
+
}
|
|
1884
|
+
frameState.temporalFrameInput = undefined;
|
|
1885
|
+
}
|
|
1886
|
+
if (passTimingCapture !== undefined) {
|
|
1887
|
+
const completion = internals.device.queue.onSubmittedWorkDone();
|
|
1888
|
+
timingHost.gpuPassTimingSubmittedWork = completion;
|
|
1889
|
+
passTimingCapture.markSubmitted(completion);
|
|
1890
|
+
}
|
|
1039
1891
|
if (frameState.bloomFrameReceipts !== undefined) {
|
|
1040
1892
|
internals
|
|
1041
1893
|
.getPipelineState()
|
|
@@ -1049,7 +1901,7 @@ export function executeCompiledFrameGraph(
|
|
|
1049
1901
|
frameState.activeTemporalGpuState = stagedGpuState;
|
|
1050
1902
|
if (previousGpuState !== undefined && previousGpuState !== stagedGpuState) {
|
|
1051
1903
|
internals.clearPostProcessPipelineCache?.('forgeax.taa-resolve');
|
|
1052
|
-
|
|
1904
|
+
invalidatePostProcessModule('forgeax.taa-resolve');
|
|
1053
1905
|
retireTemporalGpuStateAfterFence(
|
|
1054
1906
|
previousGpuState,
|
|
1055
1907
|
internals.device.queue,
|
|
@@ -1079,7 +1931,7 @@ export function executeCompiledFrameGraph(
|
|
|
1079
1931
|
}
|
|
1080
1932
|
if (stagedTemporalCommit.kind === 'off') {
|
|
1081
1933
|
internals.clearPostProcessPipelineCache?.('forgeax.taa-resolve');
|
|
1082
|
-
|
|
1934
|
+
invalidatePostProcessModule('forgeax.taa-resolve');
|
|
1083
1935
|
const activeGpuState = frameState.activeTemporalGpuState;
|
|
1084
1936
|
if (activeGpuState !== undefined) {
|
|
1085
1937
|
retireTemporalGpuStateAfterFence(
|
|
@@ -1104,8 +1956,13 @@ export function executeCompiledFrameGraph(
|
|
|
1104
1956
|
frameState.environmentLifecycle?.publish(frameState.environmentGeneration);
|
|
1105
1957
|
frameState.environmentGeneration = undefined;
|
|
1106
1958
|
}
|
|
1959
|
+
onSubmitted?.(internals.device.queue.onSubmittedWorkDone());
|
|
1107
1960
|
},
|
|
1108
1961
|
abort: (failure) => {
|
|
1962
|
+
frameHooks?.onAborted?.();
|
|
1963
|
+
passTimingCapture?.abort({ code: failure.stage });
|
|
1964
|
+
timingHost.gpuPassTimingCapture = undefined;
|
|
1965
|
+
timingHost.gpuPassTimingSubmittedWork = undefined;
|
|
1109
1966
|
timingCapture?.discard();
|
|
1110
1967
|
frameState.bloomFrameReceipts = undefined;
|
|
1111
1968
|
if (frameState.environmentGeneration !== undefined) {
|
|
@@ -1133,3 +1990,137 @@ export function executeCompiledFrameGraph(
|
|
|
1133
1990
|
if (!transaction.ok) rejectTemporalFrame();
|
|
1134
1991
|
return transaction.ok;
|
|
1135
1992
|
}
|
|
1993
|
+
|
|
1994
|
+
function createTimingInstrumentation(
|
|
1995
|
+
capture: GpuTimingCapture,
|
|
1996
|
+
): RenderGraphPassInstrumentation<RenderPipelineFrame> {
|
|
1997
|
+
return {
|
|
1998
|
+
begin: (pass): RenderGraphPassInstrumentationScope | undefined => {
|
|
1999
|
+
// WebGPU has no portable timestamp boundary for a copy pass. Do not
|
|
2000
|
+
// pretend a command-encoder marker exists; frame timing remains valid
|
|
2001
|
+
// when at least one raster/compute pass is present.
|
|
2002
|
+
if (pass.kind === 'copy') return undefined;
|
|
2003
|
+
const writes = capture.beginPass(pass.name, pass.kind, pass.executionIndex);
|
|
2004
|
+
if (writes === undefined) return undefined;
|
|
2005
|
+
if (pass.kind === 'raster') {
|
|
2006
|
+
return {
|
|
2007
|
+
renderPassDescriptor: (descriptor) => {
|
|
2008
|
+
if (descriptor.timestampWrites !== undefined) {
|
|
2009
|
+
capture.markOwnerConflict(pass.name);
|
|
2010
|
+
return descriptor;
|
|
2011
|
+
}
|
|
2012
|
+
return { ...descriptor, timestampWrites: writes };
|
|
2013
|
+
},
|
|
2014
|
+
};
|
|
2015
|
+
}
|
|
2016
|
+
return {
|
|
2017
|
+
computePassDescriptor: (descriptor) => {
|
|
2018
|
+
if (descriptor.timestampWrites !== undefined) {
|
|
2019
|
+
capture.markOwnerConflict(pass.name);
|
|
2020
|
+
return descriptor;
|
|
2021
|
+
}
|
|
2022
|
+
return { ...descriptor, timestampWrites: writes };
|
|
2023
|
+
},
|
|
2024
|
+
};
|
|
2025
|
+
},
|
|
2026
|
+
};
|
|
2027
|
+
}
|
|
2028
|
+
|
|
2029
|
+
function getTimingInstrumentationState(
|
|
2030
|
+
internals: RenderSystemInternals,
|
|
2031
|
+
capture: GpuPassTimingCapture,
|
|
2032
|
+
): TimingInstrumentationState {
|
|
2033
|
+
const existing = timingInstrumentationStates.get(internals);
|
|
2034
|
+
if (existing !== undefined) {
|
|
2035
|
+
existing.setCapture(capture);
|
|
2036
|
+
return existing;
|
|
2037
|
+
}
|
|
2038
|
+
type TimestampWrites = NonNullable<ReturnType<GpuPassTimingCapture['timestampWrites']>>;
|
|
2039
|
+
const activeIdentity: {
|
|
2040
|
+
passName: string;
|
|
2041
|
+
passKind: GpuPassTimingPassIdentity['passKind'];
|
|
2042
|
+
executionIndex: number;
|
|
2043
|
+
} = {
|
|
2044
|
+
passName: '',
|
|
2045
|
+
passKind: 'raster',
|
|
2046
|
+
executionIndex: 0,
|
|
2047
|
+
};
|
|
2048
|
+
let activeWrites: TimestampWrites | undefined;
|
|
2049
|
+
let activeCapture: GpuPassTimingCapture | undefined = capture;
|
|
2050
|
+
const rasterScope: RenderGraphPassInstrumentationScope = {
|
|
2051
|
+
renderPassDescriptor: (descriptor) => {
|
|
2052
|
+
const capture = activeCapture;
|
|
2053
|
+
const identity = activeIdentity;
|
|
2054
|
+
const writes = activeWrites;
|
|
2055
|
+
if (capture === undefined || identity === undefined || writes === undefined) {
|
|
2056
|
+
return descriptor;
|
|
2057
|
+
}
|
|
2058
|
+
if (descriptor.timestampWrites !== undefined) {
|
|
2059
|
+
capture.markOwnerConflict(identity);
|
|
2060
|
+
return descriptor;
|
|
2061
|
+
}
|
|
2062
|
+
(descriptor as { timestampWrites?: TimestampWrites }).timestampWrites = writes;
|
|
2063
|
+
return descriptor;
|
|
2064
|
+
},
|
|
2065
|
+
};
|
|
2066
|
+
const computeScope: RenderGraphPassInstrumentationScope = {
|
|
2067
|
+
computePassDescriptor: (descriptor) => {
|
|
2068
|
+
const capture = activeCapture;
|
|
2069
|
+
const identity = activeIdentity;
|
|
2070
|
+
const writes = activeWrites;
|
|
2071
|
+
if (capture === undefined || identity === undefined || writes === undefined) {
|
|
2072
|
+
return descriptor;
|
|
2073
|
+
}
|
|
2074
|
+
if (descriptor.timestampWrites !== undefined) {
|
|
2075
|
+
capture.markOwnerConflict(identity);
|
|
2076
|
+
return descriptor;
|
|
2077
|
+
}
|
|
2078
|
+
(descriptor as { timestampWrites?: TimestampWrites }).timestampWrites = writes;
|
|
2079
|
+
return descriptor;
|
|
2080
|
+
},
|
|
2081
|
+
};
|
|
2082
|
+
const copyScope: RenderGraphPassInstrumentationScope = {
|
|
2083
|
+
beforeCopy: (encoder) => {
|
|
2084
|
+
const capture = activeCapture;
|
|
2085
|
+
const identity = activeIdentity;
|
|
2086
|
+
if (capture === undefined || identity === undefined) return;
|
|
2087
|
+
capture.copyBoundaryBefore(identity, encoder);
|
|
2088
|
+
},
|
|
2089
|
+
afterCopy: (encoder) => {
|
|
2090
|
+
const capture = activeCapture;
|
|
2091
|
+
const identity = activeIdentity;
|
|
2092
|
+
if (capture === undefined || identity === undefined) return;
|
|
2093
|
+
capture.copyBoundaryAfter(identity, encoder);
|
|
2094
|
+
},
|
|
2095
|
+
};
|
|
2096
|
+
const instrumentation: RenderGraphPassInstrumentation<RenderPipelineFrame> = {
|
|
2097
|
+
begin: (pass) => {
|
|
2098
|
+
const capture = activeCapture;
|
|
2099
|
+
if (capture === undefined) return undefined;
|
|
2100
|
+
activeIdentity.passName = pass.name;
|
|
2101
|
+
activeIdentity.passKind = pass.kind;
|
|
2102
|
+
activeIdentity.executionIndex = pass.executionIndex;
|
|
2103
|
+
activeWrites = capture.recordPass(activeIdentity);
|
|
2104
|
+
if (activeWrites === undefined) return undefined;
|
|
2105
|
+
switch (pass.kind) {
|
|
2106
|
+
case 'raster':
|
|
2107
|
+
return rasterScope;
|
|
2108
|
+
case 'compute':
|
|
2109
|
+
return computeScope;
|
|
2110
|
+
case 'copy':
|
|
2111
|
+
return copyScope;
|
|
2112
|
+
}
|
|
2113
|
+
},
|
|
2114
|
+
};
|
|
2115
|
+
const state: TimingInstrumentationState = {
|
|
2116
|
+
instrumentation,
|
|
2117
|
+
setCapture: (capture) => {
|
|
2118
|
+
activeCapture = capture;
|
|
2119
|
+
if (capture === undefined) {
|
|
2120
|
+
activeWrites = undefined;
|
|
2121
|
+
}
|
|
2122
|
+
},
|
|
2123
|
+
};
|
|
2124
|
+
timingInstrumentationStates.set(internals, state);
|
|
2125
|
+
return state;
|
|
2126
|
+
}
|