@forgeax/engine-render 0.1.20 → 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 +21 -18
- 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-4XINDLAY.mjs → chunk-5YADUCA7.mjs} +1552 -1361
- package/dist/chunk-5YADUCA7.mjs.map +1 -0
- package/dist/{chunk-TBQJOK2L.mjs → chunk-6OPXDQ2E.mjs} +364 -51
- package/dist/chunk-6OPXDQ2E.mjs.map +1 -0
- package/dist/{chunk-M2MP4ZOU.mjs → chunk-BXBQQKFQ.mjs} +3 -9
- package/dist/chunk-BXBQQKFQ.mjs.map +1 -0
- package/dist/{chunk-CDTWTHZR.mjs → chunk-FS2KNUQH.mjs} +548 -6
- 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/construct-renderer.mjs +5826 -1003
- package/dist/construct-renderer.mjs.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 +141 -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/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 +28 -3
- 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 +10 -1
- 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 +14 -4
- 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-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 +27 -32
- package/dist/record/frame-lighting.d.ts.map +1 -1
- package/dist/record/frame-snapshot.d.ts +28 -14
- 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 +10 -4
- 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 +8 -3
- package/dist/record/gpu-timing.d.ts.map +1 -1
- package/dist/record/main-pass-geometry.d.ts.map +1 -1
- package/dist/record/main-pass-material.d.ts +22 -1
- package/dist/record/main-pass-material.d.ts.map +1 -1
- package/dist/record/main-pass-sprite-draws.d.ts.map +1 -1
- package/dist/record/main-pass.d.ts +2 -0
- package/dist/record/main-pass.d.ts.map +1 -1
- package/dist/record/render-context.d.ts +43 -2
- 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 +72 -4
- 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 +49 -7
- 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 +42 -2
- package/dist/render-pipeline.d.ts.map +1 -1
- package/dist/render-system-extract.d.ts +58 -17
- package/dist/render-system-extract.d.ts.map +1 -1
- package/dist/render-system.d.ts +17 -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/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/index.mjs +3 -3
- package/dist/typed-render-graph-primitives.d.ts +1 -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 +2 -2
- 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 +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__/material-observation.integration.test.ts +101 -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__/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 +18 -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 +48 -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 +132 -0
- package/src/__tests__/skinned-shadow-caster.test.ts +11 -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 -38
- 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/assembly/device-feature-admission.ts +73 -0
- package/src/assembly/directional-shadow-inspection.ts +122 -0
- package/src/assembly/factory.ts +877 -286
- 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 +81 -7
- package/src/components/reflection-probe.ts +49 -0
- package/src/environment/frame.ts +6 -24
- package/src/environment/lifecycle.ts +12 -0
- package/src/errors/render.ts +286 -142
- 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/hdrp-buffers.ts +165 -59
- package/src/ibl/IblPipelineCache.ts +11 -0
- package/src/ibl/kernel-cache.ts +88 -0
- package/src/index.ts +148 -0
- package/src/inspection-types.ts +56 -0
- package/src/instances-derived-bounds.ts +171 -0
- package/src/light-buffer-layout.ts +20 -5
- package/src/mesh-material-bindings.ts +132 -0
- package/src/pbr-pipeline.ts +106 -17
- package/src/pipeline/standard-forward-lane.ts +46 -16
- 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 +122 -193
- package/src/pipeline/standard-post.ts +26 -7
- package/src/pipeline/standard-profile.ts +17 -47
- 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 +367 -427
- package/src/record/frame-snapshot.ts +35 -27
- package/src/record/frame-targets.ts +17 -0
- package/src/record/frame.ts +261 -74
- 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 +21 -12
- package/src/record/main-pass-geometry.ts +120 -80
- package/src/record/main-pass-material.ts +95 -9
- package/src/record/main-pass-sprite-draws.ts +54 -25
- package/src/record/main-pass.ts +71 -15
- package/src/record/render-context.ts +72 -0
- package/src/record/shadow-pass.ts +17 -28
- package/src/record/skybox-post-pass.ts +20 -4
- package/src/record/typed-frame-graph.ts +893 -44
- 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 +76 -5
- package/src/render-graph-primitives.ts +9 -4
- package/src/render-pipeline.ts +117 -2
- package/src/render-system-extract.ts +557 -100
- package/src/render-system.ts +1095 -66
- package/src/renderer.ts +222 -0
- package/src/scene/render-scene.ts +115 -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/transmission/__tests__/standard-transmission.dawn.test.ts +59 -20
- package/src/typed-render-graph-primitives.ts +5 -3
- package/src/typed-shadow-passes.ts +46 -40
- package/src/volume/passes.ts +15 -9
- package/dist/chunk-4XINDLAY.mjs.map +0 -1
- package/dist/chunk-CDTWTHZR.mjs.map +0 -1
- package/dist/chunk-M2MP4ZOU.mjs.map +0 -1
- package/dist/chunk-TBQJOK2L.mjs.map +0 -1
|
@@ -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,
|
|
@@ -48,16 +40,20 @@ import {
|
|
|
48
40
|
} from '../typed-render-graph-primitives';
|
|
49
41
|
import { addTypedShadowPasses } from '../typed-shadow-passes';
|
|
50
42
|
import { addAuthoredVolumetricFogPasses } from '../volume/passes';
|
|
51
|
-
|
|
52
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';
|
|
53
53
|
import { addStandardPost } from './standard-post';
|
|
54
54
|
import {
|
|
55
|
-
CLUSTER_GRID_STRIDE_U32,
|
|
56
|
-
DEFAULT_CLUSTER_GRID,
|
|
57
55
|
DEFAULT_STANDARD_PROFILE,
|
|
58
|
-
|
|
59
|
-
MAX_LIGHTS,
|
|
60
|
-
resolveStandardLane,
|
|
56
|
+
STANDARD_LIGHT_COUNTS,
|
|
61
57
|
STANDARD_PIPELINE_ID,
|
|
62
58
|
type StandardProfile,
|
|
63
59
|
} from './standard-profile';
|
|
@@ -125,26 +121,11 @@ fn cs_cluster_membership(@builtin(global_invocation_id) global_id : vec3<u32>) {
|
|
|
125
121
|
}
|
|
126
122
|
}
|
|
127
123
|
`;
|
|
128
|
-
export class HdrpInstallError extends Error {
|
|
129
|
-
readonly code = 'hdrp-grid-invalid' as const;
|
|
130
|
-
readonly expected = 'clusterGrid.{x,y,z} each integer in [1, 64]';
|
|
131
|
-
readonly hint: string;
|
|
132
|
-
readonly detail: { readonly x: number; readonly y: number; readonly z: number };
|
|
133
|
-
|
|
134
|
-
constructor(x: number, y: number, z: number) {
|
|
135
|
-
const hint = `clusterGrid {x:${x}, y:${y}, z:${z}} is invalid; set {x,y,z} to positive integers in [1, 64]`;
|
|
136
|
-
super(`hdrp-grid-invalid: ${hint}`);
|
|
137
|
-
this.name = 'HdrpInstallError';
|
|
138
|
-
this.hint = hint;
|
|
139
|
-
this.detail = { x, y, z };
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
|
|
143
124
|
export function validateClusterGrid(grid: {
|
|
144
125
|
x: number;
|
|
145
126
|
y: number;
|
|
146
127
|
z: number;
|
|
147
|
-
}): Result<{ x: number; y: number; z: number },
|
|
128
|
+
}): Result<{ x: number; y: number; z: number }, StandardProfileInvalidError> {
|
|
148
129
|
const { x, y, z } = grid;
|
|
149
130
|
return Number.isInteger(x) &&
|
|
150
131
|
Number.isInteger(y) &&
|
|
@@ -156,7 +137,12 @@ export function validateClusterGrid(grid: {
|
|
|
156
137
|
z >= 1 &&
|
|
157
138
|
z <= 64
|
|
158
139
|
? ok({ x, y, z })
|
|
159
|
-
: 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
|
+
);
|
|
160
146
|
}
|
|
161
147
|
|
|
162
148
|
function target(
|
|
@@ -167,114 +153,20 @@ function target(
|
|
|
167
153
|
return createRenderPipelineTarget(graph, label, descriptor);
|
|
168
154
|
}
|
|
169
155
|
|
|
170
|
-
|
|
171
|
-
readonly lightData: GraphBuffer;
|
|
172
|
-
readonly clusterGrid: GraphBuffer;
|
|
173
|
-
readonly lightIndexList: GraphBuffer;
|
|
174
|
-
readonly clusterUniform: GraphBuffer;
|
|
175
|
-
readonly lightBounds: GraphBuffer;
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
function importBuffers(
|
|
179
|
-
graph: RenderGraphBuilder<RenderPipelineFrame>,
|
|
180
|
-
topology: RenderPipelineTopology,
|
|
181
|
-
): Result<HdrpGraphBuffers, RenderGraphError> {
|
|
182
|
-
const grid = topology.config?.clusterGrid ?? DEFAULT_CLUSTER_GRID;
|
|
183
|
-
const cells = grid.x * grid.y * grid.z;
|
|
184
|
-
const storage = topology.lane.storageBuffer;
|
|
185
|
-
const usage =
|
|
186
|
-
(storage ? GPU_BUFFER_USAGE_STORAGE : GPU_BUFFER_USAGE_UNIFORM) | GPU_BUFFER_USAGE_COPY_DST;
|
|
187
|
-
const resolve = (frame: RenderPipelineFrame): HdrpBuffers => {
|
|
188
|
-
const internal = frame as _InternalRenderPipelineContext;
|
|
189
|
-
const buffers = getOrCreateHdrpBuffers(internal.runtime, grid);
|
|
190
|
-
if (buffers === null) throw new Error('HDRP persistent buffer allocation failed');
|
|
191
|
-
return buffers;
|
|
192
|
-
};
|
|
193
|
-
const lightData = graph.importBuffer(
|
|
194
|
-
'hdrp-light-data',
|
|
195
|
-
{ size: (storage ? MAX_LIGHTS : 128) * 64, usage },
|
|
196
|
-
(frame) => resolve(frame).lightDataBuffer,
|
|
197
|
-
);
|
|
198
|
-
if (!lightData.ok) return lightData;
|
|
199
|
-
const clusterGrid = graph.importBuffer(
|
|
200
|
-
'hdrp-cluster-grid',
|
|
201
|
-
{ size: storage ? cells * CLUSTER_GRID_STRIDE_U32 * 4 : 32, usage },
|
|
202
|
-
(frame) => resolve(frame).clusterGridBuffer,
|
|
203
|
-
);
|
|
204
|
-
if (!clusterGrid.ok) return clusterGrid;
|
|
205
|
-
const lightIndexList = graph.importBuffer(
|
|
206
|
-
'hdrp-light-index-list',
|
|
207
|
-
{ size: storage ? LIGHT_INDEX_LIST_CAPACITY * 4 : 32, usage },
|
|
208
|
-
(frame) => resolve(frame).lightIndexListBuffer,
|
|
209
|
-
);
|
|
210
|
-
if (!lightIndexList.ok) return lightIndexList;
|
|
211
|
-
const clusterUniform = graph.importBuffer(
|
|
212
|
-
'hdrp-cluster-uniform',
|
|
213
|
-
{ size: 32, usage: GPU_BUFFER_USAGE_UNIFORM | GPU_BUFFER_USAGE_COPY_DST },
|
|
214
|
-
(frame) => resolve(frame).clusterUniformBuffer,
|
|
215
|
-
);
|
|
216
|
-
if (!clusterUniform.ok) return clusterUniform;
|
|
217
|
-
const lightBounds = graph.importBuffer(
|
|
218
|
-
'hdrp-light-bounds',
|
|
219
|
-
{ size: MAX_LIGHTS * 6 * 4, usage },
|
|
220
|
-
(frame) => resolve(frame).lightBoundsBuffer,
|
|
221
|
-
);
|
|
222
|
-
if (!lightBounds.ok) return lightBounds;
|
|
223
|
-
return ok({
|
|
224
|
-
lightData: lightData.value,
|
|
225
|
-
clusterGrid: clusterGrid.value,
|
|
226
|
-
lightIndexList: lightIndexList.value,
|
|
227
|
-
clusterUniform: clusterUniform.value,
|
|
228
|
-
lightBounds: lightBounds.value,
|
|
229
|
-
});
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
function addMembershipPass(
|
|
233
|
-
graph: RenderGraphBuilder<RenderPipelineFrame>,
|
|
234
|
-
topology: RenderPipelineTopology,
|
|
235
|
-
buffers: HdrpGraphBuffers,
|
|
236
|
-
): Result<void, RenderGraphError> {
|
|
237
|
-
if (!topology.lane.compute || !topology.lane.storageBuffer) return ok(undefined);
|
|
238
|
-
return graph.addComputePass('cluster-membership-producer', {
|
|
239
|
-
accesses: [
|
|
240
|
-
{ resource: buffers.clusterGrid, usage: 'storage-read' },
|
|
241
|
-
{ resource: buffers.clusterUniform, usage: 'uniform-read' },
|
|
242
|
-
{ resource: buffers.lightBounds, usage: 'storage-read' },
|
|
243
|
-
{ resource: buffers.lightIndexList, usage: 'storage-write' },
|
|
244
|
-
],
|
|
245
|
-
executeIf: (frame) => {
|
|
246
|
-
const internal = frame as _InternalRenderPipelineContext;
|
|
247
|
-
return (
|
|
248
|
-
internal.pipelineState.hdrpClusterMembershipPipeline !== null &&
|
|
249
|
-
internal.hdrpClusterMembershipBindGroup !== null
|
|
250
|
-
);
|
|
251
|
-
},
|
|
252
|
-
encode: ({ pass, frame }) => {
|
|
253
|
-
const internal = frame as _InternalRenderPipelineContext;
|
|
254
|
-
const pipeline = internal.pipelineState.hdrpClusterMembershipPipeline;
|
|
255
|
-
const bindings = internal.hdrpClusterMembershipBindGroup;
|
|
256
|
-
if (pipeline === null || bindings === null) return;
|
|
257
|
-
const grid = topology.config?.clusterGrid ?? DEFAULT_CLUSTER_GRID;
|
|
258
|
-
pass.setPipeline(pipeline);
|
|
259
|
-
pass.setBindGroup(0, bindings);
|
|
260
|
-
pass.dispatchWorkgroups(Math.ceil((grid.x * grid.y * grid.z) / 64));
|
|
261
|
-
},
|
|
262
|
-
});
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
function buildHdrp(
|
|
156
|
+
function buildStandardDeferredLane(
|
|
266
157
|
context: RenderPipelineBuildContext<RenderPipelineFrame>,
|
|
267
158
|
topology: RenderPipelineTopology,
|
|
159
|
+
lighting: StandardTopologyInputValue,
|
|
268
160
|
): ReturnType<RenderPipeline['build']> {
|
|
269
|
-
if (topology.lane.maxColorAttachments < 4) {
|
|
270
|
-
return err(new HdrpDeferredCapsInsufficientError(topology.lane.maxColorAttachments));
|
|
271
|
-
}
|
|
272
161
|
const graph = context.graph;
|
|
273
162
|
const surface = importRenderPipelineSurface(graph, topology);
|
|
274
163
|
if (!surface.ok) return surface;
|
|
275
|
-
const buffers =
|
|
164
|
+
const buffers = importStandardClusterBuffers(graph, lighting);
|
|
276
165
|
if (!buffers.ok) return buffers;
|
|
277
|
-
const membership =
|
|
166
|
+
const membership =
|
|
167
|
+
buffers.value === null
|
|
168
|
+
? ok(undefined)
|
|
169
|
+
: addStandardClusterMembershipPass(graph, lighting, buffers.value);
|
|
278
170
|
if (!membership.ok) return membership;
|
|
279
171
|
const shadows = addTypedShadowPasses(graph, topology);
|
|
280
172
|
if (!shadows.ok) return shadows;
|
|
@@ -305,9 +197,7 @@ function buildHdrp(
|
|
|
305
197
|
taa: topology.camera.antialias === 'taa',
|
|
306
198
|
motionBlur: topology.temporal?.motionBlur === true,
|
|
307
199
|
});
|
|
308
|
-
const temporalLane = topology.lane.compute
|
|
309
|
-
? (topology.standardProfile?.lighting ?? 'direct')
|
|
310
|
-
: 'cpu-webgl2';
|
|
200
|
+
const temporalLane = topology.lane.compute ? 'clustered' : 'cpu-webgl2';
|
|
311
201
|
const temporalAdmission = standardTemporalLaneAdmission({
|
|
312
202
|
lane: temporalLane,
|
|
313
203
|
demand: temporalDemand,
|
|
@@ -330,7 +220,11 @@ function buildHdrp(
|
|
|
330
220
|
}),
|
|
331
221
|
);
|
|
332
222
|
}
|
|
333
|
-
|
|
223
|
+
const gpuDriven = context.projectGpuDriven({
|
|
224
|
+
format: scene.value.format,
|
|
225
|
+
sampleCount: scene.value.sampleCount,
|
|
226
|
+
});
|
|
227
|
+
if (!gpuDriven.ok) return gpuDriven;
|
|
334
228
|
const gbuffer = addTypedScenePass(graph, {
|
|
335
229
|
name: 'g-buffer',
|
|
336
230
|
color: gbuffer0.value,
|
|
@@ -363,25 +257,13 @@ function buildHdrp(
|
|
|
363
257
|
{ resource: gbuffer1.value.view, usage: 'sampled-read' },
|
|
364
258
|
{ resource: gbuffer2.value.view, usage: 'sampled-read' },
|
|
365
259
|
{ resource: depth.value.view, usage: 'depth-stencil-read' },
|
|
366
|
-
|
|
367
|
-
resource: buffers.value.lightData,
|
|
368
|
-
usage: topology.lane.storageBuffer ? 'storage-read' : 'uniform-read',
|
|
369
|
-
},
|
|
370
|
-
{
|
|
371
|
-
resource: buffers.value.clusterGrid,
|
|
372
|
-
usage: topology.lane.storageBuffer ? 'storage-read' : 'uniform-read',
|
|
373
|
-
},
|
|
374
|
-
{
|
|
375
|
-
resource: buffers.value.lightIndexList,
|
|
376
|
-
usage: topology.lane.storageBuffer ? 'storage-read' : 'uniform-read',
|
|
377
|
-
},
|
|
378
|
-
{ resource: buffers.value.clusterUniform, usage: 'uniform-read' },
|
|
260
|
+
...(buffers.value === null ? [] : standardClusterReadAccesses(buffers.value)),
|
|
379
261
|
...(ssao === undefined
|
|
380
262
|
? []
|
|
381
263
|
: ([{ resource: ssao.view, usage: 'sampled-read' }] satisfies GraphAccess[])),
|
|
382
264
|
{ resource: scene.value.view, usage: 'color-attachment' },
|
|
383
265
|
];
|
|
384
|
-
const
|
|
266
|
+
const lightingPass = graph.addRasterPass('lighting', {
|
|
385
267
|
accesses: lightingAccesses,
|
|
386
268
|
colorAttachments: [
|
|
387
269
|
{
|
|
@@ -393,7 +275,7 @@ function buildHdrp(
|
|
|
393
275
|
],
|
|
394
276
|
encode: () => undefined,
|
|
395
277
|
});
|
|
396
|
-
if (!
|
|
278
|
+
if (!lightingPass.ok) return lightingPass;
|
|
397
279
|
|
|
398
280
|
const skybox = addTypedSkyboxPass(graph, scene.value);
|
|
399
281
|
if (!skybox.ok) return skybox;
|
|
@@ -403,21 +285,8 @@ function buildHdrp(
|
|
|
403
285
|
demand: transmissionDemand,
|
|
404
286
|
sourceSampleCount: scene.value.sampleCount,
|
|
405
287
|
}).active;
|
|
406
|
-
const forwardExtraAccesses: GraphAccess[] =
|
|
407
|
-
|
|
408
|
-
resource: buffers.value.lightData,
|
|
409
|
-
usage: topology.lane.storageBuffer ? 'storage-read' : 'uniform-read',
|
|
410
|
-
},
|
|
411
|
-
{
|
|
412
|
-
resource: buffers.value.clusterGrid,
|
|
413
|
-
usage: topology.lane.storageBuffer ? 'storage-read' : 'uniform-read',
|
|
414
|
-
},
|
|
415
|
-
{
|
|
416
|
-
resource: buffers.value.lightIndexList,
|
|
417
|
-
usage: topology.lane.storageBuffer ? 'storage-read' : 'uniform-read',
|
|
418
|
-
},
|
|
419
|
-
{ resource: buffers.value.clusterUniform, usage: 'uniform-read' },
|
|
420
|
-
];
|
|
288
|
+
const forwardExtraAccesses: GraphAccess[] =
|
|
289
|
+
buffers.value === null ? [] : [...standardClusterReadAccesses(buffers.value)];
|
|
421
290
|
|
|
422
291
|
const forward = addTypedScenePass(graph, {
|
|
423
292
|
name: 'forward',
|
|
@@ -430,14 +299,17 @@ function buildHdrp(
|
|
|
430
299
|
gbuffer0.value,
|
|
431
300
|
gbuffer1.value,
|
|
432
301
|
gbuffer2.value,
|
|
433
|
-
shadows.value.directional,
|
|
302
|
+
...(shadows.value.directional === undefined ? [] : [shadows.value.directional]),
|
|
434
303
|
shadows.value.spot,
|
|
435
304
|
...(shadows.value.point === undefined ? [] : [shadows.value.point]),
|
|
436
305
|
...(ssao === undefined ? [] : [ssao]),
|
|
437
306
|
],
|
|
438
|
-
|
|
307
|
+
...(shadows.value.directional === undefined
|
|
308
|
+
? {}
|
|
309
|
+
: { directionalShadow: shadows.value.directional }),
|
|
439
310
|
spotShadow: shadows.value.spot,
|
|
440
311
|
...(ssao === undefined ? {} : { ssao }),
|
|
312
|
+
...(gpuDriven.value === undefined ? {} : { gpuDriven: gpuDriven.value }),
|
|
441
313
|
passKind: 'forward',
|
|
442
314
|
...(transmissionActive ? { recordMode: 'opaque' as const } : {}),
|
|
443
315
|
extraAccesses: forwardExtraAccesses,
|
|
@@ -472,7 +344,7 @@ function buildHdrp(
|
|
|
472
344
|
gbuffer0.value,
|
|
473
345
|
gbuffer1.value,
|
|
474
346
|
gbuffer2.value,
|
|
475
|
-
shadows.value.directional,
|
|
347
|
+
...(shadows.value.directional === undefined ? [] : [shadows.value.directional]),
|
|
476
348
|
shadows.value.spot,
|
|
477
349
|
...(shadows.value.point === undefined ? [] : [shadows.value.point]),
|
|
478
350
|
...(ssao === undefined ? [] : [ssao]),
|
|
@@ -501,7 +373,7 @@ function buildHdrp(
|
|
|
501
373
|
gbuffer0.value,
|
|
502
374
|
gbuffer1.value,
|
|
503
375
|
gbuffer2.value,
|
|
504
|
-
shadows.value.directional,
|
|
376
|
+
...(shadows.value.directional === undefined ? [] : [shadows.value.directional]),
|
|
505
377
|
shadows.value.spot,
|
|
506
378
|
...(shadows.value.point === undefined ? [] : [shadows.value.point]),
|
|
507
379
|
...(ssao === undefined ? [] : [ssao]),
|
|
@@ -529,7 +401,7 @@ function buildHdrp(
|
|
|
529
401
|
topology,
|
|
530
402
|
scene.value,
|
|
531
403
|
depthSample.value,
|
|
532
|
-
shadows.value.directional
|
|
404
|
+
shadows.value.directional?.view,
|
|
533
405
|
shadows.value.spot.view,
|
|
534
406
|
);
|
|
535
407
|
if (!volume.ok) return volume;
|
|
@@ -556,8 +428,7 @@ function buildHdrp(
|
|
|
556
428
|
if (!features.ok) return features;
|
|
557
429
|
const observation = addTypedFrameObservationPass(graph, scene.value, 'forgeax::standard');
|
|
558
430
|
if (!observation.ok) return observation;
|
|
559
|
-
|
|
560
|
-
return addStandardPost(
|
|
431
|
+
const post = addStandardPost(
|
|
561
432
|
context,
|
|
562
433
|
topology,
|
|
563
434
|
scene.value,
|
|
@@ -565,13 +436,19 @@ function buildHdrp(
|
|
|
565
436
|
surface.value,
|
|
566
437
|
temporal.value?.temporal,
|
|
567
438
|
);
|
|
439
|
+
if (!post.ok) return post;
|
|
440
|
+
const cubeCaptures = context.contributeCubeCaptures?.();
|
|
441
|
+
if (cubeCaptures !== undefined && !cubeCaptures.ok) return cubeCaptures;
|
|
442
|
+
return ok(undefined);
|
|
568
443
|
}
|
|
569
|
-
const buildStandardClusteredLane = buildHdrp;
|
|
570
|
-
|
|
571
444
|
export interface StandardPipeline extends RenderPipeline {
|
|
572
445
|
readonly identity: typeof STANDARD_PIPELINE_ID;
|
|
573
446
|
}
|
|
574
447
|
|
|
448
|
+
export function standardProfileSupportsReflectionProbes(_profile: StandardProfile): boolean {
|
|
449
|
+
return true;
|
|
450
|
+
}
|
|
451
|
+
|
|
575
452
|
/** Standard graph inputs are derived once from the immutable frame plan. */
|
|
576
453
|
export type StandardFramePlan = FramePlan;
|
|
577
454
|
|
|
@@ -579,6 +456,43 @@ function profileFor(topology: RenderPipelineTopology): StandardProfile {
|
|
|
579
456
|
return topology.standardProfile ?? DEFAULT_STANDARD_PROFILE;
|
|
580
457
|
}
|
|
581
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
|
+
|
|
582
496
|
function standardTopology(
|
|
583
497
|
topology: RenderPipelineTopology,
|
|
584
498
|
profile: StandardProfile,
|
|
@@ -596,26 +510,41 @@ function standardTopology(
|
|
|
596
510
|
}
|
|
597
511
|
|
|
598
512
|
/**
|
|
599
|
-
* The sole built-in pipeline entry point.
|
|
600
|
-
*
|
|
601
|
-
*
|
|
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.
|
|
602
516
|
*/
|
|
603
517
|
function buildStandard(
|
|
604
518
|
context: RenderPipelineBuildContext<RenderPipelineFrame>,
|
|
605
519
|
topology: RenderPipelineTopology,
|
|
606
520
|
): ReturnType<RenderPipeline['build']> {
|
|
607
521
|
const profile = profileFor(topology);
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
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
|
+
}
|
|
612
537
|
const effective = standardTopology(topology, profile);
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
//
|
|
616
|
-
|
|
617
|
-
if (
|
|
618
|
-
|
|
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);
|
|
619
548
|
}
|
|
620
549
|
|
|
621
550
|
export const standardPipeline: StandardPipeline = Object.freeze({
|
|
@@ -11,7 +11,11 @@ import type {
|
|
|
11
11
|
RenderPipelineFrame,
|
|
12
12
|
RenderPipelineTopology,
|
|
13
13
|
} from '../render-pipeline';
|
|
14
|
-
import {
|
|
14
|
+
import {
|
|
15
|
+
createRenderPipelineTarget,
|
|
16
|
+
type RenderPipelineTarget,
|
|
17
|
+
resolveOutputDither,
|
|
18
|
+
} from '../render-pipeline';
|
|
15
19
|
import {
|
|
16
20
|
addTypedBloomPasses,
|
|
17
21
|
addTypedCompositePostEffects,
|
|
@@ -134,7 +138,7 @@ function missingTemporalContributor(
|
|
|
134
138
|
return new SceneDataUnavailableError({
|
|
135
139
|
featureIdentity: 'forgeax::standard',
|
|
136
140
|
schema: 'forgeax::scene-data::temporal-v1',
|
|
137
|
-
lane: topology.lane.compute ?
|
|
141
|
+
lane: topology.lane.compute ? 'clustered' : 'cpu-webgl2',
|
|
138
142
|
reason: 'producer-missing',
|
|
139
143
|
missingContributorIds: [contributorId],
|
|
140
144
|
omittedMissingContributorCount: 0,
|
|
@@ -165,9 +169,13 @@ export function addStandardPost(
|
|
|
165
169
|
// left clear and the following Output Transform presents a black frame.
|
|
166
170
|
const bloomActive = hdr && topology.camera.bloom === 'on' && topology.camera.tonemap !== 'none';
|
|
167
171
|
const fxaa = !clearOnly && topology.camera.antialias === 'fxaa';
|
|
168
|
-
|
|
169
|
-
|
|
172
|
+
// All non-clear Standard frames use the graph-owned float scene target and
|
|
173
|
+
// the shared Output Transform, even when AA is disabled or the backend has
|
|
174
|
+
// no storage buffers. This keeps the final dither at one owner-level
|
|
175
|
+
// surface boundary instead of making no-AA/WebGL2 a silent bypass.
|
|
176
|
+
const linearLdr = !clearOnly && !hdr;
|
|
170
177
|
const rawOnly = !clearOnly && topology.surface.profile?.kind === 'raw-only';
|
|
178
|
+
const outputDither = resolveOutputDither(topology.config);
|
|
171
179
|
const motionBlur = !clearOnly && topology.temporal?.motionBlur === true;
|
|
172
180
|
const postEffects = clearOnly ? [] : (topology.config?.postEffects ?? []);
|
|
173
181
|
const rawOnlyPostInput =
|
|
@@ -312,7 +320,11 @@ export function addStandardPost(
|
|
|
312
320
|
domain: 'display-encoded',
|
|
313
321
|
});
|
|
314
322
|
if (!output.ok) return output;
|
|
315
|
-
|
|
323
|
+
// FXAA samples this display-encoded intermediate; leave dither to the
|
|
324
|
+
// final FXAA writer so the same pixel is not dithered twice.
|
|
325
|
+
const outputTransform = addTypedOutputTransformPass(context.graph, postInput, output.value, {
|
|
326
|
+
dither: false,
|
|
327
|
+
});
|
|
316
328
|
if (!outputTransform.ok) return outputTransform;
|
|
317
329
|
const aa = addTypedFullscreenPass(context.graph, {
|
|
318
330
|
name: 'fxaa',
|
|
@@ -326,13 +338,20 @@ export function addStandardPost(
|
|
|
326
338
|
context.graph,
|
|
327
339
|
postInput,
|
|
328
340
|
rawOnlyPostInput.value,
|
|
341
|
+
{
|
|
342
|
+
dither: outputDither && postEffects.length === 0,
|
|
343
|
+
},
|
|
329
344
|
);
|
|
330
345
|
if (!transformed.ok) return transformed;
|
|
331
346
|
} else if (rawOnly || linearLdr) {
|
|
332
|
-
const transformed = addTypedOutputTransformPass(context.graph, postInput, finalPresent
|
|
347
|
+
const transformed = addTypedOutputTransformPass(context.graph, postInput, finalPresent, {
|
|
348
|
+
dither: outputDither,
|
|
349
|
+
});
|
|
333
350
|
if (!transformed.ok) return transformed;
|
|
334
351
|
} else {
|
|
335
|
-
const outputTransform = addTypedOutputTransformPass(context.graph, postInput, finalPresent
|
|
352
|
+
const outputTransform = addTypedOutputTransformPass(context.graph, postInput, finalPresent, {
|
|
353
|
+
dither: outputDither,
|
|
354
|
+
});
|
|
336
355
|
if (!outputTransform.ok) return outputTransform;
|
|
337
356
|
}
|
|
338
357
|
}
|
|
@@ -1,25 +1,22 @@
|
|
|
1
1
|
export const STANDARD_PIPELINE_ID = 'forgeax::standard' as const;
|
|
2
2
|
export const STANDARD_LIGHT_COUNTS = [1, 32, 256] as const;
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
3
|
+
export {
|
|
4
|
+
CLUSTER_GRID_STRIDE_U32,
|
|
5
|
+
DEFAULT_CLUSTER_GRID,
|
|
6
|
+
LIGHT_INDEX_LIST_CAPACITY,
|
|
7
|
+
MAX_LIGHTS,
|
|
8
|
+
} from './standard-lighting/layout';
|
|
8
9
|
|
|
9
10
|
export type StandardLightCount = (typeof STANDARD_LIGHT_COUNTS)[number];
|
|
10
|
-
export type StandardLightingLane = 'direct' | 'clustered';
|
|
11
|
-
export type StandardFallbackLane = 'native' | 'cpu-webgl2';
|
|
12
11
|
export type StandardShadowMode = 'off' | 'hard' | 'filtered';
|
|
13
|
-
export type
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
|
18
|
-
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
| 'reinhard-extended';
|
|
22
|
-
export type StandardAntialias = 'none' | 'fxaa' | 'msaa';
|
|
12
|
+
export type StandardVolumetricFogQuality = 'low' | 'high';
|
|
13
|
+
|
|
14
|
+
export interface StandardVolumetricFogProfile {
|
|
15
|
+
readonly quality: StandardVolumetricFogQuality;
|
|
16
|
+
readonly depth: 48 | 64;
|
|
17
|
+
readonly tileSize: 4 | 16;
|
|
18
|
+
}
|
|
19
|
+
|
|
23
20
|
export const STANDARD_POST_STAGE_NAMES = [
|
|
24
21
|
'transparent-blend',
|
|
25
22
|
'bloom',
|
|
@@ -29,45 +26,28 @@ export const STANDARD_POST_STAGE_NAMES = [
|
|
|
29
26
|
'present',
|
|
30
27
|
] as const;
|
|
31
28
|
export type StandardPostStage = (typeof STANDARD_POST_STAGE_NAMES)[number];
|
|
32
|
-
export type StandardVolumetricFogQuality = 'low' | 'high';
|
|
33
|
-
|
|
34
|
-
export interface StandardVolumetricFogProfile {
|
|
35
|
-
readonly quality: StandardVolumetricFogQuality;
|
|
36
|
-
readonly depth: 48 | 64;
|
|
37
|
-
readonly tileSize: 4 | 16;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
29
|
export interface StandardProfile {
|
|
41
30
|
readonly pipelineId: typeof STANDARD_PIPELINE_ID;
|
|
42
31
|
readonly lightCount: StandardLightCount;
|
|
43
|
-
|
|
32
|
+
/** Graph topology selector; all local lights use the shared Cluster path. */
|
|
33
|
+
readonly renderPath: 'forward' | 'deferred';
|
|
44
34
|
readonly shadows: StandardShadowMode;
|
|
45
35
|
readonly pbr: boolean;
|
|
46
36
|
readonly ibl: boolean;
|
|
47
37
|
readonly ssao: boolean;
|
|
48
|
-
readonly bloom: boolean;
|
|
49
|
-
readonly tone: StandardTone;
|
|
50
|
-
readonly antialias: StandardAntialias;
|
|
51
|
-
readonly sky: boolean;
|
|
52
38
|
/** Renderer-owned 1080p volume profile; tile width/height remain surface-derived. */
|
|
53
39
|
readonly volumetricFog?: StandardVolumetricFogProfile | undefined;
|
|
54
|
-
readonly fallback: StandardFallbackLane;
|
|
55
40
|
readonly postStages: typeof STANDARD_POST_STAGE_NAMES;
|
|
56
41
|
}
|
|
57
42
|
|
|
58
43
|
export const DEFAULT_STANDARD_PROFILE: StandardProfile = Object.freeze({
|
|
59
44
|
pipelineId: STANDARD_PIPELINE_ID,
|
|
60
45
|
lightCount: 32,
|
|
61
|
-
|
|
46
|
+
renderPath: 'forward',
|
|
62
47
|
shadows: 'filtered',
|
|
63
48
|
pbr: true,
|
|
64
49
|
ibl: true,
|
|
65
50
|
ssao: false,
|
|
66
|
-
bloom: true,
|
|
67
|
-
tone: 'aces-filmic',
|
|
68
|
-
antialias: 'fxaa',
|
|
69
|
-
sky: true,
|
|
70
|
-
fallback: 'native',
|
|
71
51
|
postStages: STANDARD_POST_STAGE_NAMES,
|
|
72
52
|
});
|
|
73
53
|
|
|
@@ -76,13 +56,3 @@ export function resolveVolumetricFogProfile(
|
|
|
76
56
|
): StandardVolumetricFogProfile {
|
|
77
57
|
return profile.volumetricFog ?? { quality: 'high', depth: 64, tileSize: 4 };
|
|
78
58
|
}
|
|
79
|
-
|
|
80
|
-
export type StandardLane = StandardLightingLane | 'cpu-webgl2';
|
|
81
|
-
|
|
82
|
-
export function resolveStandardLane(
|
|
83
|
-
profile: Pick<StandardProfile, 'lighting'>,
|
|
84
|
-
capabilities: { readonly compute: boolean; readonly storageBuffer: boolean },
|
|
85
|
-
): StandardLane {
|
|
86
|
-
if (!capabilities.compute || !capabilities.storageBuffer) return 'cpu-webgl2';
|
|
87
|
-
return profile.lighting;
|
|
88
|
-
}
|