@forgeax/engine-render 0.1.19 → 0.1.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +215 -0
- package/dist/.tsbuildinfo +1 -1
- package/dist/assembly/device-feature-admission.d.ts +18 -0
- package/dist/assembly/device-feature-admission.d.ts.map +1 -0
- package/dist/assembly/directional-shadow-inspection.d.ts +38 -0
- package/dist/assembly/directional-shadow-inspection.d.ts.map +1 -0
- package/dist/assembly/factory.d.ts +34 -20
- package/dist/assembly/factory.d.ts.map +1 -1
- package/dist/assembly/host-contract.d.ts +9 -0
- package/dist/assembly/host-contract.d.ts.map +1 -1
- package/dist/assembly/render-target-host.d.ts +46 -0
- package/dist/assembly/render-target-host.d.ts.map +1 -0
- package/dist/assets/render-asset-port.d.ts.map +1 -1
- package/dist/authoring.mjs +3 -0
- package/dist/authoring.mjs.map +1 -1
- package/dist/capture/cube-views.d.ts +21 -0
- package/dist/capture/cube-views.d.ts.map +1 -0
- package/dist/capture/scheduler.d.ts +54 -0
- package/dist/capture/scheduler.d.ts.map +1 -0
- package/dist/{chunk-RJRUS55L.mjs → chunk-5YADUCA7.mjs} +1896 -1624
- package/dist/chunk-5YADUCA7.mjs.map +1 -0
- package/dist/{chunk-LOSO4CTV.mjs → chunk-6OPXDQ2E.mjs} +423 -46
- package/dist/chunk-6OPXDQ2E.mjs.map +1 -0
- package/dist/{chunk-IPXCABEP.mjs → chunk-BXBQQKFQ.mjs} +3 -9
- package/dist/chunk-BXBQQKFQ.mjs.map +1 -0
- package/dist/chunk-FS2KNUQH.mjs +1294 -0
- package/dist/chunk-FS2KNUQH.mjs.map +1 -0
- package/dist/components/camera.d.ts +1 -0
- package/dist/components/camera.d.ts.map +1 -1
- package/dist/components/cube-camera.d.ts +20 -0
- package/dist/components/cube-camera.d.ts.map +1 -0
- package/dist/components/directional-light.d.ts +11 -2
- package/dist/components/directional-light.d.ts.map +1 -1
- package/dist/components/directional-shadow-filter.d.ts +25 -0
- package/dist/components/directional-shadow-filter.d.ts.map +1 -0
- package/dist/components/index.d.ts +2 -0
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/light-helpers.d.ts.map +1 -1
- package/dist/components/reflection-probe.d.ts +17 -0
- package/dist/components/reflection-probe.d.ts.map +1 -0
- package/dist/components/spot-light.d.ts +12 -0
- package/dist/components/spot-light.d.ts.map +1 -1
- package/dist/construct-renderer.mjs +8552 -1612
- package/dist/construct-renderer.mjs.map +1 -1
- package/dist/device/gpu-residency.d.ts +19 -2
- package/dist/device/gpu-residency.d.ts.map +1 -1
- package/dist/environment/frame.d.ts.map +1 -1
- package/dist/environment/lifecycle.d.ts +5 -0
- package/dist/environment/lifecycle.d.ts.map +1 -1
- package/dist/errors/render.d.ts +209 -93
- package/dist/errors/render.d.ts.map +1 -1
- package/dist/extract/directional-shadow-projection.d.ts +23 -0
- package/dist/extract/directional-shadow-projection.d.ts.map +1 -0
- package/dist/extract/environment.d.ts +14 -0
- package/dist/extract/environment.d.ts.map +1 -1
- package/dist/extract/visibility.d.ts.map +1 -1
- package/dist/features/fullscreen.d.ts.map +1 -1
- package/dist/features/targets.d.ts.map +1 -1
- package/dist/features/types.d.ts +10 -0
- package/dist/features/types.d.ts.map +1 -1
- package/dist/fullscreen-post-process-pass.d.ts +13 -2
- package/dist/fullscreen-post-process-pass.d.ts.map +1 -1
- package/dist/gpu-driven/batch-topology.d.ts.map +1 -1
- package/dist/gpu-driven/production-raster.d.ts +0 -1
- package/dist/gpu-driven/production-raster.d.ts.map +1 -1
- package/dist/gpu-scene.d.ts.map +1 -1
- package/dist/gpu-usage.d.ts +2 -0
- package/dist/gpu-usage.d.ts.map +1 -1
- package/dist/hdrp-buffers.d.ts +19 -17
- package/dist/hdrp-buffers.d.ts.map +1 -1
- package/dist/ibl/IblPipelineCache.d.ts +4 -0
- package/dist/ibl/IblPipelineCache.d.ts.map +1 -1
- package/dist/ibl/kernel-cache.d.ts +36 -0
- package/dist/ibl/kernel-cache.d.ts.map +1 -0
- package/dist/index.d.ts +35 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.mjs +4 -4
- package/dist/index.mjs.map +1 -1
- package/dist/inspection-types.d.ts +51 -0
- package/dist/inspection-types.d.ts.map +1 -1
- package/dist/instances-derived-bounds.d.ts +50 -0
- package/dist/instances-derived-bounds.d.ts.map +1 -0
- package/dist/internal.mjs +1 -1
- package/dist/light-buffer-layout.d.ts +30 -13
- package/dist/light-buffer-layout.d.ts.map +1 -1
- package/dist/mesh-material-bindings.d.ts +54 -0
- package/dist/mesh-material-bindings.d.ts.map +1 -1
- package/dist/pbr-pipeline.d.ts +20 -7
- package/dist/pbr-pipeline.d.ts.map +1 -1
- package/dist/pipeline/standard-forward-lane.d.ts +2 -1
- package/dist/pipeline/standard-forward-lane.d.ts.map +1 -1
- package/dist/pipeline/standard-lighting/errors.d.ts +4 -0
- package/dist/pipeline/standard-lighting/errors.d.ts.map +1 -0
- package/dist/pipeline/standard-lighting/graph.d.ts +24 -0
- package/dist/pipeline/standard-lighting/graph.d.ts.map +1 -0
- package/dist/pipeline/standard-lighting/inspection.d.ts +38 -0
- package/dist/pipeline/standard-lighting/inspection.d.ts.map +1 -0
- package/dist/pipeline/standard-lighting/layout.d.ts +28 -0
- package/dist/pipeline/standard-lighting/layout.d.ts.map +1 -0
- package/dist/pipeline/standard-lighting/light-frame.d.ts +33 -0
- package/dist/pipeline/standard-lighting/light-frame.d.ts.map +1 -0
- package/dist/pipeline/standard-lighting/membership.d.ts +14 -0
- package/dist/pipeline/standard-lighting/membership.d.ts.map +1 -0
- package/dist/pipeline/standard-lighting/prepare.d.ts +16 -0
- package/dist/pipeline/standard-lighting/prepare.d.ts.map +1 -0
- package/dist/pipeline/standard-lighting/topology.d.ts +45 -0
- package/dist/pipeline/standard-lighting/topology.d.ts.map +1 -0
- package/dist/pipeline/standard-lighting/transport.d.ts +36 -0
- package/dist/pipeline/standard-lighting/transport.d.ts.map +1 -0
- package/dist/pipeline/standard-pipeline.d.ts +4 -13
- package/dist/pipeline/standard-pipeline.d.ts.map +1 -1
- package/dist/pipeline/standard-post.d.ts.map +1 -1
- package/dist/pipeline/standard-profile.d.ts +12 -20
- package/dist/pipeline/standard-profile.d.ts.map +1 -1
- package/dist/pipeline-spec.d.ts +40 -7
- package/dist/pipeline-spec.d.ts.map +1 -1
- package/dist/point-shadow-inspection.d.ts +21 -0
- package/dist/point-shadow-inspection.d.ts.map +1 -0
- package/dist/record/frame-lighting.d.ts +29 -32
- package/dist/record/frame-lighting.d.ts.map +1 -1
- package/dist/record/frame-snapshot.d.ts +65 -15
- package/dist/record/frame-snapshot.d.ts.map +1 -1
- package/dist/record/frame-targets.d.ts +5 -0
- package/dist/record/frame-targets.d.ts.map +1 -1
- package/dist/record/frame.d.ts +12 -5
- package/dist/record/frame.d.ts.map +1 -1
- package/dist/record/gpu-pass-timing/contract.d.ts +96 -0
- package/dist/record/gpu-pass-timing/contract.d.ts.map +1 -0
- package/dist/record/gpu-pass-timing/errors.d.ts +18 -0
- package/dist/record/gpu-pass-timing/errors.d.ts.map +1 -0
- package/dist/record/gpu-pass-timing/index.d.ts +8 -0
- package/dist/record/gpu-pass-timing/index.d.ts.map +1 -0
- package/dist/record/gpu-pass-timing/parser.d.ts +11 -0
- package/dist/record/gpu-pass-timing/parser.d.ts.map +1 -0
- package/dist/record/gpu-pass-timing/session.d.ts +43 -0
- package/dist/record/gpu-pass-timing/session.d.ts.map +1 -0
- package/dist/record/gpu-timing.d.ts +37 -0
- package/dist/record/gpu-timing.d.ts.map +1 -0
- package/dist/record/main-pass-geometry.d.ts.map +1 -1
- package/dist/record/main-pass-material.d.ts +23 -2
- package/dist/record/main-pass-material.d.ts.map +1 -1
- package/dist/record/main-pass-sprite-draws.d.ts.map +1 -1
- package/dist/record/main-pass.d.ts +2 -0
- package/dist/record/main-pass.d.ts.map +1 -1
- package/dist/record/render-context.d.ts +48 -3
- package/dist/record/render-context.d.ts.map +1 -1
- package/dist/record/shadow-pass.d.ts.map +1 -1
- package/dist/record/skybox-post-pass.d.ts.map +1 -1
- package/dist/record/typed-frame-graph.d.ts +81 -5
- package/dist/record/typed-frame-graph.d.ts.map +1 -1
- package/dist/record/view-ubo.d.ts +7 -4
- package/dist/record/view-ubo.d.ts.map +1 -1
- package/dist/reflection/filter.d.ts +22 -0
- package/dist/reflection/filter.d.ts.map +1 -0
- package/dist/reflection/gpu-table.d.ts +25 -0
- package/dist/reflection/gpu-table.d.ts.map +1 -0
- package/dist/reflection/projection.d.ts +91 -0
- package/dist/reflection/projection.d.ts.map +1 -0
- package/dist/render-contract.d.ts +114 -7
- package/dist/render-contract.d.ts.map +1 -1
- package/dist/render-data.d.ts +10 -6
- package/dist/render-data.d.ts.map +1 -1
- package/dist/render-graph-primitives.d.ts +1 -0
- package/dist/render-graph-primitives.d.ts.map +1 -1
- package/dist/render-pipeline.d.ts +78 -2
- package/dist/render-pipeline.d.ts.map +1 -1
- package/dist/render-system-extract.d.ts +113 -20
- package/dist/render-system-extract.d.ts.map +1 -1
- package/dist/render-system.d.ts +24 -3
- package/dist/render-system.d.ts.map +1 -1
- package/dist/renderer-inspect.d.ts +29 -0
- package/dist/renderer-inspect.d.ts.map +1 -0
- package/dist/renderer.d.ts +43 -0
- package/dist/renderer.d.ts.map +1 -0
- package/dist/scene/render-scene.d.ts +14 -0
- package/dist/scene/render-scene.d.ts.map +1 -1
- package/dist/shadow-atlas.d.ts +3 -3
- package/dist/shadow-atlas.d.ts.map +1 -1
- package/dist/ssao-buffers.d.ts +3 -0
- package/dist/ssao-buffers.d.ts.map +1 -1
- package/dist/targets/contracts.d.ts +66 -0
- package/dist/targets/contracts.d.ts.map +1 -0
- package/dist/targets/graph-projection.d.ts +29 -0
- package/dist/targets/graph-projection.d.ts.map +1 -0
- package/dist/targets/material-source.d.ts +34 -0
- package/dist/targets/material-source.d.ts.map +1 -0
- package/dist/targets/owner.d.ts +32 -0
- package/dist/targets/owner.d.ts.map +1 -0
- package/dist/targets/physical.d.ts +18 -0
- package/dist/targets/physical.d.ts.map +1 -0
- package/dist/targets/readback.d.ts +39 -0
- package/dist/targets/readback.d.ts.map +1 -0
- package/dist/temporal/frame.d.ts +44 -0
- package/dist/temporal/frame.d.ts.map +1 -0
- package/dist/temporal/index.mjs +3 -3
- package/dist/typed-render-graph-primitives.d.ts +6 -1
- package/dist/typed-render-graph-primitives.d.ts.map +1 -1
- package/dist/typed-shadow-atlas.d.ts +10 -0
- package/dist/typed-shadow-atlas.d.ts.map +1 -0
- package/dist/typed-shadow-passes.d.ts +1 -1
- package/dist/typed-shadow-passes.d.ts.map +1 -1
- package/dist/volume/capability.d.ts +57 -0
- package/dist/volume/capability.d.ts.map +1 -0
- package/dist/volume/component.d.ts +61 -0
- package/dist/volume/component.d.ts.map +1 -0
- package/dist/volume/extract.d.ts +11 -0
- package/dist/volume/extract.d.ts.map +1 -0
- package/dist/volume/inspection.d.ts +38 -0
- package/dist/volume/inspection.d.ts.map +1 -0
- package/dist/volume/passes.d.ts +38 -0
- package/dist/volume/passes.d.ts.map +1 -0
- package/dist/volume/recovery.d.ts +38 -0
- package/dist/volume/recovery.d.ts.map +1 -0
- package/dist/volume/resources.d.ts +57 -0
- package/dist/volume/resources.d.ts.map +1 -0
- package/dist/volume/temporal.d.ts +35 -0
- package/dist/volume/temporal.d.ts.map +1 -0
- package/package.json +20 -20
- package/src/__tests__/bloom-exact-zero.unit.test.ts +48 -19
- package/src/__tests__/bloom-lifecycle.integration.test.ts +41 -13
- package/src/__tests__/camera-target-consumption.unit.test.ts +53 -0
- package/src/__tests__/cluster-binner.unit.test.ts +35 -0
- package/src/__tests__/cluster-grid-default-surface.unit.test.ts +7 -2
- package/src/__tests__/cube-camera-scheduler.unit.test.ts +70 -0
- package/src/__tests__/cube-camera-single-submit.perf.test.ts +75 -0
- package/src/__tests__/cube-camera-view-matrices.unit.test.ts +41 -0
- package/src/__tests__/cube-camera-vocabulary.unit.test.ts +47 -0
- package/src/__tests__/cube-camera.integration.test.ts +42 -0
- package/src/__tests__/device-feature-admission.unit.test.ts +73 -0
- package/src/__tests__/direct-light-snapshot.unit.test.ts +3 -3
- package/src/__tests__/docs-gate-green.unit.test.ts +38 -0
- package/src/__tests__/factory-contract.integration.test.ts +255 -29
- package/src/__tests__/fog-component.unit.test.ts +67 -0
- package/src/__tests__/fog.integration.test.ts +86 -0
- package/src/__tests__/fullscreen-feature-plan.unit.test.ts +37 -0
- package/src/__tests__/gpu-driven-indirect-raster-evidence.ts +10 -9
- package/src/__tests__/gpu-driven-indirect-raster.dawn.test.ts +17 -1
- package/src/__tests__/gpu-driven-production.integration.test.ts +16 -17
- package/src/__tests__/gpu-driven-view-graph.integration.test.ts +12 -4
- package/src/__tests__/gpu-pass-timing-browser-runner.ts +281 -0
- package/src/__tests__/gpu-pass-timing-coexistence.integration.test.ts +80 -0
- package/src/__tests__/gpu-pass-timing-contract.unit.test.ts +243 -0
- package/src/__tests__/gpu-pass-timing-exact-zero.unit.test.ts +131 -0
- package/src/__tests__/gpu-pass-timing-lifecycle.integration.test.ts +230 -0
- package/src/__tests__/gpu-pass-timing-observation.unit.test.ts +233 -0
- package/src/__tests__/gpu-pass-timing-session.unit.test.ts +438 -0
- package/src/__tests__/gpu-pass-timing.browser.test.ts +26 -0
- package/src/__tests__/gpu-pass-timing.rhi-null.unit.test.ts +125 -0
- package/src/__tests__/hdrp-group2-visibility.unit.test.ts +24 -0
- package/src/__tests__/instances-culling.integration.test.ts +94 -0
- package/src/__tests__/instances-derived-bounds.unit.test.ts +118 -0
- package/src/__tests__/ktx2-basis-gpu-consumer.dawn.test.ts +14 -14
- package/src/__tests__/material-observation.integration.test.ts +101 -0
- package/src/__tests__/mesh-buffer-usage-surface.unit.test.ts +1 -1
- package/src/__tests__/pbr-view-layout.unit.test.ts +16 -0
- package/src/__tests__/point-shadow-inspection.unit.test.ts +60 -0
- package/src/__tests__/public-surface.test-d.ts +10 -0
- package/src/__tests__/reflection-probe-authoring.unit.test.ts +71 -0
- package/src/__tests__/reflection-probe-filter.unit.test.ts +54 -0
- package/src/__tests__/reflection-probe-ibl-topology.unit.test.ts +45 -0
- package/src/__tests__/reflection-probe-pass-encode.integration.test.ts +101 -0
- package/src/__tests__/reflection-probe-performance.perf.test.ts +60 -0
- package/src/__tests__/reflection-probe-recovery.integration.test.ts +55 -0
- package/src/__tests__/reflection-probe-selection.unit.test.ts +46 -0
- package/src/__tests__/render-error-code-owner.test-d.ts +23 -3
- package/src/__tests__/render-feature-docs.unit.test.ts +1 -1
- package/src/__tests__/render-target-admission.unit.test.ts +80 -0
- package/src/__tests__/render-target-graph-projection.unit.test.ts +102 -0
- package/src/__tests__/render-target-inspection.unit.test.ts +52 -0
- package/src/__tests__/render-target-material-source.test-d.ts +30 -0
- package/src/__tests__/render-target-material-source.unit.test.ts +97 -0
- package/src/__tests__/render-target-owner-placement.unit.test.ts +203 -0
- package/src/__tests__/render-target-owner.unit.test.ts +122 -0
- package/src/__tests__/render-target-probe-soak.perf.test.ts +94 -0
- package/src/__tests__/render-target-public-schema.json +107 -0
- package/src/__tests__/render-target-public-schema.unit.test.ts +91 -0
- package/src/__tests__/render-target-public-surface.test-d.ts +83 -0
- package/src/__tests__/render-target-readback.integration.test.ts +90 -0
- package/src/__tests__/render-target-recovery.integration.test.ts +85 -0
- package/src/__tests__/renderer-factory-material-contract.unit.test.ts +76 -0
- package/src/__tests__/renderer-frame-transaction.integration.test.ts +1 -1
- package/src/__tests__/renderer-lifecycle.integration.test.ts +14 -0
- package/src/__tests__/shader-stage-surface.unit.test.ts +19 -4
- package/src/__tests__/skin-motion-regression.unit.test.ts +132 -0
- package/src/__tests__/skinned-shadow-caster.test.ts +32 -2
- package/src/__tests__/standard-cluster-capability.integration.test.ts +63 -0
- package/src/__tests__/standard-cluster-transport.unit.test.ts +121 -0
- package/src/__tests__/standard-cluster-variant-resolution.unit.test.ts +232 -0
- package/src/__tests__/standard-clustered-pipeline.unit.test.ts +8 -5
- package/src/__tests__/standard-lighting-inspection.integration.test.ts +138 -0
- package/src/__tests__/standard-lighting-ssot.unit.test.ts +18 -0
- package/src/__tests__/standard-lighting-write.unit.test.ts +377 -0
- package/src/__tests__/standard-lighting.integration.test.ts +67 -0
- package/src/__tests__/standard-pipeline.dawn.test.ts +206 -5
- package/src/__tests__/standard-pipeline.integration.test.ts +181 -150
- package/src/__tests__/standard-probe-binding.unit.test.ts +25 -0
- package/src/__tests__/standard-profile-oracle.unit.test.ts +23 -36
- package/src/__tests__/typed-pipeline-topology.unit.test.ts +395 -14
- package/src/__tests__/urp-pipeline-targets.unit.test.ts +2 -2
- package/src/__tests__/visibility-resolver.unit.test.ts +15 -0
- package/src/__tests__/volume-optics-oracle.unit.test.ts +85 -0
- package/src/__tests__/volumetric-fog-budget-recovery.integration.test.ts +655 -0
- package/src/__tests__/volumetric-fog-component.unit.test.ts +71 -0
- package/src/__tests__/volumetric-fog-composite-stage-readback.dawn.test.ts +376 -0
- package/src/__tests__/volumetric-fog-errors.unit.test.ts +51 -0
- package/src/__tests__/volumetric-fog-inspection.unit.test.ts +77 -0
- package/src/__tests__/volumetric-fog-light-capability.unit.test.ts +19 -0
- package/src/__tests__/volumetric-fog-light-consumers.integration.test.ts +18 -0
- package/src/__tests__/volumetric-fog-light-errors.unit.test.ts +17 -0
- package/src/__tests__/volumetric-fog-light-topology.unit.test.ts +21 -0
- package/src/__tests__/volumetric-fog-light-transaction.integration.test.ts +53 -0
- package/src/__tests__/volumetric-fog-m9-watcher.integration.test.ts +27 -0
- package/src/__tests__/volumetric-fog-point-light-owner.integration.test.ts +44 -0
- package/src/__tests__/volumetric-fog-point-spot-accumulation.integration.test.ts +49 -0
- package/src/__tests__/volumetric-fog-point-spot-contract.unit.test.ts +28 -0
- package/src/__tests__/volumetric-fog-point-spot-lkg.integration.test.ts +65 -0
- package/src/__tests__/volumetric-fog-point-spot-selection.integration.test.ts +49 -0
- package/src/__tests__/volumetric-fog-point-spot-temporal.unit.test.ts +55 -0
- package/src/__tests__/volumetric-fog-projector-contract.unit.test.ts +22 -0
- package/src/__tests__/volumetric-fog-projector-inspection.unit.test.ts +12 -0
- package/src/__tests__/volumetric-fog-projector-surface-volume.integration.test.ts +11 -0
- package/src/__tests__/volumetric-fog-projector-transaction.integration.test.ts +26 -0
- package/src/__tests__/volumetric-fog-recovery.integration.test.ts +47 -0
- package/src/__tests__/volumetric-fog-selected-light-resolution.integration.test.ts +63 -0
- package/src/__tests__/volumetric-fog-spot-closure.integration.test.ts +26 -0
- package/src/__tests__/volumetric-fog-spot-contract.test-d.ts +21 -0
- package/src/__tests__/volumetric-fog-spot-contract.unit.test.ts +27 -0
- package/src/__tests__/volumetric-fog-spot-frame-optics.integration.test.ts +14 -0
- package/src/__tests__/volumetric-fog-spot-optics.integration.test.ts +29 -0
- package/src/__tests__/volumetric-fog-stage-readback.dawn.test.ts +550 -0
- package/src/__tests__/volumetric-fog-temporal-selected-light.unit.test.ts +33 -0
- package/src/__tests__/volumetric-fog-temporal.unit.test.ts +45 -0
- package/src/__tests__/volumetric-fog-topology.unit.test.ts +237 -0
- package/src/__tests__/volumetric-fog-transparent.integration.test.ts +27 -0
- package/src/assembly/device-feature-admission.ts +73 -0
- package/src/assembly/directional-shadow-inspection.ts +122 -0
- package/src/assembly/factory.ts +1093 -246
- package/src/assembly/host-contract.ts +25 -0
- package/src/assembly/render-target-host.ts +847 -0
- package/src/assets/asset-decoders.ts +1 -1
- package/src/assets/render-asset-port.ts +7 -1
- package/src/capture/cube-views.ts +69 -0
- package/src/capture/scheduler.ts +265 -0
- package/src/components/__tests__/schema-contract.unit.test.ts +12 -0
- package/src/components/__tests__/schema-parity.unit.test.ts +9 -0
- package/src/components/camera.ts +4 -0
- package/src/components/cube-camera.ts +52 -0
- package/src/components/directional-light.ts +22 -2
- package/src/components/directional-shadow-filter.ts +57 -0
- package/src/components/index.ts +2 -0
- package/src/components/light-helpers.ts +85 -7
- package/src/components/reflection-probe.ts +49 -0
- package/src/components/spot-light.ts +22 -3
- package/src/device/gpu-residency.ts +168 -58
- package/src/environment/frame.ts +6 -24
- package/src/environment/lifecycle.ts +12 -0
- package/src/errors/render.ts +405 -143
- package/src/extract/directional-shadow-projection.ts +61 -0
- package/src/extract/environment.ts +57 -0
- package/src/extract/visibility.ts +25 -1
- package/src/features/fullscreen.ts +3 -0
- package/src/features/targets.ts +4 -1
- package/src/features/types.ts +10 -0
- package/src/fullscreen-post-process-pass.ts +43 -2
- package/src/gpu-driven/batch-topology.ts +1 -0
- package/src/gpu-driven/production-raster.ts +1 -3
- package/src/gpu-scene.ts +8 -1
- package/src/gpu-usage.ts +2 -0
- package/src/hdrp-buffers.ts +165 -59
- package/src/ibl/IblPipelineCache.ts +11 -0
- package/src/ibl/kernel-cache.ts +88 -0
- package/src/index.ts +186 -1
- package/src/inspection-types.ts +56 -0
- package/src/instances-derived-bounds.ts +171 -0
- package/src/light-buffer-layout.ts +74 -26
- package/src/mesh-material-bindings.ts +132 -0
- package/src/pbr-pipeline.ts +139 -27
- package/src/pipeline/standard-forward-lane.ts +65 -15
- package/src/pipeline/standard-lighting/errors.ts +6 -0
- package/src/pipeline/standard-lighting/graph.ts +157 -0
- package/src/pipeline/standard-lighting/inspection.ts +88 -0
- package/src/pipeline/standard-lighting/layout.ts +31 -0
- package/src/pipeline/standard-lighting/light-frame.ts +34 -0
- package/src/pipeline/standard-lighting/membership.ts +43 -0
- package/src/pipeline/standard-lighting/prepare.ts +37 -0
- package/src/pipeline/standard-lighting/topology.ts +120 -0
- package/src/pipeline/standard-lighting/transport.ts +77 -0
- package/src/pipeline/standard-pipeline.ts +141 -192
- package/src/pipeline/standard-post.ts +26 -7
- package/src/pipeline/standard-profile.ts +23 -30
- package/src/pipeline-spec.ts +84 -21
- package/src/point-shadow-inspection.ts +55 -0
- package/src/record/__tests__/temporal-payload.unit.test.ts +42 -1
- package/src/record/__tests__/transparent-group2-selection.unit.test.ts +73 -0
- package/src/record/__tests__/view-ubo-layout.unit.test.ts +40 -0
- package/src/record/frame-lighting.ts +470 -516
- package/src/record/frame-snapshot.ts +76 -28
- package/src/record/frame-targets.ts +23 -2
- package/src/record/frame.ts +1169 -79
- package/src/record/gpu-pass-timing/contract.ts +180 -0
- package/src/record/gpu-pass-timing/errors.ts +34 -0
- package/src/record/gpu-pass-timing/index.ts +37 -0
- package/src/record/gpu-pass-timing/parser.ts +97 -0
- package/src/record/gpu-pass-timing/session.ts +938 -0
- package/src/record/gpu-timing.ts +233 -0
- package/src/record/main-pass-geometry.ts +120 -80
- package/src/record/main-pass-material.ts +101 -11
- package/src/record/main-pass-sprite-draws.ts +54 -25
- package/src/record/main-pass.ts +71 -15
- package/src/record/render-context.ts +77 -0
- package/src/record/shadow-pass.ts +104 -66
- package/src/record/skybox-post-pass.ts +20 -4
- package/src/record/typed-frame-graph.ts +1016 -32
- package/src/record/view-ubo.ts +63 -28
- package/src/reflection/filter.ts +81 -0
- package/src/reflection/gpu-table.ts +44 -0
- package/src/reflection/projection.ts +281 -0
- package/src/render-contract.ts +147 -4
- package/src/render-data.ts +50 -22
- package/src/render-graph-primitives.ts +9 -4
- package/src/render-pipeline.ts +161 -2
- package/src/render-system-extract.ts +886 -103
- package/src/render-system.ts +1174 -66
- package/src/renderer-inspect.ts +66 -0
- package/src/renderer.ts +222 -0
- package/src/scene/render-scene.ts +117 -9
- package/src/shadow-atlas.ts +5 -5
- package/src/ssao-buffers.ts +9 -2
- package/src/targets/contracts.ts +182 -0
- package/src/targets/graph-projection.ts +169 -0
- package/src/targets/material-source.ts +143 -0
- package/src/targets/owner.ts +214 -0
- package/src/targets/physical.ts +18 -0
- package/src/targets/readback.ts +153 -0
- package/src/temporal/frame.ts +128 -0
- package/src/transmission/__tests__/standard-transmission.dawn.test.ts +61 -23
- package/src/typed-render-graph-primitives.ts +34 -2
- package/src/typed-shadow-atlas.ts +17 -0
- package/src/typed-shadow-passes.ts +47 -40
- package/src/volume/capability.ts +173 -0
- package/src/volume/component.ts +110 -0
- package/src/volume/extract.ts +21 -0
- package/src/volume/inspection.ts +78 -0
- package/src/volume/passes.ts +686 -0
- package/src/volume/recovery.ts +86 -0
- package/src/volume/resources.ts +236 -0
- package/src/volume/temporal.ts +89 -0
- package/dist/chunk-IPXCABEP.mjs.map +0 -1
- package/dist/chunk-LOSO4CTV.mjs.map +0 -1
- package/dist/chunk-RJRUS55L.mjs.map +0 -1
- package/dist/chunk-YTQ5C7YQ.mjs +0 -584
- package/dist/chunk-YTQ5C7YQ.mjs.map +0 -1
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { err, ok, type Result } from '@forgeax/engine-types';
|
|
2
|
+
import type { PreparedStandardLighting } from './prepare';
|
|
3
|
+
import type { StandardClusterTransport } from './transport';
|
|
4
|
+
|
|
5
|
+
/** A prepared frame with no local lights on a non-storage direct backend. */
|
|
6
|
+
export interface StandardNoLocalTopologyInput {
|
|
7
|
+
readonly kind: 'no-local-lights';
|
|
8
|
+
readonly prepared: PreparedStandardLighting;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/** A prepared frame whose Standard surface uses one proven Cluster transport. */
|
|
12
|
+
export interface StandardClusteredTopologyInput {
|
|
13
|
+
readonly kind: 'clustered';
|
|
14
|
+
readonly prepared: PreparedStandardLighting;
|
|
15
|
+
readonly transport: StandardClusterTransport;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* The only lighting value accepted by a Standard topology adapter. It is a
|
|
20
|
+
* projection of one prepared frame, not a second light/config/capability
|
|
21
|
+
* input. Both Forward and Deferred keep the same object identity for a frame.
|
|
22
|
+
*/
|
|
23
|
+
export type StandardTopologyInput = StandardNoLocalTopologyInput | StandardClusteredTopologyInput;
|
|
24
|
+
|
|
25
|
+
export type StandardTopologyInputValue = StandardTopologyInput;
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Stable identity for the graph-facing Standard lighting declaration.
|
|
29
|
+
*
|
|
30
|
+
* The prepared light payload itself is frame-local and must never be retained
|
|
31
|
+
* by a compiled graph. These are the only facts that affect the Cluster graph
|
|
32
|
+
* shape and persistent buffer contract, so the record owner can reject an old
|
|
33
|
+
* graph before uploading a payload derived from a different declaration.
|
|
34
|
+
*/
|
|
35
|
+
export function standardLightingTopologySignature(
|
|
36
|
+
input: StandardTopologyInputValue | undefined,
|
|
37
|
+
): string {
|
|
38
|
+
if (input === undefined) return 'missing';
|
|
39
|
+
if (input.kind === 'no-local-lights') return 'no-local-lights';
|
|
40
|
+
return JSON.stringify({
|
|
41
|
+
kind: input.kind,
|
|
42
|
+
transport: input.transport.kind,
|
|
43
|
+
producer: input.transport.producer,
|
|
44
|
+
grid: input.prepared.layout.grid,
|
|
45
|
+
clusterGridU32Length: input.prepared.layout.clusterGridU32Length,
|
|
46
|
+
lightIndexListCapacity: input.prepared.layout.lightIndexListCapacity,
|
|
47
|
+
lightDataSlotCount: input.prepared.layout.lightDataSlotCount,
|
|
48
|
+
lightBoundsInt32Length: input.prepared.layout.lightBoundsInt32Length,
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export interface StandardTopologyInputError {
|
|
53
|
+
readonly code: 'topology-input-invalid';
|
|
54
|
+
readonly expected: 'prepared Standard lighting topology input';
|
|
55
|
+
readonly hint: 'derive topology from prepared Standard lighting';
|
|
56
|
+
readonly detail: {
|
|
57
|
+
readonly field: 'kind' | 'prepared' | 'transport' | 'lights' | 'capabilities';
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function invalid(
|
|
62
|
+
field: StandardTopologyInputError['detail']['field'],
|
|
63
|
+
): Result<never, StandardTopologyInputError> {
|
|
64
|
+
return err({
|
|
65
|
+
code: 'topology-input-invalid',
|
|
66
|
+
expected: 'prepared Standard lighting topology input',
|
|
67
|
+
hint: 'derive topology from prepared Standard lighting',
|
|
68
|
+
detail: { field },
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Validate that transport and prepared membership are the same derivation.
|
|
74
|
+
* The identity checks make it impossible for an adapter to silently combine
|
|
75
|
+
* one path's layout/counts with another path's prepared light corpus.
|
|
76
|
+
*/
|
|
77
|
+
export function deriveStandardTopologyInput(
|
|
78
|
+
input: StandardTopologyInput,
|
|
79
|
+
): Result<StandardTopologyInputValue, StandardTopologyInputError> {
|
|
80
|
+
const candidate = input as StandardTopologyInput & {
|
|
81
|
+
readonly kind?: unknown;
|
|
82
|
+
readonly lights?: unknown;
|
|
83
|
+
readonly capabilities?: unknown;
|
|
84
|
+
readonly transport?: unknown;
|
|
85
|
+
};
|
|
86
|
+
if ('lights' in candidate) return invalid('lights');
|
|
87
|
+
if ('capabilities' in candidate) return invalid('capabilities');
|
|
88
|
+
if (input === null || typeof input !== 'object') return invalid('kind');
|
|
89
|
+
if (input.prepared === null || typeof input.prepared !== 'object') {
|
|
90
|
+
return invalid('prepared');
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const prepared = input.prepared;
|
|
94
|
+
if (input.kind === 'no-local-lights') {
|
|
95
|
+
if (prepared.local.length !== 0 || 'transport' in candidate) return invalid('transport');
|
|
96
|
+
return ok(input);
|
|
97
|
+
}
|
|
98
|
+
if (input.kind !== 'clustered') return invalid('kind');
|
|
99
|
+
if (
|
|
100
|
+
!('transport' in candidate) ||
|
|
101
|
+
candidate.transport === null ||
|
|
102
|
+
typeof candidate.transport !== 'object'
|
|
103
|
+
) {
|
|
104
|
+
return invalid('transport');
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const transport = input.transport;
|
|
108
|
+
const requested = prepared.local.length;
|
|
109
|
+
const transportMatchesPrepared =
|
|
110
|
+
transport.layout === prepared.layout &&
|
|
111
|
+
transport.requestedLightCount === requested &&
|
|
112
|
+
transport.admittedLightCount === requested &&
|
|
113
|
+
transport.membershipEntryCount === prepared.membershipEntryCount &&
|
|
114
|
+
transport.lightBoundsBytes === prepared.lightBounds.byteLength;
|
|
115
|
+
const producerMatchesKind =
|
|
116
|
+
(transport.producer === 'gpu' && transport.kind === 'compute-storage') ||
|
|
117
|
+
(transport.producer === 'cpu' && transport.kind === 'cpu-storage');
|
|
118
|
+
if (!transportMatchesPrepared || !producerMatchesKind) return invalid('transport');
|
|
119
|
+
return ok(input);
|
|
120
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { err, ok, type Result } from '@forgeax/engine-types';
|
|
2
|
+
import { type RenderError, StandardClusterTransportUnavailableError } from '../../errors/render';
|
|
3
|
+
import type { PreparedStandardLighting } from './prepare';
|
|
4
|
+
|
|
5
|
+
export interface StandardClusterCapabilities {
|
|
6
|
+
readonly compute: boolean;
|
|
7
|
+
readonly storageBuffer: boolean;
|
|
8
|
+
/**
|
|
9
|
+
* The graph producer is ready to encode the selected compute lane. The
|
|
10
|
+
* renderer supplies this from the actual pipeline + bind-group layout; it is
|
|
11
|
+
* required so capability admission cannot forge a GPU producer from
|
|
12
|
+
* `compute` alone.
|
|
13
|
+
*/
|
|
14
|
+
readonly membershipPipelineReady: boolean;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/** Only transports with storage-backed membership representation exist. */
|
|
18
|
+
export type StandardClusterTransportKind = 'compute-storage' | 'cpu-storage';
|
|
19
|
+
export type StandardClusterMembershipProducer = 'cpu' | 'gpu';
|
|
20
|
+
|
|
21
|
+
export interface StandardClusterTransport {
|
|
22
|
+
readonly kind: StandardClusterTransportKind;
|
|
23
|
+
readonly producer: StandardClusterMembershipProducer;
|
|
24
|
+
readonly layout: PreparedStandardLighting['layout'];
|
|
25
|
+
readonly requestedLightCount: number;
|
|
26
|
+
readonly admittedLightCount: number;
|
|
27
|
+
readonly membershipEntryCount: number;
|
|
28
|
+
readonly occupiedClusterCount: number;
|
|
29
|
+
readonly clusterGridBytes: number;
|
|
30
|
+
readonly lightIndexListBytes: number;
|
|
31
|
+
readonly lightDataBytes: number;
|
|
32
|
+
readonly lightBoundsBytes: number;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function occupiedClusterCount(prepared: PreparedStandardLighting): number {
|
|
36
|
+
let occupied = 0;
|
|
37
|
+
for (let index = 1; index < prepared.clusterGrid.length; index += 2) {
|
|
38
|
+
if ((prepared.clusterGrid[index] ?? 0) > 0) occupied += 1;
|
|
39
|
+
}
|
|
40
|
+
return occupied;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Select a transport from one prepared frame. Capability facts choose only a
|
|
45
|
+
* producer/storage pair; all counts and byte sizes come from that frame.
|
|
46
|
+
*/
|
|
47
|
+
export function selectStandardClusterTransport(
|
|
48
|
+
capabilities: StandardClusterCapabilities,
|
|
49
|
+
prepared: PreparedStandardLighting,
|
|
50
|
+
): Result<StandardClusterTransport, RenderError> {
|
|
51
|
+
const requested = prepared.local.length;
|
|
52
|
+
if (!capabilities.storageBuffer) {
|
|
53
|
+
return err(
|
|
54
|
+
new StandardClusterTransportUnavailableError(
|
|
55
|
+
requested,
|
|
56
|
+
'enable a proven storage-buffer Cluster transport; compute without storage is not a membership path',
|
|
57
|
+
),
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const producer: StandardClusterMembershipProducer =
|
|
62
|
+
capabilities.compute && capabilities.membershipPipelineReady ? 'gpu' : 'cpu';
|
|
63
|
+
const kind: StandardClusterTransportKind = producer === 'gpu' ? 'compute-storage' : 'cpu-storage';
|
|
64
|
+
return ok({
|
|
65
|
+
kind,
|
|
66
|
+
producer,
|
|
67
|
+
layout: prepared.layout,
|
|
68
|
+
requestedLightCount: requested,
|
|
69
|
+
admittedLightCount: requested,
|
|
70
|
+
membershipEntryCount: prepared.membershipEntryCount,
|
|
71
|
+
occupiedClusterCount: occupiedClusterCount(prepared),
|
|
72
|
+
clusterGridBytes: prepared.layout.clusterGridU32Length * Uint32Array.BYTES_PER_ELEMENT,
|
|
73
|
+
lightIndexListBytes: prepared.membershipEntryCount * Uint32Array.BYTES_PER_ELEMENT,
|
|
74
|
+
lightDataBytes: requested * 64,
|
|
75
|
+
lightBoundsBytes: prepared.lightBounds.byteLength,
|
|
76
|
+
});
|
|
77
|
+
}
|
|
@@ -1,21 +1,13 @@
|
|
|
1
|
-
import
|
|
2
|
-
GraphAccess,
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
RenderGraphBuilder,
|
|
1
|
+
import {
|
|
2
|
+
type GraphAccess,
|
|
3
|
+
type GraphTextureDescriptor,
|
|
4
|
+
type RenderGraphBuilder,
|
|
6
5
|
RenderGraphError,
|
|
7
6
|
} from '@forgeax/engine-render-graph';
|
|
8
7
|
import { err, ok, type Result } from '@forgeax/engine-types';
|
|
9
|
-
import {
|
|
8
|
+
import { SceneDataUnavailableError, StandardProfileInvalidError } from '../errors/render';
|
|
10
9
|
import type { FramePlan } from '../extract/environment';
|
|
11
|
-
import {
|
|
12
|
-
GPU_BUFFER_USAGE_COPY_DST,
|
|
13
|
-
GPU_BUFFER_USAGE_STORAGE,
|
|
14
|
-
GPU_BUFFER_USAGE_UNIFORM,
|
|
15
|
-
} from '../gpu-usage';
|
|
16
|
-
import { getOrCreateHdrpBuffers, type HdrpBuffers } from '../hdrp-buffers';
|
|
17
10
|
import { DEFERRED_COLOR_FORMATS } from '../pipeline-spec';
|
|
18
|
-
import type { _InternalRenderPipelineContext } from '../record/render-context';
|
|
19
11
|
import type {
|
|
20
12
|
RenderPipeline,
|
|
21
13
|
RenderPipelineBuildContext,
|
|
@@ -47,16 +39,21 @@ import {
|
|
|
47
39
|
typedFrameClearColor,
|
|
48
40
|
} from '../typed-render-graph-primitives';
|
|
49
41
|
import { addTypedShadowPasses } from '../typed-shadow-passes';
|
|
50
|
-
|
|
42
|
+
import { addAuthoredVolumetricFogPasses } from '../volume/passes';
|
|
51
43
|
import { buildStandardForwardLane } from './standard-forward-lane';
|
|
44
|
+
import {
|
|
45
|
+
addStandardClusterMembershipPass,
|
|
46
|
+
importStandardClusterBuffers,
|
|
47
|
+
standardClusterReadAccesses,
|
|
48
|
+
} from './standard-lighting/graph';
|
|
49
|
+
import {
|
|
50
|
+
deriveStandardTopologyInput,
|
|
51
|
+
type StandardTopologyInputValue,
|
|
52
|
+
} from './standard-lighting/topology';
|
|
52
53
|
import { addStandardPost } from './standard-post';
|
|
53
54
|
import {
|
|
54
|
-
CLUSTER_GRID_STRIDE_U32,
|
|
55
|
-
DEFAULT_CLUSTER_GRID,
|
|
56
55
|
DEFAULT_STANDARD_PROFILE,
|
|
57
|
-
|
|
58
|
-
MAX_LIGHTS,
|
|
59
|
-
resolveStandardLane,
|
|
56
|
+
STANDARD_LIGHT_COUNTS,
|
|
60
57
|
STANDARD_PIPELINE_ID,
|
|
61
58
|
type StandardProfile,
|
|
62
59
|
} from './standard-profile';
|
|
@@ -124,26 +121,11 @@ fn cs_cluster_membership(@builtin(global_invocation_id) global_id : vec3<u32>) {
|
|
|
124
121
|
}
|
|
125
122
|
}
|
|
126
123
|
`;
|
|
127
|
-
export class HdrpInstallError extends Error {
|
|
128
|
-
readonly code = 'hdrp-grid-invalid' as const;
|
|
129
|
-
readonly expected = 'clusterGrid.{x,y,z} each integer in [1, 64]';
|
|
130
|
-
readonly hint: string;
|
|
131
|
-
readonly detail: { readonly x: number; readonly y: number; readonly z: number };
|
|
132
|
-
|
|
133
|
-
constructor(x: number, y: number, z: number) {
|
|
134
|
-
const hint = `clusterGrid {x:${x}, y:${y}, z:${z}} is invalid; set {x,y,z} to positive integers in [1, 64]`;
|
|
135
|
-
super(`hdrp-grid-invalid: ${hint}`);
|
|
136
|
-
this.name = 'HdrpInstallError';
|
|
137
|
-
this.hint = hint;
|
|
138
|
-
this.detail = { x, y, z };
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
|
|
142
124
|
export function validateClusterGrid(grid: {
|
|
143
125
|
x: number;
|
|
144
126
|
y: number;
|
|
145
127
|
z: number;
|
|
146
|
-
}): Result<{ x: number; y: number; z: number },
|
|
128
|
+
}): Result<{ x: number; y: number; z: number }, StandardProfileInvalidError> {
|
|
147
129
|
const { x, y, z } = grid;
|
|
148
130
|
return Number.isInteger(x) &&
|
|
149
131
|
Number.isInteger(y) &&
|
|
@@ -155,7 +137,12 @@ export function validateClusterGrid(grid: {
|
|
|
155
137
|
z >= 1 &&
|
|
156
138
|
z <= 64
|
|
157
139
|
? ok({ x, y, z })
|
|
158
|
-
: err(
|
|
140
|
+
: err(
|
|
141
|
+
new StandardProfileInvalidError(
|
|
142
|
+
`clusterGrid {x:${x}, y:${y}, z:${z}} is invalid; set x, y, and z to positive integers in [1, 64]`,
|
|
143
|
+
{ field: 'clusterGrid', actual: { x, y, z } },
|
|
144
|
+
),
|
|
145
|
+
);
|
|
159
146
|
}
|
|
160
147
|
|
|
161
148
|
function target(
|
|
@@ -166,114 +153,20 @@ function target(
|
|
|
166
153
|
return createRenderPipelineTarget(graph, label, descriptor);
|
|
167
154
|
}
|
|
168
155
|
|
|
169
|
-
|
|
170
|
-
readonly lightData: GraphBuffer;
|
|
171
|
-
readonly clusterGrid: GraphBuffer;
|
|
172
|
-
readonly lightIndexList: GraphBuffer;
|
|
173
|
-
readonly clusterUniform: GraphBuffer;
|
|
174
|
-
readonly lightBounds: GraphBuffer;
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
function importBuffers(
|
|
178
|
-
graph: RenderGraphBuilder<RenderPipelineFrame>,
|
|
179
|
-
topology: RenderPipelineTopology,
|
|
180
|
-
): Result<HdrpGraphBuffers, RenderGraphError> {
|
|
181
|
-
const grid = topology.config?.clusterGrid ?? DEFAULT_CLUSTER_GRID;
|
|
182
|
-
const cells = grid.x * grid.y * grid.z;
|
|
183
|
-
const storage = topology.lane.storageBuffer;
|
|
184
|
-
const usage =
|
|
185
|
-
(storage ? GPU_BUFFER_USAGE_STORAGE : GPU_BUFFER_USAGE_UNIFORM) | GPU_BUFFER_USAGE_COPY_DST;
|
|
186
|
-
const resolve = (frame: RenderPipelineFrame): HdrpBuffers => {
|
|
187
|
-
const internal = frame as _InternalRenderPipelineContext;
|
|
188
|
-
const buffers = getOrCreateHdrpBuffers(internal.runtime, grid);
|
|
189
|
-
if (buffers === null) throw new Error('HDRP persistent buffer allocation failed');
|
|
190
|
-
return buffers;
|
|
191
|
-
};
|
|
192
|
-
const lightData = graph.importBuffer(
|
|
193
|
-
'hdrp-light-data',
|
|
194
|
-
{ size: (storage ? MAX_LIGHTS : 128) * 64, usage },
|
|
195
|
-
(frame) => resolve(frame).lightDataBuffer,
|
|
196
|
-
);
|
|
197
|
-
if (!lightData.ok) return lightData;
|
|
198
|
-
const clusterGrid = graph.importBuffer(
|
|
199
|
-
'hdrp-cluster-grid',
|
|
200
|
-
{ size: storage ? cells * CLUSTER_GRID_STRIDE_U32 * 4 : 32, usage },
|
|
201
|
-
(frame) => resolve(frame).clusterGridBuffer,
|
|
202
|
-
);
|
|
203
|
-
if (!clusterGrid.ok) return clusterGrid;
|
|
204
|
-
const lightIndexList = graph.importBuffer(
|
|
205
|
-
'hdrp-light-index-list',
|
|
206
|
-
{ size: storage ? LIGHT_INDEX_LIST_CAPACITY * 4 : 32, usage },
|
|
207
|
-
(frame) => resolve(frame).lightIndexListBuffer,
|
|
208
|
-
);
|
|
209
|
-
if (!lightIndexList.ok) return lightIndexList;
|
|
210
|
-
const clusterUniform = graph.importBuffer(
|
|
211
|
-
'hdrp-cluster-uniform',
|
|
212
|
-
{ size: 32, usage: GPU_BUFFER_USAGE_UNIFORM | GPU_BUFFER_USAGE_COPY_DST },
|
|
213
|
-
(frame) => resolve(frame).clusterUniformBuffer,
|
|
214
|
-
);
|
|
215
|
-
if (!clusterUniform.ok) return clusterUniform;
|
|
216
|
-
const lightBounds = graph.importBuffer(
|
|
217
|
-
'hdrp-light-bounds',
|
|
218
|
-
{ size: MAX_LIGHTS * 6 * 4, usage },
|
|
219
|
-
(frame) => resolve(frame).lightBoundsBuffer,
|
|
220
|
-
);
|
|
221
|
-
if (!lightBounds.ok) return lightBounds;
|
|
222
|
-
return ok({
|
|
223
|
-
lightData: lightData.value,
|
|
224
|
-
clusterGrid: clusterGrid.value,
|
|
225
|
-
lightIndexList: lightIndexList.value,
|
|
226
|
-
clusterUniform: clusterUniform.value,
|
|
227
|
-
lightBounds: lightBounds.value,
|
|
228
|
-
});
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
function addMembershipPass(
|
|
232
|
-
graph: RenderGraphBuilder<RenderPipelineFrame>,
|
|
233
|
-
topology: RenderPipelineTopology,
|
|
234
|
-
buffers: HdrpGraphBuffers,
|
|
235
|
-
): Result<void, RenderGraphError> {
|
|
236
|
-
if (!topology.lane.compute || !topology.lane.storageBuffer) return ok(undefined);
|
|
237
|
-
return graph.addComputePass('cluster-membership-producer', {
|
|
238
|
-
accesses: [
|
|
239
|
-
{ resource: buffers.clusterGrid, usage: 'storage-read' },
|
|
240
|
-
{ resource: buffers.clusterUniform, usage: 'uniform-read' },
|
|
241
|
-
{ resource: buffers.lightBounds, usage: 'storage-read' },
|
|
242
|
-
{ resource: buffers.lightIndexList, usage: 'storage-write' },
|
|
243
|
-
],
|
|
244
|
-
executeIf: (frame) => {
|
|
245
|
-
const internal = frame as _InternalRenderPipelineContext;
|
|
246
|
-
return (
|
|
247
|
-
internal.pipelineState.hdrpClusterMembershipPipeline !== null &&
|
|
248
|
-
internal.hdrpClusterMembershipBindGroup !== null
|
|
249
|
-
);
|
|
250
|
-
},
|
|
251
|
-
encode: ({ pass, frame }) => {
|
|
252
|
-
const internal = frame as _InternalRenderPipelineContext;
|
|
253
|
-
const pipeline = internal.pipelineState.hdrpClusterMembershipPipeline;
|
|
254
|
-
const bindings = internal.hdrpClusterMembershipBindGroup;
|
|
255
|
-
if (pipeline === null || bindings === null) return;
|
|
256
|
-
const grid = topology.config?.clusterGrid ?? DEFAULT_CLUSTER_GRID;
|
|
257
|
-
pass.setPipeline(pipeline);
|
|
258
|
-
pass.setBindGroup(0, bindings);
|
|
259
|
-
pass.dispatchWorkgroups(Math.ceil((grid.x * grid.y * grid.z) / 64));
|
|
260
|
-
},
|
|
261
|
-
});
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
function buildHdrp(
|
|
156
|
+
function buildStandardDeferredLane(
|
|
265
157
|
context: RenderPipelineBuildContext<RenderPipelineFrame>,
|
|
266
158
|
topology: RenderPipelineTopology,
|
|
159
|
+
lighting: StandardTopologyInputValue,
|
|
267
160
|
): ReturnType<RenderPipeline['build']> {
|
|
268
|
-
if (topology.lane.maxColorAttachments < 4) {
|
|
269
|
-
return err(new HdrpDeferredCapsInsufficientError(topology.lane.maxColorAttachments));
|
|
270
|
-
}
|
|
271
161
|
const graph = context.graph;
|
|
272
162
|
const surface = importRenderPipelineSurface(graph, topology);
|
|
273
163
|
if (!surface.ok) return surface;
|
|
274
|
-
const buffers =
|
|
164
|
+
const buffers = importStandardClusterBuffers(graph, lighting);
|
|
275
165
|
if (!buffers.ok) return buffers;
|
|
276
|
-
const membership =
|
|
166
|
+
const membership =
|
|
167
|
+
buffers.value === null
|
|
168
|
+
? ok(undefined)
|
|
169
|
+
: addStandardClusterMembershipPass(graph, lighting, buffers.value);
|
|
277
170
|
if (!membership.ok) return membership;
|
|
278
171
|
const shadows = addTypedShadowPasses(graph, topology);
|
|
279
172
|
if (!shadows.ok) return shadows;
|
|
@@ -304,9 +197,7 @@ function buildHdrp(
|
|
|
304
197
|
taa: topology.camera.antialias === 'taa',
|
|
305
198
|
motionBlur: topology.temporal?.motionBlur === true,
|
|
306
199
|
});
|
|
307
|
-
const temporalLane = topology.lane.compute
|
|
308
|
-
? (topology.standardProfile?.lighting ?? 'direct')
|
|
309
|
-
: 'cpu-webgl2';
|
|
200
|
+
const temporalLane = topology.lane.compute ? 'clustered' : 'cpu-webgl2';
|
|
310
201
|
const temporalAdmission = standardTemporalLaneAdmission({
|
|
311
202
|
lane: temporalLane,
|
|
312
203
|
demand: temporalDemand,
|
|
@@ -329,7 +220,11 @@ function buildHdrp(
|
|
|
329
220
|
}),
|
|
330
221
|
);
|
|
331
222
|
}
|
|
332
|
-
|
|
223
|
+
const gpuDriven = context.projectGpuDriven({
|
|
224
|
+
format: scene.value.format,
|
|
225
|
+
sampleCount: scene.value.sampleCount,
|
|
226
|
+
});
|
|
227
|
+
if (!gpuDriven.ok) return gpuDriven;
|
|
333
228
|
const gbuffer = addTypedScenePass(graph, {
|
|
334
229
|
name: 'g-buffer',
|
|
335
230
|
color: gbuffer0.value,
|
|
@@ -362,25 +257,13 @@ function buildHdrp(
|
|
|
362
257
|
{ resource: gbuffer1.value.view, usage: 'sampled-read' },
|
|
363
258
|
{ resource: gbuffer2.value.view, usage: 'sampled-read' },
|
|
364
259
|
{ resource: depth.value.view, usage: 'depth-stencil-read' },
|
|
365
|
-
|
|
366
|
-
resource: buffers.value.lightData,
|
|
367
|
-
usage: topology.lane.storageBuffer ? 'storage-read' : 'uniform-read',
|
|
368
|
-
},
|
|
369
|
-
{
|
|
370
|
-
resource: buffers.value.clusterGrid,
|
|
371
|
-
usage: topology.lane.storageBuffer ? 'storage-read' : 'uniform-read',
|
|
372
|
-
},
|
|
373
|
-
{
|
|
374
|
-
resource: buffers.value.lightIndexList,
|
|
375
|
-
usage: topology.lane.storageBuffer ? 'storage-read' : 'uniform-read',
|
|
376
|
-
},
|
|
377
|
-
{ resource: buffers.value.clusterUniform, usage: 'uniform-read' },
|
|
260
|
+
...(buffers.value === null ? [] : standardClusterReadAccesses(buffers.value)),
|
|
378
261
|
...(ssao === undefined
|
|
379
262
|
? []
|
|
380
263
|
: ([{ resource: ssao.view, usage: 'sampled-read' }] satisfies GraphAccess[])),
|
|
381
264
|
{ resource: scene.value.view, usage: 'color-attachment' },
|
|
382
265
|
];
|
|
383
|
-
const
|
|
266
|
+
const lightingPass = graph.addRasterPass('lighting', {
|
|
384
267
|
accesses: lightingAccesses,
|
|
385
268
|
colorAttachments: [
|
|
386
269
|
{
|
|
@@ -392,7 +275,7 @@ function buildHdrp(
|
|
|
392
275
|
],
|
|
393
276
|
encode: () => undefined,
|
|
394
277
|
});
|
|
395
|
-
if (!
|
|
278
|
+
if (!lightingPass.ok) return lightingPass;
|
|
396
279
|
|
|
397
280
|
const skybox = addTypedSkyboxPass(graph, scene.value);
|
|
398
281
|
if (!skybox.ok) return skybox;
|
|
@@ -402,21 +285,8 @@ function buildHdrp(
|
|
|
402
285
|
demand: transmissionDemand,
|
|
403
286
|
sourceSampleCount: scene.value.sampleCount,
|
|
404
287
|
}).active;
|
|
405
|
-
const forwardExtraAccesses: GraphAccess[] =
|
|
406
|
-
|
|
407
|
-
resource: buffers.value.lightData,
|
|
408
|
-
usage: topology.lane.storageBuffer ? 'storage-read' : 'uniform-read',
|
|
409
|
-
},
|
|
410
|
-
{
|
|
411
|
-
resource: buffers.value.clusterGrid,
|
|
412
|
-
usage: topology.lane.storageBuffer ? 'storage-read' : 'uniform-read',
|
|
413
|
-
},
|
|
414
|
-
{
|
|
415
|
-
resource: buffers.value.lightIndexList,
|
|
416
|
-
usage: topology.lane.storageBuffer ? 'storage-read' : 'uniform-read',
|
|
417
|
-
},
|
|
418
|
-
{ resource: buffers.value.clusterUniform, usage: 'uniform-read' },
|
|
419
|
-
];
|
|
288
|
+
const forwardExtraAccesses: GraphAccess[] =
|
|
289
|
+
buffers.value === null ? [] : [...standardClusterReadAccesses(buffers.value)];
|
|
420
290
|
|
|
421
291
|
const forward = addTypedScenePass(graph, {
|
|
422
292
|
name: 'forward',
|
|
@@ -429,14 +299,17 @@ function buildHdrp(
|
|
|
429
299
|
gbuffer0.value,
|
|
430
300
|
gbuffer1.value,
|
|
431
301
|
gbuffer2.value,
|
|
432
|
-
shadows.value.directional,
|
|
302
|
+
...(shadows.value.directional === undefined ? [] : [shadows.value.directional]),
|
|
433
303
|
shadows.value.spot,
|
|
434
304
|
...(shadows.value.point === undefined ? [] : [shadows.value.point]),
|
|
435
305
|
...(ssao === undefined ? [] : [ssao]),
|
|
436
306
|
],
|
|
437
|
-
|
|
307
|
+
...(shadows.value.directional === undefined
|
|
308
|
+
? {}
|
|
309
|
+
: { directionalShadow: shadows.value.directional }),
|
|
438
310
|
spotShadow: shadows.value.spot,
|
|
439
311
|
...(ssao === undefined ? {} : { ssao }),
|
|
312
|
+
...(gpuDriven.value === undefined ? {} : { gpuDriven: gpuDriven.value }),
|
|
440
313
|
passKind: 'forward',
|
|
441
314
|
...(transmissionActive ? { recordMode: 'opaque' as const } : {}),
|
|
442
315
|
extraAccesses: forwardExtraAccesses,
|
|
@@ -471,7 +344,7 @@ function buildHdrp(
|
|
|
471
344
|
gbuffer0.value,
|
|
472
345
|
gbuffer1.value,
|
|
473
346
|
gbuffer2.value,
|
|
474
|
-
shadows.value.directional,
|
|
347
|
+
...(shadows.value.directional === undefined ? [] : [shadows.value.directional]),
|
|
475
348
|
shadows.value.spot,
|
|
476
349
|
...(shadows.value.point === undefined ? [] : [shadows.value.point]),
|
|
477
350
|
...(ssao === undefined ? [] : [ssao]),
|
|
@@ -500,7 +373,7 @@ function buildHdrp(
|
|
|
500
373
|
gbuffer0.value,
|
|
501
374
|
gbuffer1.value,
|
|
502
375
|
gbuffer2.value,
|
|
503
|
-
shadows.value.directional,
|
|
376
|
+
...(shadows.value.directional === undefined ? [] : [shadows.value.directional]),
|
|
504
377
|
shadows.value.spot,
|
|
505
378
|
...(shadows.value.point === undefined ? [] : [shadows.value.point]),
|
|
506
379
|
...(ssao === undefined ? [] : [ssao]),
|
|
@@ -516,9 +389,28 @@ function buildHdrp(
|
|
|
516
389
|
const temporal = addTransmissionBackdropTemporalPass(graph, scene.value);
|
|
517
390
|
if (!temporal.ok) return temporal;
|
|
518
391
|
}
|
|
392
|
+
if (topology.volumetricFog?.enabled === true) {
|
|
393
|
+
const depthSample = graph.view(depth.value.texture, {
|
|
394
|
+
label: 'scene-depth.sample',
|
|
395
|
+
dimension: '2d',
|
|
396
|
+
aspect: 'depth-only',
|
|
397
|
+
});
|
|
398
|
+
if (!depthSample.ok) return depthSample;
|
|
399
|
+
const volume = addAuthoredVolumetricFogPasses(
|
|
400
|
+
graph,
|
|
401
|
+
topology,
|
|
402
|
+
scene.value,
|
|
403
|
+
depthSample.value,
|
|
404
|
+
shadows.value.directional?.view,
|
|
405
|
+
shadows.value.spot.view,
|
|
406
|
+
);
|
|
407
|
+
if (!volume.ok) return volume;
|
|
408
|
+
}
|
|
409
|
+
// The volume-composite pass remains in linear HDR before tone mapping.
|
|
519
410
|
|
|
520
411
|
const features = context.contributeFeatures([
|
|
521
412
|
{
|
|
413
|
+
name: 'linear-hdr',
|
|
522
414
|
kind: 'scene-color',
|
|
523
415
|
texture: scene.value.texture,
|
|
524
416
|
view: scene.value.view,
|
|
@@ -536,8 +428,7 @@ function buildHdrp(
|
|
|
536
428
|
if (!features.ok) return features;
|
|
537
429
|
const observation = addTypedFrameObservationPass(graph, scene.value, 'forgeax::standard');
|
|
538
430
|
if (!observation.ok) return observation;
|
|
539
|
-
|
|
540
|
-
return addStandardPost(
|
|
431
|
+
const post = addStandardPost(
|
|
541
432
|
context,
|
|
542
433
|
topology,
|
|
543
434
|
scene.value,
|
|
@@ -545,13 +436,19 @@ function buildHdrp(
|
|
|
545
436
|
surface.value,
|
|
546
437
|
temporal.value?.temporal,
|
|
547
438
|
);
|
|
439
|
+
if (!post.ok) return post;
|
|
440
|
+
const cubeCaptures = context.contributeCubeCaptures?.();
|
|
441
|
+
if (cubeCaptures !== undefined && !cubeCaptures.ok) return cubeCaptures;
|
|
442
|
+
return ok(undefined);
|
|
548
443
|
}
|
|
549
|
-
const buildStandardClusteredLane = buildHdrp;
|
|
550
|
-
|
|
551
444
|
export interface StandardPipeline extends RenderPipeline {
|
|
552
445
|
readonly identity: typeof STANDARD_PIPELINE_ID;
|
|
553
446
|
}
|
|
554
447
|
|
|
448
|
+
export function standardProfileSupportsReflectionProbes(_profile: StandardProfile): boolean {
|
|
449
|
+
return true;
|
|
450
|
+
}
|
|
451
|
+
|
|
555
452
|
/** Standard graph inputs are derived once from the immutable frame plan. */
|
|
556
453
|
export type StandardFramePlan = FramePlan;
|
|
557
454
|
|
|
@@ -559,6 +456,43 @@ function profileFor(topology: RenderPipelineTopology): StandardProfile {
|
|
|
559
456
|
return topology.standardProfile ?? DEFAULT_STANDARD_PROFILE;
|
|
560
457
|
}
|
|
561
458
|
|
|
459
|
+
function resolveStandardTopologyInput(
|
|
460
|
+
context: RenderPipelineBuildContext<RenderPipelineFrame>,
|
|
461
|
+
): Result<StandardTopologyInputValue, RenderGraphError> {
|
|
462
|
+
const supplied = context.standardLighting;
|
|
463
|
+
if (supplied !== undefined) {
|
|
464
|
+
const derived = deriveStandardTopologyInput(supplied);
|
|
465
|
+
if (derived.ok) return derived;
|
|
466
|
+
return err(
|
|
467
|
+
new RenderGraphError({
|
|
468
|
+
code: 'resource-descriptor-invalid',
|
|
469
|
+
expected: 'Forward/Deferred consume one prepared Standard topology input',
|
|
470
|
+
hint: derived.error.hint,
|
|
471
|
+
detail: {
|
|
472
|
+
resourceLabel: 'forgeax::standard',
|
|
473
|
+
field: `standardLighting.${derived.error.detail.field}`,
|
|
474
|
+
expected: derived.error.expected,
|
|
475
|
+
actual: 'invalid',
|
|
476
|
+
},
|
|
477
|
+
}),
|
|
478
|
+
);
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
return err(
|
|
482
|
+
new RenderGraphError({
|
|
483
|
+
code: 'resource-descriptor-invalid',
|
|
484
|
+
expected: 'RenderPipelineBuildContext.standardLighting from frame preparation',
|
|
485
|
+
hint: 'prepare Standard lighting once, select a proven Cluster transport, and pass it to both lanes',
|
|
486
|
+
detail: {
|
|
487
|
+
resourceLabel: 'forgeax::standard',
|
|
488
|
+
field: 'standardLighting',
|
|
489
|
+
expected: 'prepared Standard lighting topology input',
|
|
490
|
+
actual: 'invalid',
|
|
491
|
+
},
|
|
492
|
+
}),
|
|
493
|
+
);
|
|
494
|
+
}
|
|
495
|
+
|
|
562
496
|
function standardTopology(
|
|
563
497
|
topology: RenderPipelineTopology,
|
|
564
498
|
profile: StandardProfile,
|
|
@@ -576,26 +510,41 @@ function standardTopology(
|
|
|
576
510
|
}
|
|
577
511
|
|
|
578
512
|
/**
|
|
579
|
-
* The sole built-in pipeline entry point.
|
|
580
|
-
*
|
|
581
|
-
*
|
|
513
|
+
* The sole built-in pipeline entry point. All local lights use the same
|
|
514
|
+
* prepared Cluster topology; the profile chooses only Forward or Deferred
|
|
515
|
+
* graph shape and never a second lighting authority.
|
|
582
516
|
*/
|
|
583
517
|
function buildStandard(
|
|
584
518
|
context: RenderPipelineBuildContext<RenderPipelineFrame>,
|
|
585
519
|
topology: RenderPipelineTopology,
|
|
586
520
|
): ReturnType<RenderPipeline['build']> {
|
|
587
521
|
const profile = profileFor(topology);
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
522
|
+
if (!STANDARD_LIGHT_COUNTS.some((count) => count === profile.lightCount)) {
|
|
523
|
+
return err(
|
|
524
|
+
new RenderGraphError({
|
|
525
|
+
code: 'resource-descriptor-invalid',
|
|
526
|
+
expected: 'StandardProfile.lightCount is one of 1, 32, or 256',
|
|
527
|
+
hint: 'set StandardProfile.lightCount to 1, 32, or 256',
|
|
528
|
+
detail: {
|
|
529
|
+
resourceLabel: 'forgeax::standard',
|
|
530
|
+
field: 'lightCount',
|
|
531
|
+
expected: '1 | 32 | 256',
|
|
532
|
+
actual: profile.lightCount,
|
|
533
|
+
},
|
|
534
|
+
}),
|
|
535
|
+
);
|
|
536
|
+
}
|
|
592
537
|
const effective = standardTopology(topology, profile);
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
//
|
|
596
|
-
|
|
597
|
-
if (
|
|
598
|
-
|
|
538
|
+
const lighting = resolveStandardTopologyInput(context);
|
|
539
|
+
if (!lighting.ok) return lighting;
|
|
540
|
+
// A missing Camera is an intentional clear-only frame. Keep it on the
|
|
541
|
+
// forward raster lane so clustered resources cannot introduce work.
|
|
542
|
+
if (effective.clearOnly === true) {
|
|
543
|
+
return buildStandardForwardLane(context, effective, lighting.value);
|
|
544
|
+
}
|
|
545
|
+
return profile.renderPath === 'forward'
|
|
546
|
+
? buildStandardForwardLane(context, effective, lighting.value)
|
|
547
|
+
: buildStandardDeferredLane(context, effective, lighting.value);
|
|
599
548
|
}
|
|
600
549
|
|
|
601
550
|
export const standardPipeline: StandardPipeline = Object.freeze({
|