@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
|
@@ -34,6 +34,13 @@ import {
|
|
|
34
34
|
addTypedSkyboxPass,
|
|
35
35
|
} from '../typed-render-graph-primitives';
|
|
36
36
|
import { addTypedShadowPasses } from '../typed-shadow-passes';
|
|
37
|
+
import { addAuthoredVolumetricFogPasses } from '../volume/passes';
|
|
38
|
+
import {
|
|
39
|
+
addStandardClusterMembershipPass,
|
|
40
|
+
importStandardClusterBuffers,
|
|
41
|
+
standardClusterReadAccesses,
|
|
42
|
+
} from './standard-lighting/graph';
|
|
43
|
+
import type { StandardTopologyInputValue } from './standard-lighting/topology';
|
|
37
44
|
import { addStandardPost } from './standard-post';
|
|
38
45
|
|
|
39
46
|
function target(
|
|
@@ -47,6 +54,7 @@ function target(
|
|
|
47
54
|
function buildUrp(
|
|
48
55
|
context: RenderPipelineBuildContext<RenderPipelineFrame>,
|
|
49
56
|
topology: RenderPipelineTopology,
|
|
57
|
+
lighting: StandardTopologyInputValue,
|
|
50
58
|
): ReturnType<RenderPipeline['build']> {
|
|
51
59
|
const graph = context.graph;
|
|
52
60
|
const surface = importRenderPipelineSurface(graph, topology);
|
|
@@ -59,16 +67,14 @@ function buildUrp(
|
|
|
59
67
|
const fxaa = !clearOnly && topology.camera.antialias === 'fxaa';
|
|
60
68
|
const taa = !clearOnly && topology.camera.antialias === 'taa';
|
|
61
69
|
const rawOnly = !clearOnly && topology.surface.profile?.kind === 'raw-only';
|
|
62
|
-
//
|
|
63
|
-
//
|
|
64
|
-
//
|
|
65
|
-
// remain float even when tone mapping is disabled. This prevents an
|
|
66
|
-
// eight-bit quantization before the OETF/display-encoded boundary.
|
|
70
|
+
// Every non-clear lane keeps a linear float scene target until the shared
|
|
71
|
+
// Output Transform. This includes no-AA and the no-storage fallback: the
|
|
72
|
+
// final dither and display encoding must have one graph-owned boundary.
|
|
67
73
|
// MSAA resolves into a separate linear target before presentation. Treat
|
|
68
74
|
// that resolved target like linear LDR so the shared Output Transform owns
|
|
69
75
|
// its write into the surface storage view; without this, the resolve is
|
|
70
76
|
// never presented and MSAA is indistinguishable from the no-AA path.
|
|
71
|
-
const linearLdr = !clearOnly &&
|
|
77
|
+
const linearLdr = !clearOnly && !hdr;
|
|
72
78
|
const temporalDemand = aggregateTemporalDemand({
|
|
73
79
|
taa,
|
|
74
80
|
motionBlur: !clearOnly && topology.temporal?.motionBlur === true,
|
|
@@ -87,7 +93,14 @@ function buildUrp(
|
|
|
87
93
|
if (!depth.ok) return depth;
|
|
88
94
|
|
|
89
95
|
const sceneResolved = clearOnly
|
|
90
|
-
?
|
|
96
|
+
? surface.value.display === undefined
|
|
97
|
+
? target(graph, 'scene-color', {
|
|
98
|
+
format: topology.surface.storageFormat,
|
|
99
|
+
size: 'surface',
|
|
100
|
+
sampleCount: 1,
|
|
101
|
+
domain: 'display-encoded',
|
|
102
|
+
})
|
|
103
|
+
: ok(surface.value.display)
|
|
91
104
|
: hdr || fxaa || linearLdr || msaa || rawOnly || needsTemporalIntermediate
|
|
92
105
|
? target(graph, 'scene-color', {
|
|
93
106
|
format: sceneFormat,
|
|
@@ -125,6 +138,16 @@ function buildUrp(
|
|
|
125
138
|
const shadows = addTypedShadowPasses(graph, topology);
|
|
126
139
|
if (!shadows.ok) return shadows;
|
|
127
140
|
|
|
141
|
+
const clusterBuffers = clearOnly ? ok(null) : importStandardClusterBuffers(graph, lighting);
|
|
142
|
+
if (!clusterBuffers.ok) return clusterBuffers;
|
|
143
|
+
const clusterMembership =
|
|
144
|
+
clusterBuffers.value === null
|
|
145
|
+
? ok(undefined)
|
|
146
|
+
: addStandardClusterMembershipPass(graph, lighting, clusterBuffers.value);
|
|
147
|
+
if (!clusterMembership.ok) return clusterMembership;
|
|
148
|
+
const clusterReads =
|
|
149
|
+
clusterBuffers.value === null ? [] : standardClusterReadAccesses(clusterBuffers.value);
|
|
150
|
+
|
|
128
151
|
const skybox = addTypedSkyboxPass(graph, scene.value);
|
|
129
152
|
if (!skybox.ok) return skybox;
|
|
130
153
|
const gpuDriven = context.projectGpuDriven({
|
|
@@ -143,22 +166,23 @@ function buildUrp(
|
|
|
143
166
|
depth: depth.value,
|
|
144
167
|
...(msaa ? { resolve: sceneResolved.value } : {}),
|
|
145
168
|
sampled: [
|
|
146
|
-
shadows.value.directional,
|
|
169
|
+
...(shadows.value.directional === undefined ? [] : [shadows.value.directional]),
|
|
147
170
|
shadows.value.spot,
|
|
148
171
|
...(shadows.value.point === undefined ? [] : [shadows.value.point]),
|
|
149
172
|
],
|
|
150
|
-
|
|
173
|
+
...(shadows.value.directional === undefined
|
|
174
|
+
? {}
|
|
175
|
+
: { directionalShadow: shadows.value.directional }),
|
|
151
176
|
spotShadow: shadows.value.spot,
|
|
152
177
|
selector: { LightMode: ['Forward'] },
|
|
153
178
|
colorLoadOp: 'load',
|
|
179
|
+
extraAccesses: clusterReads,
|
|
154
180
|
...(transmissionActive ? { recordMode: 'opaque' as const } : {}),
|
|
155
181
|
...(gpuDriven.value === undefined ? {} : { gpuDriven: gpuDriven.value }),
|
|
156
182
|
});
|
|
157
183
|
if (!main.ok) return main;
|
|
158
184
|
|
|
159
|
-
const temporalLane = topology.lane.compute
|
|
160
|
-
? (topology.standardProfile?.lighting ?? 'direct')
|
|
161
|
-
: 'cpu-webgl2';
|
|
185
|
+
const temporalLane = topology.lane.compute ? 'clustered' : 'cpu-webgl2';
|
|
162
186
|
const temporalAdmission = standardTemporalLaneAdmission({
|
|
163
187
|
lane: temporalLane,
|
|
164
188
|
demand: temporalDemand,
|
|
@@ -190,6 +214,7 @@ function buildUrp(
|
|
|
190
214
|
const producer = addStandardSceneDataPass(graph, temporal.value.temporal, depth.value);
|
|
191
215
|
if (!producer.ok) return producer;
|
|
192
216
|
}
|
|
217
|
+
|
|
193
218
|
const transmission = addTransmissionBackdropPasses({
|
|
194
219
|
graph,
|
|
195
220
|
source: sceneResolved.value,
|
|
@@ -206,7 +231,7 @@ function buildUrp(
|
|
|
206
231
|
depth: depth.value,
|
|
207
232
|
...(msaa ? { resolve: sceneResolved.value } : {}),
|
|
208
233
|
sampled: [
|
|
209
|
-
shadows.value.directional,
|
|
234
|
+
...(shadows.value.directional === undefined ? [] : [shadows.value.directional]),
|
|
210
235
|
shadows.value.spot,
|
|
211
236
|
...(shadows.value.point === undefined ? [] : [shadows.value.point]),
|
|
212
237
|
],
|
|
@@ -216,6 +241,7 @@ function buildUrp(
|
|
|
216
241
|
colorLoadOp: 'load',
|
|
217
242
|
depthLoadOp: 'load',
|
|
218
243
|
recordMode: 'transmission',
|
|
244
|
+
extraAccesses: clusterReads,
|
|
219
245
|
// Inject the complete backdrop view so the Standard shader can select
|
|
220
246
|
// the producer's optional roughness mip level. mipViews[0] is only the
|
|
221
247
|
// copy destination view and intentionally exposes one level.
|
|
@@ -229,7 +255,7 @@ function buildUrp(
|
|
|
229
255
|
depth: depth.value,
|
|
230
256
|
...(msaa ? { resolve: sceneResolved.value } : {}),
|
|
231
257
|
sampled: [
|
|
232
|
-
shadows.value.directional,
|
|
258
|
+
...(shadows.value.directional === undefined ? [] : [shadows.value.directional]),
|
|
233
259
|
shadows.value.spot,
|
|
234
260
|
...(shadows.value.point === undefined ? [] : [shadows.value.point]),
|
|
235
261
|
],
|
|
@@ -239,14 +265,34 @@ function buildUrp(
|
|
|
239
265
|
colorLoadOp: 'load',
|
|
240
266
|
depthLoadOp: 'load',
|
|
241
267
|
recordMode: 'transparent',
|
|
268
|
+
extraAccesses: clusterReads,
|
|
242
269
|
});
|
|
243
270
|
if (!transparentPass.ok) return transparentPass;
|
|
244
271
|
const temporal = addTransmissionBackdropTemporalPass(graph, sceneResolved.value);
|
|
245
272
|
if (!temporal.ok) return temporal;
|
|
246
273
|
}
|
|
247
274
|
|
|
275
|
+
if (topology.volumetricFog?.enabled === true) {
|
|
276
|
+
const depthSample = graph.view(depth.value.texture, {
|
|
277
|
+
label: 'scene-depth.sample',
|
|
278
|
+
dimension: '2d',
|
|
279
|
+
aspect: 'depth-only',
|
|
280
|
+
});
|
|
281
|
+
if (!depthSample.ok) return depthSample;
|
|
282
|
+
const volume = addAuthoredVolumetricFogPasses(
|
|
283
|
+
graph,
|
|
284
|
+
topology,
|
|
285
|
+
sceneResolved.value,
|
|
286
|
+
depthSample.value,
|
|
287
|
+
shadows.value.directional?.view,
|
|
288
|
+
shadows.value.spot.view,
|
|
289
|
+
);
|
|
290
|
+
if (!volume.ok) return volume;
|
|
291
|
+
}
|
|
292
|
+
|
|
248
293
|
const features = context.contributeFeatures([
|
|
249
294
|
{
|
|
295
|
+
name: 'linear-hdr',
|
|
250
296
|
kind: 'scene-color',
|
|
251
297
|
texture: scene.value.texture,
|
|
252
298
|
view: scene.value.view,
|
|
@@ -273,7 +319,7 @@ function buildUrp(
|
|
|
273
319
|
if (!observation.ok) return observation;
|
|
274
320
|
}
|
|
275
321
|
|
|
276
|
-
|
|
322
|
+
const post = addStandardPost(
|
|
277
323
|
context,
|
|
278
324
|
topology,
|
|
279
325
|
sceneResolved.value,
|
|
@@ -281,6 +327,10 @@ function buildUrp(
|
|
|
281
327
|
surface.value,
|
|
282
328
|
temporal.value?.temporal,
|
|
283
329
|
);
|
|
330
|
+
if (!post.ok) return post;
|
|
331
|
+
const cubeCaptures = context.contributeCubeCaptures?.();
|
|
332
|
+
if (cubeCaptures !== undefined && !cubeCaptures.ok) return cubeCaptures;
|
|
333
|
+
return ok(undefined);
|
|
284
334
|
}
|
|
285
335
|
|
|
286
336
|
export const buildStandardForwardLane = buildUrp;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { ClusterBinError } from '../../cluster-binner';
|
|
2
|
+
import { StandardClusterIndexOverflowError } from '../../errors/render';
|
|
3
|
+
|
|
4
|
+
export function fromClusterBinError(error: ClusterBinError): StandardClusterIndexOverflowError {
|
|
5
|
+
return new StandardClusterIndexOverflowError(error.detail.actual, error.detail.capacity);
|
|
6
|
+
}
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
GraphAccess,
|
|
3
|
+
GraphBuffer,
|
|
4
|
+
RenderGraphBuilder,
|
|
5
|
+
RenderGraphError,
|
|
6
|
+
} from '@forgeax/engine-render-graph';
|
|
7
|
+
import { ok, type Result } from '@forgeax/engine-types';
|
|
8
|
+
import {
|
|
9
|
+
GPU_BUFFER_USAGE_COPY_DST,
|
|
10
|
+
GPU_BUFFER_USAGE_STORAGE,
|
|
11
|
+
GPU_BUFFER_USAGE_UNIFORM,
|
|
12
|
+
} from '../../gpu-usage';
|
|
13
|
+
import { getOrCreateHdrpBuffers, type HdrpBuffers } from '../../hdrp-buffers';
|
|
14
|
+
import type { _InternalRenderPipelineContext } from '../../record/render-context';
|
|
15
|
+
import type { RenderPipelineFrame } from '../../render-pipeline';
|
|
16
|
+
import type { StandardTopologyInputValue } from './topology';
|
|
17
|
+
|
|
18
|
+
/** Graph resources projected from one Standard lighting topology input. */
|
|
19
|
+
export interface StandardClusterGraphBuffers {
|
|
20
|
+
readonly lightData: GraphBuffer;
|
|
21
|
+
readonly clusterGrid: GraphBuffer;
|
|
22
|
+
readonly lightIndexList: GraphBuffer;
|
|
23
|
+
readonly clusterUniform: GraphBuffer;
|
|
24
|
+
readonly lightBounds: GraphBuffer;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/** Stable graph-time projection; never retain a frame's typed-array payload. */
|
|
28
|
+
interface StandardClusterGraphDescriptor {
|
|
29
|
+
readonly grid: { readonly x: number; readonly y: number; readonly z: number };
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function projectDescriptor(input: StandardTopologyInputValue): StandardClusterGraphDescriptor {
|
|
33
|
+
const { x, y, z } = input.prepared.layout.grid;
|
|
34
|
+
return { grid: { x, y, z } };
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function resolveBuffers(
|
|
38
|
+
frame: RenderPipelineFrame,
|
|
39
|
+
descriptor: StandardClusterGraphDescriptor,
|
|
40
|
+
): HdrpBuffers {
|
|
41
|
+
const internal = frame as _InternalRenderPipelineContext;
|
|
42
|
+
const buffers = getOrCreateHdrpBuffers(internal.runtime, descriptor.grid);
|
|
43
|
+
if (buffers === null) throw new Error('Standard persistent buffer allocation failed');
|
|
44
|
+
return buffers;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/** Resolve membership execution from the frame's current prepared payload. */
|
|
48
|
+
export function shouldExecuteStandardClusterMembershipPass(frame: RenderPipelineFrame): boolean {
|
|
49
|
+
const standardLighting = (frame as _InternalRenderPipelineContext).standardLighting;
|
|
50
|
+
return (
|
|
51
|
+
standardLighting?.kind === 'clustered' &&
|
|
52
|
+
standardLighting.transport.kind === 'compute-storage' &&
|
|
53
|
+
standardLighting.prepared.local.length > 0
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/** Import the shared Standard Cluster buffers with sizes derived from layout. */
|
|
58
|
+
export function importStandardClusterBuffers(
|
|
59
|
+
graph: RenderGraphBuilder<RenderPipelineFrame>,
|
|
60
|
+
input: StandardTopologyInputValue,
|
|
61
|
+
): Result<StandardClusterGraphBuffers | null, RenderGraphError> {
|
|
62
|
+
if (input.kind === 'no-local-lights') return ok(null);
|
|
63
|
+
const layout = input.prepared.layout;
|
|
64
|
+
const descriptor = projectDescriptor(input);
|
|
65
|
+
const usage = GPU_BUFFER_USAGE_STORAGE | GPU_BUFFER_USAGE_COPY_DST;
|
|
66
|
+
const lightData = graph.importBuffer(
|
|
67
|
+
'hdrp-light-data',
|
|
68
|
+
{ size: layout.lightDataSlotCount * 64, usage },
|
|
69
|
+
(frame) => resolveBuffers(frame, descriptor).lightDataBuffer,
|
|
70
|
+
);
|
|
71
|
+
if (!lightData.ok) return lightData;
|
|
72
|
+
const clusterGrid = graph.importBuffer(
|
|
73
|
+
'hdrp-cluster-grid',
|
|
74
|
+
{ size: layout.clusterGridU32Length * 4, usage },
|
|
75
|
+
(frame) => resolveBuffers(frame, descriptor).clusterGridBuffer,
|
|
76
|
+
);
|
|
77
|
+
if (!clusterGrid.ok) return clusterGrid;
|
|
78
|
+
const lightIndexList = graph.importBuffer(
|
|
79
|
+
'hdrp-light-index-list',
|
|
80
|
+
{ size: layout.lightIndexListCapacity * 4, usage },
|
|
81
|
+
(frame) => resolveBuffers(frame, descriptor).lightIndexListBuffer,
|
|
82
|
+
);
|
|
83
|
+
if (!lightIndexList.ok) return lightIndexList;
|
|
84
|
+
const clusterUniform = graph.importBuffer(
|
|
85
|
+
'hdrp-cluster-uniform',
|
|
86
|
+
{ size: 32, usage: GPU_BUFFER_USAGE_UNIFORM | GPU_BUFFER_USAGE_COPY_DST },
|
|
87
|
+
(frame) => resolveBuffers(frame, descriptor).clusterUniformBuffer,
|
|
88
|
+
);
|
|
89
|
+
if (!clusterUniform.ok) return clusterUniform;
|
|
90
|
+
const lightBounds = graph.importBuffer(
|
|
91
|
+
'hdrp-light-bounds',
|
|
92
|
+
{ size: layout.lightBoundsInt32Length * 4, usage },
|
|
93
|
+
(frame) => resolveBuffers(frame, descriptor).lightBoundsBuffer,
|
|
94
|
+
);
|
|
95
|
+
if (!lightBounds.ok) return lightBounds;
|
|
96
|
+
return ok({
|
|
97
|
+
lightData: lightData.value,
|
|
98
|
+
clusterGrid: clusterGrid.value,
|
|
99
|
+
lightIndexList: lightIndexList.value,
|
|
100
|
+
clusterUniform: clusterUniform.value,
|
|
101
|
+
lightBounds: lightBounds.value,
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/** Accesses used by raster consumers of the shared Cluster payload. */
|
|
106
|
+
export function standardClusterReadAccesses(
|
|
107
|
+
buffers: StandardClusterGraphBuffers,
|
|
108
|
+
): readonly GraphAccess[] {
|
|
109
|
+
return [
|
|
110
|
+
{ resource: buffers.lightData, usage: 'storage-read' },
|
|
111
|
+
{ resource: buffers.clusterGrid, usage: 'storage-read' },
|
|
112
|
+
{ resource: buffers.lightIndexList, usage: 'storage-read' },
|
|
113
|
+
{ resource: buffers.clusterUniform, usage: 'uniform-read' },
|
|
114
|
+
];
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Add the sole GPU membership producer. CPU membership is already materialized
|
|
119
|
+
* in PreparedStandardLighting and therefore contributes no second pass.
|
|
120
|
+
*/
|
|
121
|
+
export function addStandardClusterMembershipPass(
|
|
122
|
+
graph: RenderGraphBuilder<RenderPipelineFrame>,
|
|
123
|
+
input: StandardTopologyInputValue,
|
|
124
|
+
buffers: StandardClusterGraphBuffers,
|
|
125
|
+
): Result<void, RenderGraphError> {
|
|
126
|
+
if (input.kind === 'no-local-lights') return ok(undefined);
|
|
127
|
+
if (input.transport.kind !== 'compute-storage') return ok(undefined);
|
|
128
|
+
const descriptor = projectDescriptor(input);
|
|
129
|
+
return graph.addComputePass('cluster-membership-producer', {
|
|
130
|
+
accesses: [
|
|
131
|
+
{ resource: buffers.clusterGrid, usage: 'storage-read' },
|
|
132
|
+
{ resource: buffers.clusterUniform, usage: 'uniform-read' },
|
|
133
|
+
{ resource: buffers.lightBounds, usage: 'storage-read' },
|
|
134
|
+
{ resource: buffers.lightIndexList, usage: 'storage-write' },
|
|
135
|
+
],
|
|
136
|
+
// Keep the clustered graph/ABI stable for a directional-only frame, but
|
|
137
|
+
// do not require a producer bind group when there is no local corpus to
|
|
138
|
+
// bin. The zero-length prepared payload is already the complete result;
|
|
139
|
+
// executing this pass would only turn an otherwise valid frame into a
|
|
140
|
+
// null-backend encode failure.
|
|
141
|
+
executeIf: shouldExecuteStandardClusterMembershipPass,
|
|
142
|
+
encode: ({ pass, frame }) => {
|
|
143
|
+
const internal = frame as _InternalRenderPipelineContext;
|
|
144
|
+
const pipeline = internal.pipelineState.hdrpClusterMembershipPipeline;
|
|
145
|
+
const bindings = internal.hdrpClusterMembershipBindGroup;
|
|
146
|
+
if (pipeline === null || bindings === null) {
|
|
147
|
+
throw new Error(
|
|
148
|
+
'standard-cluster-transport-unavailable: selected compute Cluster producer is not ready',
|
|
149
|
+
);
|
|
150
|
+
}
|
|
151
|
+
const { x, y, z } = descriptor.grid;
|
|
152
|
+
pass.setPipeline(pipeline);
|
|
153
|
+
pass.setBindGroup(0, bindings);
|
|
154
|
+
pass.dispatchWorkgroups(Math.ceil((x * y * z) / 64));
|
|
155
|
+
},
|
|
156
|
+
});
|
|
157
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import type { StandardTopologyInputValue } from './topology';
|
|
2
|
+
import type { StandardClusterTransport } from './transport';
|
|
3
|
+
|
|
4
|
+
export interface StandardClusterTransportInspection {
|
|
5
|
+
readonly renderPath: 'forward' | 'deferred';
|
|
6
|
+
readonly transport: StandardClusterTransport['kind'];
|
|
7
|
+
readonly producer: StandardClusterTransport['producer'];
|
|
8
|
+
readonly requested: StandardClusterTransport['requestedLightCount'];
|
|
9
|
+
readonly admitted: StandardClusterTransport['admittedLightCount'];
|
|
10
|
+
readonly shadowed: number;
|
|
11
|
+
readonly maxLights: number;
|
|
12
|
+
readonly indexCount: StandardClusterTransport['membershipEntryCount'];
|
|
13
|
+
readonly occupied: StandardClusterTransport['occupiedClusterCount'];
|
|
14
|
+
readonly clusterGridBytes: number;
|
|
15
|
+
readonly lightIndexListBytes: number;
|
|
16
|
+
readonly lightDataBytes: number;
|
|
17
|
+
readonly lightBoundsBytes: number;
|
|
18
|
+
readonly grid: StandardClusterTransport['layout']['grid'];
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export interface StandardNoLocalLightingInspection {
|
|
22
|
+
readonly renderPath: 'forward' | 'deferred';
|
|
23
|
+
readonly transport: 'not-required';
|
|
24
|
+
readonly producer: 'none';
|
|
25
|
+
readonly requested: 0;
|
|
26
|
+
readonly admitted: 0;
|
|
27
|
+
readonly shadowed: 0;
|
|
28
|
+
readonly maxLights: number;
|
|
29
|
+
readonly indexCount: 0;
|
|
30
|
+
readonly occupied: 0;
|
|
31
|
+
readonly clusterGridBytes: 0;
|
|
32
|
+
readonly lightIndexListBytes: 0;
|
|
33
|
+
readonly lightDataBytes: 0;
|
|
34
|
+
readonly lightBoundsBytes: 0;
|
|
35
|
+
readonly grid: StandardTopologyInputValue['prepared']['layout']['grid'];
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export type StandardLightingInspection =
|
|
39
|
+
| StandardClusterTransportInspection
|
|
40
|
+
| StandardNoLocalLightingInspection;
|
|
41
|
+
|
|
42
|
+
export function inspectStandardClusterTransport(
|
|
43
|
+
transport: StandardClusterTransport,
|
|
44
|
+
prepared: StandardTopologyInputValue['prepared'],
|
|
45
|
+
): StandardClusterTransportInspection {
|
|
46
|
+
return Object.freeze({
|
|
47
|
+
renderPath: prepared.renderPath,
|
|
48
|
+
transport: transport.kind,
|
|
49
|
+
producer: transport.producer,
|
|
50
|
+
requested: transport.requestedLightCount,
|
|
51
|
+
admitted: transport.admittedLightCount,
|
|
52
|
+
shadowed: prepared.local.filter((light) => light.shadowed === true).length,
|
|
53
|
+
maxLights: prepared.maxLights,
|
|
54
|
+
indexCount: transport.membershipEntryCount,
|
|
55
|
+
occupied: transport.occupiedClusterCount,
|
|
56
|
+
clusterGridBytes: transport.clusterGridBytes,
|
|
57
|
+
lightIndexListBytes: transport.lightIndexListBytes,
|
|
58
|
+
lightDataBytes: transport.lightDataBytes,
|
|
59
|
+
lightBoundsBytes: transport.lightBoundsBytes,
|
|
60
|
+
// The inspection boundary is JSON-safe and detached from the mutable
|
|
61
|
+
// layout object carried by a per-frame prepared result.
|
|
62
|
+
grid: Object.freeze({ ...transport.layout.grid }),
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export function inspectStandardLighting(
|
|
67
|
+
input: StandardTopologyInputValue,
|
|
68
|
+
): StandardLightingInspection {
|
|
69
|
+
if (input.kind === 'no-local-lights') {
|
|
70
|
+
return Object.freeze({
|
|
71
|
+
renderPath: input.prepared.renderPath,
|
|
72
|
+
transport: 'not-required' as const,
|
|
73
|
+
producer: 'none' as const,
|
|
74
|
+
requested: 0 as const,
|
|
75
|
+
admitted: 0 as const,
|
|
76
|
+
shadowed: 0 as const,
|
|
77
|
+
maxLights: input.prepared.maxLights,
|
|
78
|
+
indexCount: 0 as const,
|
|
79
|
+
occupied: 0 as const,
|
|
80
|
+
clusterGridBytes: 0 as const,
|
|
81
|
+
lightIndexListBytes: 0 as const,
|
|
82
|
+
lightDataBytes: 0 as const,
|
|
83
|
+
lightBoundsBytes: 0 as const,
|
|
84
|
+
grid: Object.freeze({ ...input.prepared.layout.grid }),
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
return inspectStandardClusterTransport(input.transport, input.prepared);
|
|
88
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
export const DEFAULT_CLUSTER_GRID = { x: 16, y: 9, z: 24 } as const;
|
|
2
|
+
export const CLUSTER_GRID_STRIDE_U32 = 2 as const;
|
|
3
|
+
export const LIGHT_INDEX_LIST_CAPACITY = 1048576 as const;
|
|
4
|
+
export const MAX_LIGHTS = 256 as const;
|
|
5
|
+
|
|
6
|
+
export interface StandardClusterLayout {
|
|
7
|
+
readonly grid: { readonly x: number; readonly y: number; readonly z: number };
|
|
8
|
+
readonly clusterCount: number;
|
|
9
|
+
readonly clusterGridStrideU32: typeof CLUSTER_GRID_STRIDE_U32;
|
|
10
|
+
readonly clusterGridU32Length: number;
|
|
11
|
+
readonly lightIndexListCapacity: typeof LIGHT_INDEX_LIST_CAPACITY;
|
|
12
|
+
readonly lightDataSlotCount: typeof MAX_LIGHTS;
|
|
13
|
+
readonly lightBoundsInt32Length: number;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function createStandardClusterLayout(
|
|
17
|
+
grid: { readonly x: number; readonly y: number; readonly z: number } = DEFAULT_CLUSTER_GRID,
|
|
18
|
+
): StandardClusterLayout {
|
|
19
|
+
const clusterCount = grid.x * grid.y * grid.z;
|
|
20
|
+
return Object.freeze({
|
|
21
|
+
grid,
|
|
22
|
+
clusterCount,
|
|
23
|
+
clusterGridStrideU32: CLUSTER_GRID_STRIDE_U32,
|
|
24
|
+
clusterGridU32Length: clusterCount * CLUSTER_GRID_STRIDE_U32,
|
|
25
|
+
lightIndexListCapacity: LIGHT_INDEX_LIST_CAPACITY,
|
|
26
|
+
lightDataSlotCount: MAX_LIGHTS,
|
|
27
|
+
lightBoundsInt32Length: MAX_LIGHTS * 6,
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export const STANDARD_CLUSTER_LAYOUT = createStandardClusterLayout();
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { Mat4, Vec3 } from '@forgeax/engine-math';
|
|
2
|
+
import type {
|
|
3
|
+
DirectionalLightSnapshot,
|
|
4
|
+
PointLightSnapshot,
|
|
5
|
+
SpotLightSnapshot,
|
|
6
|
+
} from '../../render-system-extract';
|
|
7
|
+
import type { StandardLightCount } from '../standard-profile';
|
|
8
|
+
|
|
9
|
+
export interface StandardLocalLightInput {
|
|
10
|
+
readonly kind: 'point' | 'spot';
|
|
11
|
+
readonly position: Vec3;
|
|
12
|
+
readonly range: number;
|
|
13
|
+
/** Whether the shadow producer admitted this local light to its atlas. */
|
|
14
|
+
readonly shadowed: boolean;
|
|
15
|
+
/**
|
|
16
|
+
* The immutable extract snapshot used by the record payload packer. Keeping
|
|
17
|
+
* it on the POD frame prevents Forward/Deferred from rebuilding a second
|
|
18
|
+
* light list while leaving hand-authored unit fixtures source-free.
|
|
19
|
+
*/
|
|
20
|
+
readonly source?: PointLightSnapshot | SpotLightSnapshot;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface StandardLightFrame {
|
|
24
|
+
readonly directional: DirectionalLightSnapshot | undefined;
|
|
25
|
+
readonly local: readonly StandardLocalLightInput[];
|
|
26
|
+
readonly view: Mat4;
|
|
27
|
+
readonly projection: Mat4;
|
|
28
|
+
readonly near: number;
|
|
29
|
+
readonly far: number;
|
|
30
|
+
readonly grid: { readonly x: number; readonly y: number; readonly z: number };
|
|
31
|
+
readonly lightCount: StandardLightCount;
|
|
32
|
+
/** Graph path carried into inspection from the active Standard profile. */
|
|
33
|
+
readonly renderPath: 'forward' | 'deferred';
|
|
34
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { err, ok, type Result } from '@forgeax/engine-types';
|
|
2
|
+
import { bin, type ClusterBinScratch, createClusterBinScratch } from '../../cluster-binner';
|
|
3
|
+
import type { RenderError } from '../../errors/render';
|
|
4
|
+
import { fromClusterBinError } from './errors';
|
|
5
|
+
import type { StandardClusterLayout } from './layout';
|
|
6
|
+
import type { StandardLightFrame } from './light-frame';
|
|
7
|
+
|
|
8
|
+
export interface StandardClusterMembership {
|
|
9
|
+
readonly clusterGrid: Uint32Array;
|
|
10
|
+
readonly lightIndexList: Uint32Array;
|
|
11
|
+
readonly lightBounds: Int32Array;
|
|
12
|
+
readonly membershipEntryCount: number;
|
|
13
|
+
readonly scratch: ClusterBinScratch;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function deriveStandardMembership(
|
|
17
|
+
frame: StandardLightFrame,
|
|
18
|
+
layout: StandardClusterLayout,
|
|
19
|
+
scratch = createClusterBinScratch(),
|
|
20
|
+
): Result<StandardClusterMembership, RenderError> {
|
|
21
|
+
const clusterGrid = new Uint32Array(layout.clusterGridU32Length);
|
|
22
|
+
const lightIndexList = new Uint32Array(layout.lightIndexListCapacity);
|
|
23
|
+
const result = bin(
|
|
24
|
+
frame.local,
|
|
25
|
+
frame.view,
|
|
26
|
+
frame.projection,
|
|
27
|
+
layout.grid,
|
|
28
|
+
frame.near,
|
|
29
|
+
frame.far,
|
|
30
|
+
clusterGrid,
|
|
31
|
+
lightIndexList,
|
|
32
|
+
layout.lightIndexListCapacity,
|
|
33
|
+
scratch,
|
|
34
|
+
);
|
|
35
|
+
if (!result.ok) return err(fromClusterBinError(result.error));
|
|
36
|
+
return ok({
|
|
37
|
+
clusterGrid,
|
|
38
|
+
lightIndexList,
|
|
39
|
+
lightBounds: scratch.lightBounds.slice(0, frame.local.length * 6),
|
|
40
|
+
membershipEntryCount: result.value,
|
|
41
|
+
scratch,
|
|
42
|
+
});
|
|
43
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { err, ok, type Result } from '@forgeax/engine-types';
|
|
2
|
+
import { type RenderError, StandardLightBudgetExceededError } from '../../errors/render';
|
|
3
|
+
import { MAX_LIGHTS } from '../standard-profile';
|
|
4
|
+
import { createStandardClusterLayout, type StandardClusterLayout } from './layout';
|
|
5
|
+
import type { StandardLightFrame } from './light-frame';
|
|
6
|
+
import { deriveStandardMembership, type StandardClusterMembership } from './membership';
|
|
7
|
+
|
|
8
|
+
export type { StandardLightFrame } from './light-frame';
|
|
9
|
+
|
|
10
|
+
export interface PreparedStandardLighting extends StandardClusterMembership {
|
|
11
|
+
readonly directional: StandardLightFrame['directional'];
|
|
12
|
+
readonly local: StandardLightFrame['local'];
|
|
13
|
+
readonly layout: StandardClusterLayout;
|
|
14
|
+
readonly membershipLightCount: number;
|
|
15
|
+
readonly renderPath: NonNullable<StandardLightFrame['renderPath']>;
|
|
16
|
+
readonly maxLights: StandardLightFrame['lightCount'];
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function prepareStandardLighting(
|
|
20
|
+
frame: StandardLightFrame,
|
|
21
|
+
): Result<PreparedStandardLighting, RenderError> {
|
|
22
|
+
if (frame.local.length > frame.lightCount || frame.local.length > MAX_LIGHTS) {
|
|
23
|
+
return err(new StandardLightBudgetExceededError(frame.local.length, frame.lightCount));
|
|
24
|
+
}
|
|
25
|
+
const layout = createStandardClusterLayout(frame.grid);
|
|
26
|
+
const membership = deriveStandardMembership(frame, layout);
|
|
27
|
+
if (!membership.ok) return membership;
|
|
28
|
+
return ok({
|
|
29
|
+
...membership.value,
|
|
30
|
+
directional: frame.directional,
|
|
31
|
+
local: frame.local,
|
|
32
|
+
layout,
|
|
33
|
+
membershipLightCount: frame.local.length,
|
|
34
|
+
renderPath: frame.renderPath,
|
|
35
|
+
maxLights: frame.lightCount,
|
|
36
|
+
});
|
|
37
|
+
}
|