@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
|
@@ -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,37 +26,33 @@ 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
|
-
|
|
33
29
|
export interface StandardProfile {
|
|
34
30
|
readonly pipelineId: typeof STANDARD_PIPELINE_ID;
|
|
35
31
|
readonly lightCount: StandardLightCount;
|
|
36
|
-
|
|
32
|
+
/** Graph topology selector; all local lights use the shared Cluster path. */
|
|
33
|
+
readonly renderPath: 'forward' | 'deferred';
|
|
37
34
|
readonly shadows: StandardShadowMode;
|
|
38
35
|
readonly pbr: boolean;
|
|
39
36
|
readonly ibl: boolean;
|
|
40
37
|
readonly ssao: boolean;
|
|
41
|
-
|
|
38
|
+
/** Renderer-owned 1080p volume profile; tile width/height remain surface-derived. */
|
|
39
|
+
readonly volumetricFog?: StandardVolumetricFogProfile | undefined;
|
|
42
40
|
readonly postStages: typeof STANDARD_POST_STAGE_NAMES;
|
|
43
41
|
}
|
|
44
42
|
|
|
45
43
|
export const DEFAULT_STANDARD_PROFILE: StandardProfile = Object.freeze({
|
|
46
44
|
pipelineId: STANDARD_PIPELINE_ID,
|
|
47
45
|
lightCount: 32,
|
|
48
|
-
|
|
46
|
+
renderPath: 'forward',
|
|
49
47
|
shadows: 'filtered',
|
|
50
48
|
pbr: true,
|
|
51
49
|
ibl: true,
|
|
52
50
|
ssao: false,
|
|
53
|
-
fallback: 'native',
|
|
54
51
|
postStages: STANDARD_POST_STAGE_NAMES,
|
|
55
52
|
});
|
|
56
53
|
|
|
57
|
-
export
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
profile:
|
|
61
|
-
capabilities: { readonly compute: boolean; readonly storageBuffer: boolean },
|
|
62
|
-
): StandardLane {
|
|
63
|
-
if (!capabilities.compute || !capabilities.storageBuffer) return 'cpu-webgl2';
|
|
64
|
-
return profile.lighting;
|
|
54
|
+
export function resolveVolumetricFogProfile(
|
|
55
|
+
profile: Pick<StandardProfile, 'volumetricFog'>,
|
|
56
|
+
): StandardVolumetricFogProfile {
|
|
57
|
+
return profile.volumetricFog ?? { quality: 'high', depth: 64, tileSize: 4 };
|
|
65
58
|
}
|
package/src/pipeline-spec.ts
CHANGED
|
@@ -287,6 +287,69 @@ export function variantSetFromVertexLayoutProjection(
|
|
|
287
287
|
return ok(parts.join('+'));
|
|
288
288
|
}
|
|
289
289
|
|
|
290
|
+
/**
|
|
291
|
+
* Derive the capability axes shared by every Standard PBR draw owner.
|
|
292
|
+
*
|
|
293
|
+
* The all-true key is the canonical empty key used by the shader manifest;
|
|
294
|
+
* every other capability pair stays explicit so a no-local-light frame on a
|
|
295
|
+
* device without storage buffers cannot accidentally select a storage-backed
|
|
296
|
+
* PSO. Vertex-color is supplied here because the empty-key rule is only valid
|
|
297
|
+
* when that geometry-owned axis is also true.
|
|
298
|
+
*/
|
|
299
|
+
export function standardCapabilityVariantSet(
|
|
300
|
+
clustered: boolean,
|
|
301
|
+
storageBuffer: boolean,
|
|
302
|
+
vertexColorAvailable: boolean,
|
|
303
|
+
): string {
|
|
304
|
+
if (clustered && storageBuffer && vertexColorAvailable) return '';
|
|
305
|
+
return `CLUSTER_FORWARD_AVAILABLE=${clustered}+STORAGE_BUFFER_AVAILABLE=${storageBuffer}`;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
/**
|
|
309
|
+
* Project the frame-owned Standard topology onto its material variant axes.
|
|
310
|
+
*
|
|
311
|
+
* `StandardTopologyInputValue.kind` is the only runtime authority for the
|
|
312
|
+
* cluster axis: a frame with local lights must request the clustered artifact,
|
|
313
|
+
* while the no-local-light topology requests the direct artifact. Keeping
|
|
314
|
+
* this projection beside the canonical key builder prevents PBR, skin, and
|
|
315
|
+
* sprite-lit record owners from independently inferring the active lane from
|
|
316
|
+
* whichever bind group happened to be constructed first.
|
|
317
|
+
*/
|
|
318
|
+
export function standardTopologyVariantSet(
|
|
319
|
+
topology: { readonly kind: 'no-local-lights' | 'clustered' } | undefined,
|
|
320
|
+
storageBuffer: boolean,
|
|
321
|
+
vertexColorAvailable: boolean,
|
|
322
|
+
): string {
|
|
323
|
+
return standardCapabilityVariantSet(
|
|
324
|
+
topology?.kind === 'clustered',
|
|
325
|
+
storageBuffer,
|
|
326
|
+
vertexColorAvailable,
|
|
327
|
+
);
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
/**
|
|
331
|
+
* Keep a clustered frame fail-closed when its unified group(2) resource is
|
|
332
|
+
* unavailable. A missing group is not evidence that the frame is direct; it
|
|
333
|
+
* is an invalid prepared resource state.
|
|
334
|
+
*/
|
|
335
|
+
export function standardTopologyBindGroupReady(
|
|
336
|
+
topology: { readonly kind: 'no-local-lights' | 'clustered' } | undefined,
|
|
337
|
+
clusterBindGroup: unknown,
|
|
338
|
+
): boolean {
|
|
339
|
+
return (
|
|
340
|
+
topology?.kind !== 'clustered' || (clusterBindGroup !== null && clusterBindGroup !== undefined)
|
|
341
|
+
);
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
/** Derive the storage axis for Standard-compatible unlit material draws. */
|
|
345
|
+
export function standardStorageVariantSet(
|
|
346
|
+
storageBuffer: boolean,
|
|
347
|
+
vertexColorAvailable: boolean,
|
|
348
|
+
): string {
|
|
349
|
+
if (storageBuffer && vertexColorAvailable) return '';
|
|
350
|
+
return `STORAGE_BUFFER_AVAILABLE=${storageBuffer}+VERTEX_COLOR_AVAILABLE=${vertexColorAvailable}`;
|
|
351
|
+
}
|
|
352
|
+
|
|
290
353
|
/**
|
|
291
354
|
* Build a `GPURenderPipelineDescriptor` from a PipelineSpec + shader modules.
|
|
292
355
|
*
|
|
@@ -925,14 +988,14 @@ const TRI_GEOMETRY_PBR = {
|
|
|
925
988
|
shaderUvSetCount: 8,
|
|
926
989
|
};
|
|
927
990
|
|
|
928
|
-
// M6 fix-up:
|
|
929
|
-
// boot-time variantSet computed at createRenderer.ts step 1b when
|
|
930
|
-
//
|
|
931
|
-
// surface). The
|
|
991
|
+
// M6 fix-up: non-clustered boot-variant key string for the standard PBR shader.
|
|
992
|
+
// Mirrors the boot-time variantSet computed at createRenderer.ts step 1b when
|
|
993
|
+
// clustered lighting is not yet admitted and `storageBufferCapable=true` (the
|
|
994
|
+
// surface). The default record path requests this exact string at every
|
|
932
995
|
// `getMaterialShaderPipeline` call site, so seeding the table with these
|
|
933
|
-
// variants keeps the
|
|
996
|
+
// variants keeps the default cache lookup hot from frame 1 instead of
|
|
934
997
|
// skip-drawing the first ~1 frames while the async compile resolves.
|
|
935
|
-
const
|
|
998
|
+
const STANDARD_BOOT_VARIANT_SET = standardCapabilityVariantSet(false, true, false);
|
|
936
999
|
|
|
937
1000
|
/**
|
|
938
1001
|
* Build the boot-time pre-warm table: 15 standard PipelineSpec variants.
|
|
@@ -944,22 +1007,22 @@ const URP_PBR_VARIANT_SET = 'CLUSTER_FORWARD_AVAILABLE=false+STORAGE_BUFFER_AVAI
|
|
|
944
1007
|
*
|
|
945
1008
|
* Matrix:
|
|
946
1009
|
* - 8 base material variants — {unlit, standard-pbr} x {LDR, HDR} x {S1, S4}
|
|
947
|
-
* - 4
|
|
948
|
-
* x {LDR, HDR} x {S1, S4};
|
|
1010
|
+
* - 4 non-clustered standard-pbr — standard-pbr (variantSet=STANDARD_BOOT_VARIANT_SET)
|
|
1011
|
+
* x {LDR, HDR} x {S1, S4}; the default record path requests these specs by
|
|
949
1012
|
* `getMaterialShaderPipeline` keying off `cacheKeyOf` so the boot-time
|
|
950
1013
|
* prewarm seeds `materialShaderPipelineCache` and avoids a 1-frame
|
|
951
|
-
* async-compile skip-draw (M6 fix-up; see render-system-record.ts
|
|
1014
|
+
* async-compile skip-draw (M6 fix-up; see render-system-record.ts)
|
|
952
1015
|
* - 3 fullscreen-post — tonemap (LDR S1) + skybox (HDR S1, HDR S4)
|
|
953
1016
|
*
|
|
954
|
-
* Total: 15. The
|
|
955
|
-
* - unlit
|
|
1017
|
+
* Total: 15. The non-clustered variant is PBR-only because:
|
|
1018
|
+
* - unlit record path passes `variantSet=undefined` (the no-variant
|
|
956
1019
|
* boot-default entries already cover it; createRenderer.ts §unlitRsp)
|
|
957
1020
|
* - sprite goes through `getMaterialShaderPipeline('forgeax::sprite', ...)`
|
|
958
1021
|
* lazily at first transparent-LDR-split draw — no boot-time pre-warm.
|
|
959
|
-
* -
|
|
1022
|
+
* - clustered variant (`variantSet=''` or compound `=true` form) is registered
|
|
960
1023
|
* lazily when the clustered Standard profile activates, not at boot — adding clustered
|
|
961
1024
|
* prewarm here would build PSOs against the URP layout (the boot-time
|
|
962
|
-
* `pbrModule` is the
|
|
1025
|
+
* `pbrModule` is the non-clustered variant before a frame admits local lights)
|
|
963
1026
|
*
|
|
964
1027
|
* `ldrViewFormat` parameterises the LDR color attachment format. Callers
|
|
965
1028
|
* pass the runtime-resolved swap-chain view format (Channel 2 typically
|
|
@@ -1074,12 +1137,12 @@ export function buildSpecConstTable(
|
|
|
1074
1137
|
renderState: undefined,
|
|
1075
1138
|
},
|
|
1076
1139
|
|
|
1077
|
-
// ── M6 fix-up:
|
|
1078
|
-
//
|
|
1079
|
-
// `variantSet=
|
|
1140
|
+
// ── M6 fix-up: non-clustered standard-pbr prewarm ─────────────────────────
|
|
1141
|
+
// The default record path (`getMaterialShaderPipeline`) requests
|
|
1142
|
+
// `variantSet=STANDARD_BOOT_VARIANT_SET` for standard-shading entities; pre-M6
|
|
1080
1143
|
// the silent `selectStandardFallbackPipeline` shim served the no-variant
|
|
1081
1144
|
// boot prewarm during the 1-frame async-compile warmup. With M6's
|
|
1082
|
-
// explicit-failure surface, those
|
|
1145
|
+
// explicit-failure surface, those requests must hit the boot prewarm
|
|
1083
1146
|
// by their own variantSet — these 4 entries close that gap.
|
|
1084
1147
|
|
|
1085
1148
|
// standard PBR URP LDR S1
|
|
@@ -1087,7 +1150,7 @@ export function buildSpecConstTable(
|
|
|
1087
1150
|
shader: {
|
|
1088
1151
|
id: 'forgeax::default-standard-pbr',
|
|
1089
1152
|
passKind: 'forward',
|
|
1090
|
-
variantSet:
|
|
1153
|
+
variantSet: STANDARD_BOOT_VARIANT_SET,
|
|
1091
1154
|
},
|
|
1092
1155
|
attachments: TRI_ATTACHMENTS_LDR_S1,
|
|
1093
1156
|
geometry: TRI_GEOMETRY_PBR,
|
|
@@ -1098,7 +1161,7 @@ export function buildSpecConstTable(
|
|
|
1098
1161
|
shader: {
|
|
1099
1162
|
id: 'forgeax::default-standard-pbr',
|
|
1100
1163
|
passKind: 'forward',
|
|
1101
|
-
variantSet:
|
|
1164
|
+
variantSet: STANDARD_BOOT_VARIANT_SET,
|
|
1102
1165
|
},
|
|
1103
1166
|
attachments: TRI_ATTACHMENTS_LDR_S4,
|
|
1104
1167
|
geometry: TRI_GEOMETRY_PBR,
|
|
@@ -1109,7 +1172,7 @@ export function buildSpecConstTable(
|
|
|
1109
1172
|
shader: {
|
|
1110
1173
|
id: 'forgeax::default-standard-pbr',
|
|
1111
1174
|
passKind: 'forward',
|
|
1112
|
-
variantSet:
|
|
1175
|
+
variantSet: STANDARD_BOOT_VARIANT_SET,
|
|
1113
1176
|
},
|
|
1114
1177
|
attachments: TRI_ATTACHMENTS_HDR_S1,
|
|
1115
1178
|
geometry: TRI_GEOMETRY_PBR,
|
|
@@ -1120,7 +1183,7 @@ export function buildSpecConstTable(
|
|
|
1120
1183
|
shader: {
|
|
1121
1184
|
id: 'forgeax::default-standard-pbr',
|
|
1122
1185
|
passKind: 'forward',
|
|
1123
|
-
variantSet:
|
|
1186
|
+
variantSet: STANDARD_BOOT_VARIANT_SET,
|
|
1124
1187
|
},
|
|
1125
1188
|
attachments: TRI_ATTACHMENTS_HDR_S4,
|
|
1126
1189
|
geometry: TRI_GEOMETRY_PBR,
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import type { PointShadowSnapshot } from './render-system-extract';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Detached point-shadow budget facts from one completed extract/record frame.
|
|
5
|
+
*
|
|
6
|
+
* `requested` is the number of PointLight + PointLightShadow pairs. The
|
|
7
|
+
* renderer owns the bounded cube-array atlas, so `admitted`, `shadowed`, and
|
|
8
|
+
* `shadowAtlasOccupancy` are all derived from the layer sentinel emitted by
|
|
9
|
+
* the same extract owner. No consumer needs to maintain a second budget
|
|
10
|
+
* ledger.
|
|
11
|
+
*/
|
|
12
|
+
export interface PointShadowInspection {
|
|
13
|
+
readonly status: 'inactive' | 'ready' | 'over-budget';
|
|
14
|
+
readonly requested: number;
|
|
15
|
+
readonly admitted: number;
|
|
16
|
+
readonly shadowed: number;
|
|
17
|
+
readonly shadowAtlasOccupancy: number;
|
|
18
|
+
readonly shadowAtlasCapacity: number;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/** Project point-shadow snapshots to the public, JSON-safe inspection shape. */
|
|
22
|
+
export function inspectPointShadow(
|
|
23
|
+
snapshots: readonly PointShadowSnapshot[],
|
|
24
|
+
shadowAtlasCapacity: number,
|
|
25
|
+
): PointShadowInspection {
|
|
26
|
+
const requested = snapshots.length;
|
|
27
|
+
const admitted = snapshots.reduce(
|
|
28
|
+
(count, snapshot) =>
|
|
29
|
+
snapshot.shadowAtlasLayer >= 0 && snapshot.shadowAtlasLayer < shadowAtlasCapacity
|
|
30
|
+
? count + 1
|
|
31
|
+
: count,
|
|
32
|
+
0,
|
|
33
|
+
);
|
|
34
|
+
// Never publish a misleading `ready` state when any requested shadow owns
|
|
35
|
+
// no atlas layer. The extract sentinel is the single admission projection;
|
|
36
|
+
// a partial or all-sentinel frame is therefore a failed/over-budget
|
|
37
|
+
// admission, not an active shadow path with incomplete output.
|
|
38
|
+
const status =
|
|
39
|
+
requested === 0
|
|
40
|
+
? ('inactive' as const)
|
|
41
|
+
: requested > shadowAtlasCapacity || admitted !== requested
|
|
42
|
+
? ('over-budget' as const)
|
|
43
|
+
: ('ready' as const);
|
|
44
|
+
return Object.freeze({
|
|
45
|
+
status,
|
|
46
|
+
requested,
|
|
47
|
+
admitted,
|
|
48
|
+
// A point shadow only samples an atlas after it owns an atlas layer. Keep
|
|
49
|
+
// these names explicit for AI diagnostics while deriving both from the
|
|
50
|
+
// one layer projection above.
|
|
51
|
+
shadowed: admitted,
|
|
52
|
+
shadowAtlasOccupancy: admitted,
|
|
53
|
+
shadowAtlasCapacity,
|
|
54
|
+
});
|
|
55
|
+
}
|
|
@@ -2,7 +2,7 @@ import { vec3 } from '@forgeax/engine-math';
|
|
|
2
2
|
import type { Buffer, RhiQueue } from '@forgeax/engine-rhi';
|
|
3
3
|
import { describe, expect, it } from 'vitest';
|
|
4
4
|
import type { CameraSnapshot } from '../../render-contract';
|
|
5
|
-
import type { RenderableSnapshot } from '../../render-system-extract';
|
|
5
|
+
import type { RenderableSnapshot, SpotLightSnapshot } from '../../render-system-extract';
|
|
6
6
|
import type { TemporalView } from '../../temporal/temporal-view';
|
|
7
7
|
import type { ValidatedRenderable } from '../frame-snapshot';
|
|
8
8
|
import { uploadMeshSsboBatch } from '../mesh-ssbo';
|
|
@@ -98,6 +98,47 @@ function temporalView(): TemporalView {
|
|
|
98
98
|
}
|
|
99
99
|
|
|
100
100
|
describe('temporal GPU payloads', () => {
|
|
101
|
+
it('publishes a projector-only SpotLight matrix into the explicit lane-0 contract', () => {
|
|
102
|
+
const { queue, uploads } = recordingQueue();
|
|
103
|
+
const projectorMatrix = translatedMatrix(9);
|
|
104
|
+
const projector: SpotLightSnapshot = {
|
|
105
|
+
kind: 'spot',
|
|
106
|
+
entity: 4,
|
|
107
|
+
position: vec3.create(0, 2, 0),
|
|
108
|
+
direction: vec3.create(0, -1, 0),
|
|
109
|
+
color: vec3.create(1, 1, 1),
|
|
110
|
+
intensity: 1,
|
|
111
|
+
invRangeSquared: 0.04,
|
|
112
|
+
cosInner: 0.95,
|
|
113
|
+
cosOuter: 0.8,
|
|
114
|
+
castShadow: false,
|
|
115
|
+
lightViewProj: projectorMatrix,
|
|
116
|
+
mapSize: 512,
|
|
117
|
+
nearPlane: 0.1,
|
|
118
|
+
farPlane: 25,
|
|
119
|
+
shadowAtlasTile: -1,
|
|
120
|
+
projectorAsset: { kind: 'texture' } as never,
|
|
121
|
+
};
|
|
122
|
+
writeViewUbo(
|
|
123
|
+
queue,
|
|
124
|
+
{} as Buffer,
|
|
125
|
+
camera(),
|
|
126
|
+
{
|
|
127
|
+
kind: 'directional',
|
|
128
|
+
direction: vec3.create(0, -1, 0),
|
|
129
|
+
color: vec3.create(1, 1, 1),
|
|
130
|
+
intensity: 1,
|
|
131
|
+
},
|
|
132
|
+
{ point: [], spot: [projector] } as never,
|
|
133
|
+
[projector],
|
|
134
|
+
undefined,
|
|
135
|
+
undefined,
|
|
136
|
+
0,
|
|
137
|
+
);
|
|
138
|
+
const payload = new Float32Array(uploads[0]?.buffer ?? new ArrayBuffer(0));
|
|
139
|
+
expect(payload[132 + 12]).toBe(9);
|
|
140
|
+
});
|
|
141
|
+
|
|
101
142
|
it('writes temporal current/previous projection after the spot-light lanes', () => {
|
|
102
143
|
const { queue, uploads } = recordingQueue();
|
|
103
144
|
writeViewUbo(
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import { selectPipelineLayoutForVariant } from '../../assembly/factory';
|
|
3
|
+
import { resolvePipelineGroup2Contract } from '../../pbr-pipeline';
|
|
4
|
+
import { projectDeviceOwnedBindGroup } from '../frame-lighting';
|
|
5
|
+
import { selectMaterialGroup2 } from '../main-pass-material';
|
|
6
|
+
|
|
7
|
+
const meshGroup = { label: 'pbr-mesh-bg' } as never;
|
|
8
|
+
const clusterGroup = { label: 'hdrp-unified-bg-group2' } as never;
|
|
9
|
+
|
|
10
|
+
describe('transparent material group 2 selection', () => {
|
|
11
|
+
it('uses the shared cluster layout only for standard materials', () => {
|
|
12
|
+
expect(selectMaterialGroup2(clusterGroup, meshGroup, 'cluster')).toBe(clusterGroup);
|
|
13
|
+
expect(selectMaterialGroup2(clusterGroup, meshGroup, 'mesh')).toBe(meshGroup);
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
it('returns null when a non-standard material lacks its ordinary mesh group', () => {
|
|
17
|
+
expect(selectMaterialGroup2(clusterGroup, null, 'mesh')).toBeNull();
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
it('resolves mesh, skin, and clustered skin from the composed shader artifact', () => {
|
|
21
|
+
expect(
|
|
22
|
+
resolvePipelineGroup2Contract('@group(2) @binding(0) var<storage> mesh: array<u32>;'),
|
|
23
|
+
).toBe('mesh');
|
|
24
|
+
expect(
|
|
25
|
+
resolvePipelineGroup2Contract(
|
|
26
|
+
'@group(2) @binding(0) var<storage> mesh: array<u32>; @group(2) @binding(1) var<uniform> palette: mat4x4<f32>;',
|
|
27
|
+
),
|
|
28
|
+
).toBe('skin');
|
|
29
|
+
expect(
|
|
30
|
+
resolvePipelineGroup2Contract(
|
|
31
|
+
'@group(2) @binding(0) var<storage> mesh: array<u32>; @group(2) @binding(1) var<storage> palette: array<u32>; @group(2) @binding(4) var<storage> lights: array<u32>;',
|
|
32
|
+
),
|
|
33
|
+
).toBe('skin-cluster');
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it('lets the resolved clustered contract select the unified group', () => {
|
|
37
|
+
expect(selectMaterialGroup2(clusterGroup, meshGroup, 'cluster')).toBe(clusterGroup);
|
|
38
|
+
expect(selectMaterialGroup2(clusterGroup, meshGroup, 'skin')).toBeNull();
|
|
39
|
+
// A skin-cluster PSO cannot consume the ordinary HDRP group. The caller
|
|
40
|
+
// must provide the dedicated skin bind group through the skin path; when
|
|
41
|
+
// it is absent, fail-stop instead of submitting a layout-invalid draw.
|
|
42
|
+
expect(selectMaterialGroup2(clusterGroup, meshGroup, 'skin-cluster')).toBeNull();
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
it('keeps a mesh contract on the mesh pipeline despite the HDRP variant key', () => {
|
|
46
|
+
const pbrPipelineLayout = { label: 'pbr-pl' } as never;
|
|
47
|
+
const hdrpPipelineLayout = { label: 'hdrp-pbr-pl' } as never;
|
|
48
|
+
expect(
|
|
49
|
+
selectPipelineLayoutForVariant(
|
|
50
|
+
{
|
|
51
|
+
pbrPipelineLayout,
|
|
52
|
+
hdrpPbrPipelineLayout: hdrpPipelineLayout,
|
|
53
|
+
pbrSkinPipelineLayout: null,
|
|
54
|
+
hdrpSkinPipelineLayout: null,
|
|
55
|
+
},
|
|
56
|
+
'',
|
|
57
|
+
'pbr',
|
|
58
|
+
),
|
|
59
|
+
).toBe(pbrPipelineLayout);
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it('rejects membership bindings from a retired device or layout', () => {
|
|
63
|
+
const deviceA = {} as never;
|
|
64
|
+
const deviceB = {} as never;
|
|
65
|
+
const layoutA = {} as never;
|
|
66
|
+
const layoutB = {} as never;
|
|
67
|
+
const bindGroup = {} as never;
|
|
68
|
+
const state = { device: deviceA, layout: layoutA, bindGroup };
|
|
69
|
+
expect(projectDeviceOwnedBindGroup(state, deviceA, layoutA)).toBe(bindGroup);
|
|
70
|
+
expect(projectDeviceOwnedBindGroup(state, deviceB, layoutA)).toBeNull();
|
|
71
|
+
expect(projectDeviceOwnedBindGroup(state, deviceA, layoutB)).toBeNull();
|
|
72
|
+
});
|
|
73
|
+
});
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { readFileSync } from 'node:fs';
|
|
2
|
+
import { fileURLToPath } from 'node:url';
|
|
3
|
+
import { describe, expect, it } from 'vitest';
|
|
4
|
+
|
|
5
|
+
const viewUboSrc = readFileSync(fileURLToPath(new URL('../view-ubo.ts', import.meta.url)), 'utf8');
|
|
6
|
+
const commonWgslSrc = readFileSync(
|
|
7
|
+
fileURLToPath(new URL('../../../..//shader/src/common.wgsl', import.meta.url)),
|
|
8
|
+
'utf8',
|
|
9
|
+
);
|
|
10
|
+
|
|
11
|
+
describe('View UBO directional shadow ABI', () => {
|
|
12
|
+
it('keeps the 960 B payload inside the existing 1024 B slot', () => {
|
|
13
|
+
expect(viewUboSrc).toMatch(/VIEW_UNIFORM_BYTES\s*=\s*960/);
|
|
14
|
+
expect(viewUboSrc).toMatch(/VIEW_UNIFORM_SLOT_STRIDE\s*=\s*1024/);
|
|
15
|
+
expect(viewUboSrc).toMatch(/VIEW_PAYLOAD_FLOATS\s*=\s*240/);
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
it('packs all four cascade metrics into the existing vec4 lanes', () => {
|
|
19
|
+
expect(viewUboSrc).toMatch(/viewPayload\[108 \+ s \* 4 \+ lane\]/);
|
|
20
|
+
expect(viewUboSrc).not.toMatch(/viewPayload\[108 \+ s \* 4\]\s*=\s*lights\.splitPlanes/);
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
it('keeps bias at [126]/[127], directional filter at [128..131], and Spot at 132', () => {
|
|
24
|
+
expect(viewUboSrc).toMatch(/viewPayload\[126\]\s*=\s*lights\.depthBias/);
|
|
25
|
+
expect(viewUboSrc).toMatch(/viewPayload\[127\]\s*=\s*lights\.normalBias/);
|
|
26
|
+
expect(viewUboSrc).toMatch(/viewPayload\[128\]/);
|
|
27
|
+
expect(viewUboSrc).toMatch(/viewPayload\[129\]/);
|
|
28
|
+
expect(viewUboSrc).toMatch(/viewPayload\[130\]/);
|
|
29
|
+
expect(viewUboSrc).toMatch(/viewPayload\[131\]/);
|
|
30
|
+
expect(viewUboSrc).toMatch(/SPOT_LVP_BASE_FLOAT\s*=\s*132/);
|
|
31
|
+
expect(viewUboSrc).not.toMatch(/lights\.pcfKernelSize/);
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it('declares one shared View binding with a vec4 directional filter carrier', () => {
|
|
35
|
+
const viewStruct = commonWgslSrc.match(/struct View \{[\s\S]*?\n\};/)?.[0] ?? '';
|
|
36
|
+
expect(viewStruct).toMatch(/directionalShadowFilter\s*:\s*vec4<f32>/);
|
|
37
|
+
expect(viewStruct).not.toMatch(/pcfKernelSize/);
|
|
38
|
+
expect(commonWgslSrc.match(/@group\(0\) @binding\(0\) var<uniform> view/g)).toHaveLength(1);
|
|
39
|
+
});
|
|
40
|
+
});
|