@forgeax/engine-render 0.1.21 → 0.1.23
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +150 -29
- package/dist/assembly/backend-contract.d.ts +13 -0
- package/dist/assembly/backend-contract.d.ts.map +1 -1
- package/dist/assembly/device-feature-admission.d.ts.map +1 -1
- package/dist/assembly/factory.d.ts +14 -6
- package/dist/assembly/factory.d.ts.map +1 -1
- package/dist/assembly/host-contract.d.ts +10 -0
- package/dist/assembly/host-contract.d.ts.map +1 -1
- package/dist/authoring.mjs +1 -1
- package/dist/{chunk-PCHBPYML.mjs → chunk-4L3P6DT5.mjs} +2 -2
- package/dist/chunk-4L3P6DT5.mjs.map +1 -0
- package/dist/{chunk-VFPLTKCU.mjs → chunk-4NPUASZR.mjs} +15 -4
- package/dist/chunk-4NPUASZR.mjs.map +1 -0
- package/dist/chunk-DIYW3M5D.mjs +5085 -0
- package/dist/chunk-DIYW3M5D.mjs.map +1 -0
- package/dist/chunk-FBC4R44J.mjs +1003 -0
- package/dist/chunk-FBC4R44J.mjs.map +1 -0
- package/dist/{chunk-FS2KNUQH.mjs → chunk-FF7K3FSO.mjs} +253 -489
- package/dist/chunk-FF7K3FSO.mjs.map +1 -0
- package/dist/chunk-HZUPSYW7.mjs +1104 -0
- package/dist/chunk-HZUPSYW7.mjs.map +1 -0
- package/dist/{chunk-6OPXDQ2E.mjs → chunk-QODA5UKU.mjs} +33 -294
- package/dist/chunk-QODA5UKU.mjs.map +1 -0
- package/dist/chunk-YALPS44A.mjs +296 -0
- package/dist/chunk-YALPS44A.mjs.map +1 -0
- package/dist/{chunk-5YADUCA7.mjs → chunk-ZUWKAZ2I.mjs} +585 -991
- package/dist/chunk-ZUWKAZ2I.mjs.map +1 -0
- package/dist/cluster-binner.d.ts +5 -0
- package/dist/cluster-binner.d.ts.map +1 -1
- package/dist/components/index.d.ts +3 -0
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/light-helpers.d.ts +4 -0
- package/dist/components/light-helpers.d.ts.map +1 -1
- package/dist/components/light-probe.d.ts +9 -0
- package/dist/components/light-probe.d.ts.map +1 -0
- package/dist/components/rect-area-light.d.ts +12 -0
- package/dist/components/rect-area-light.d.ts.map +1 -0
- package/dist/components/scene-instance.d.ts +4 -0
- package/dist/components/scene-instance.d.ts.map +1 -1
- package/dist/components/spot-light.d.ts +3 -0
- package/dist/components/spot-light.d.ts.map +1 -1
- package/dist/construct-renderer.mjs +10437 -10044
- package/dist/construct-renderer.mjs.map +1 -1
- package/dist/device/gpu-residency.d.ts +8 -1
- package/dist/device/gpu-residency.d.ts.map +1 -1
- package/dist/device/lifecycle-transaction.d.ts +2 -0
- package/dist/device/lifecycle-transaction.d.ts.map +1 -0
- package/dist/environment/lifecycle.d.ts.map +1 -1
- package/dist/errors/gpu-driven.d.ts +26 -0
- package/dist/errors/gpu-driven.d.ts.map +1 -0
- package/dist/errors/index.d.ts +1 -0
- package/dist/errors/index.d.ts.map +1 -1
- package/dist/errors/recover.d.ts +9 -1
- package/dist/errors/recover.d.ts.map +1 -1
- package/dist/errors/render.d.ts +26 -1
- package/dist/errors/render.d.ts.map +1 -1
- package/dist/extract/gpu-driven.d.ts +50 -0
- package/dist/extract/gpu-driven.d.ts.map +1 -0
- package/dist/extract/visibility.d.ts.map +1 -1
- package/dist/gpu-driven/batch-topology.d.ts +34 -0
- package/dist/gpu-driven/batch-topology.d.ts.map +1 -1
- package/dist/gpu-driven/prepared-draw.d.ts +63 -0
- package/dist/gpu-driven/prepared-draw.d.ts.map +1 -0
- package/dist/gpu-driven/production-raster.d.ts +98 -2
- package/dist/gpu-driven/production-raster.d.ts.map +1 -1
- package/dist/gpu-driven/view-gpu.d.ts +64 -1
- package/dist/gpu-driven/view-gpu.d.ts.map +1 -1
- package/dist/gpu-scene-schema.d.ts +14 -0
- package/dist/gpu-scene-schema.d.ts.map +1 -1
- package/dist/gpu-scene.d.ts +8 -1
- package/dist/gpu-scene.d.ts.map +1 -1
- package/dist/gpu-usage.d.ts +0 -1
- package/dist/gpu-usage.d.ts.map +1 -1
- package/dist/hdrp-buffers.d.ts +3 -3
- package/dist/hdrp-buffers.d.ts.map +1 -1
- package/dist/index.d.ts +12 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.mjs +90 -5
- package/dist/index.mjs.map +1 -1
- package/dist/inspection-types.d.ts +163 -1
- package/dist/inspection-types.d.ts.map +1 -1
- package/dist/internal.d.ts +9 -0
- package/dist/internal.d.ts.map +1 -1
- package/dist/internal.mjs +23 -2
- package/dist/internal.mjs.map +1 -1
- package/dist/light-buffer-layout.d.ts +58 -149
- package/dist/light-buffer-layout.d.ts.map +1 -1
- package/dist/materials.d.ts.map +1 -1
- package/dist/pbr-pipeline.d.ts +26 -12
- package/dist/pbr-pipeline.d.ts.map +1 -1
- package/dist/pipeline/standard-forward-lane.d.ts.map +1 -1
- package/dist/pipeline/standard-lighting/graph.d.ts.map +1 -1
- package/dist/pipeline/standard-lighting/light-frame.d.ts +3 -3
- package/dist/pipeline/standard-lighting/light-frame.d.ts.map +1 -1
- package/dist/pipeline/standard-lighting/topology.d.ts +1 -1
- package/dist/pipeline/standard-lighting/topology.d.ts.map +1 -1
- package/dist/pipeline/standard-lighting/transport.d.ts.map +1 -1
- package/dist/pipeline/standard-pipeline.d.ts.map +1 -1
- package/dist/pipeline-builder.d.ts +2 -0
- package/dist/pipeline-builder.d.ts.map +1 -1
- package/dist/pipeline-spec.d.ts +1 -1
- package/dist/pipeline-spec.d.ts.map +1 -1
- package/dist/plugin.d.ts.map +1 -1
- package/dist/prepare/extended-lighting/ltc-resources.d.ts +31 -0
- package/dist/prepare/extended-lighting/ltc-resources.d.ts.map +1 -0
- package/dist/prepare/extended-lighting/resources.d.ts +72 -0
- package/dist/prepare/extended-lighting/resources.d.ts.map +1 -0
- package/dist/prepare/extended-lighting/spot-modifiers.d.ts +42 -0
- package/dist/prepare/extended-lighting/spot-modifiers.d.ts.map +1 -0
- package/dist/prepare/extended-lighting/state.d.ts +24 -0
- package/dist/prepare/extended-lighting/state.d.ts.map +1 -0
- package/dist/record/frame-lighting.d.ts +8 -6
- package/dist/record/frame-lighting.d.ts.map +1 -1
- package/dist/record/frame-snapshot.d.ts +50 -10
- package/dist/record/frame-snapshot.d.ts.map +1 -1
- package/dist/record/frame.d.ts +7 -3
- package/dist/record/frame.d.ts.map +1 -1
- package/dist/record/gpu-timing.d.ts +19 -7
- package/dist/record/gpu-timing.d.ts.map +1 -1
- package/dist/record/helpers.d.ts +0 -20
- package/dist/record/helpers.d.ts.map +1 -1
- package/dist/record/main-pass-geometry.d.ts +6 -1
- package/dist/record/main-pass-geometry.d.ts.map +1 -1
- package/dist/record/main-pass-material.d.ts +3 -1
- package/dist/record/main-pass-material.d.ts.map +1 -1
- package/dist/record/main-pass-sprite-draws.d.ts.map +1 -1
- package/dist/record/mesh-ssbo.d.ts.map +1 -1
- package/dist/record/render-context.d.ts +57 -6
- package/dist/record/render-context.d.ts.map +1 -1
- package/dist/record/shadow-pass.d.ts.map +1 -1
- package/dist/record/typed-frame-graph.d.ts +49 -2
- package/dist/record/typed-frame-graph.d.ts.map +1 -1
- package/dist/record/view-ubo.d.ts +1 -2
- package/dist/record/view-ubo.d.ts.map +1 -1
- package/dist/reflection/inspection.d.ts +10 -0
- package/dist/reflection/inspection.d.ts.map +1 -0
- package/dist/reflection/projection.d.ts +49 -0
- package/dist/reflection/projection.d.ts.map +1 -1
- package/dist/reflection/record-owner.d.ts +60 -0
- package/dist/reflection/record-owner.d.ts.map +1 -0
- package/dist/render-contract.d.ts +14 -8
- package/dist/render-contract.d.ts.map +1 -1
- package/dist/render-pipeline.d.ts +7 -0
- package/dist/render-pipeline.d.ts.map +1 -1
- package/dist/render-system-extract.d.ts +104 -16
- package/dist/render-system-extract.d.ts.map +1 -1
- package/dist/render-system.d.ts +12 -1
- package/dist/render-system.d.ts.map +1 -1
- package/dist/scene/probe-blend-record.d.ts +22 -0
- package/dist/scene/probe-blend-record.d.ts.map +1 -0
- package/dist/scene/probe-blend.d.ts +142 -0
- package/dist/scene/probe-blend.d.ts.map +1 -0
- package/dist/scene/render-scene-types.d.ts +0 -6
- package/dist/scene/render-scene-types.d.ts.map +1 -1
- package/dist/scene/render-scene.d.ts +103 -9
- package/dist/scene/render-scene.d.ts.map +1 -1
- package/dist/scene/visibility/bounds.d.ts +20 -0
- package/dist/scene/visibility/bounds.d.ts.map +1 -0
- package/dist/scene/visibility/budget.d.ts +16 -0
- package/dist/scene/visibility/budget.d.ts.map +1 -0
- package/dist/scene/visibility/facet.d.ts +73 -0
- package/dist/scene/visibility/facet.d.ts.map +1 -0
- package/dist/scene/visibility/gpu-frame-timing.d.ts +41 -0
- package/dist/scene/visibility/gpu-frame-timing.d.ts.map +1 -0
- package/dist/scene/visibility/gpu-lod.d.ts +46 -0
- package/dist/scene/visibility/gpu-lod.d.ts.map +1 -0
- package/dist/scene/visibility/inspection.d.ts +132 -0
- package/dist/scene/visibility/inspection.d.ts.map +1 -0
- package/dist/scene/visibility/lod-selector.d.ts +25 -0
- package/dist/scene/visibility/lod-selector.d.ts.map +1 -0
- package/dist/scene/visibility/occlusion-confidence.d.ts +81 -0
- package/dist/scene/visibility/occlusion-confidence.d.ts.map +1 -0
- package/dist/scene/visibility/occlusion-pass.d.ts +57 -0
- package/dist/scene/visibility/occlusion-pass.d.ts.map +1 -0
- package/dist/scene/visibility/occlusion-query-pool.d.ts +57 -0
- package/dist/scene/visibility/occlusion-query-pool.d.ts.map +1 -0
- package/dist/scene/visibility/occlusion-runtime.d.ts +96 -0
- package/dist/scene/visibility/occlusion-runtime.d.ts.map +1 -0
- package/dist/scene/visibility/types.d.ts +34 -0
- package/dist/scene/visibility/types.d.ts.map +1 -0
- package/dist/ssr/admission.d.ts +122 -0
- package/dist/ssr/admission.d.ts.map +1 -0
- package/dist/ssr/composition.d.ts +32 -0
- package/dist/ssr/composition.d.ts.map +1 -0
- package/dist/ssr/errors.d.ts +39 -0
- package/dist/ssr/errors.d.ts.map +1 -0
- package/dist/ssr/identity.d.ts +13 -0
- package/dist/ssr/identity.d.ts.map +1 -0
- package/dist/systems/skin-palette-allocator.d.ts +1 -1
- package/dist/temporal/frame-coordinator.d.ts +13 -0
- package/dist/temporal/frame-coordinator.d.ts.map +1 -1
- package/dist/temporal/frame.d.ts +2 -0
- package/dist/temporal/frame.d.ts.map +1 -1
- package/dist/temporal/index.mjs +6 -5
- package/dist/temporal/view.d.ts +7 -0
- package/dist/temporal/view.d.ts.map +1 -1
- package/dist/tilemap-chunk-extract-system.d.ts +1 -1
- package/dist/typed-render-graph-primitives.d.ts +4 -0
- package/dist/typed-render-graph-primitives.d.ts.map +1 -1
- package/dist/volume/passes.d.ts +8 -4
- package/dist/volume/passes.d.ts.map +1 -1
- package/package.json +20 -20
- package/src/__tests__/cluster-grid-default-surface.unit.test.ts +5 -0
- package/src/__tests__/detached-inspection.integration.test.ts +6 -0
- package/src/__tests__/device-feature-admission.unit.test.ts +13 -1
- package/src/__tests__/direct-light-snapshot.unit.test.ts +59 -3
- package/src/__tests__/environment-generation.integration.test.ts +16 -0
- package/src/__tests__/evidence-identity.ts +13 -0
- package/src/__tests__/evidence-identity.unit.test.ts +24 -0
- package/src/__tests__/extended-lighting-recovery.browser.test.ts +14 -0
- package/src/__tests__/extended-lighting-recovery.dawn.test.ts +14 -0
- package/src/__tests__/extended-lighting-recovery.integration.test.ts +81 -0
- package/src/__tests__/extended-lighting-resources.unit.test.ts +51 -0
- package/src/__tests__/extended-lighting-zero-feature.integration.test.ts +52 -0
- package/src/__tests__/factory-contract.integration.test.ts +33 -0
- package/src/__tests__/frame-observation.contract.test.ts +15 -0
- package/src/__tests__/gpu-driven-batch-topology-pbr.unit.test.ts +146 -0
- package/src/__tests__/gpu-driven-indirect-raster-evidence.ts +1 -0
- package/src/__tests__/gpu-driven-indirect-raster.dawn.test.ts +1 -0
- package/src/__tests__/gpu-driven-production.integration.test.ts +572 -9
- package/src/__tests__/gpu-driven-scaling.unit.test.ts +66 -2
- package/src/__tests__/gpu-driven-view-gpu-evidence.ts +26 -1
- package/src/__tests__/gpu-driven-view-graph.integration.test.ts +89 -2
- package/src/__tests__/gpu-driven-view.browser.test.ts +3 -3
- package/src/__tests__/gpu-driven-view.dawn.test.ts +3 -3
- package/src/__tests__/gpu-driven-view.unit.test.ts +50 -0
- package/src/__tests__/gpu-lod-evidence.ts +188 -0
- package/src/__tests__/gpu-lod-fallback.integration.test.ts +10 -0
- package/src/__tests__/gpu-lod-indirect.integration.test.ts +40 -0
- package/src/__tests__/gpu-lod-parity.dawn.test.ts +29 -0
- package/src/__tests__/gpu-lod-readiness.integration.test.ts +52 -0
- package/src/__tests__/gpu-lod-schema.unit.test.ts +66 -0
- package/src/__tests__/gpu-lod-selector.unit.test.ts +28 -0
- package/src/__tests__/gpu-lod-silhouette.browser.test.ts +13 -0
- package/src/__tests__/gpu-resource-store-stride.unit.test.ts +66 -1
- package/src/__tests__/gpu-scene.dawn.test.ts +8 -1
- package/src/__tests__/gpu-scene.unit.test.ts +49 -3
- package/src/__tests__/light-buffer-layout.unit.test.ts +113 -3
- package/src/__tests__/light-inspection.unit.test.ts +55 -0
- package/src/__tests__/light-resource-error.unit.test.ts +43 -0
- package/src/__tests__/lighting-scene-roundtrip.integration.test.ts +109 -0
- package/src/__tests__/lod-bounds.unit.test.ts +42 -0
- package/src/__tests__/lod-cpu-lane.integration.test.ts +55 -0
- package/src/__tests__/lod-cpu-no-change.perf.test.ts +19 -0
- package/src/__tests__/lod-gpu-frame-timing.unit.test.ts +49 -0
- package/src/__tests__/lod-multi-view.integration.test.ts +63 -0
- package/src/__tests__/lod-occlusion-device-loss.integration.test.ts +27 -0
- package/src/__tests__/lod-occlusion-final-decision.integration.test.ts +47 -0
- package/src/__tests__/lod-occlusion-inspection.integration.test.ts +217 -0
- package/src/__tests__/lod-occlusion-inspection.schema.test-d.ts +14 -0
- package/src/__tests__/lod-occlusion-inspection.unit.test.ts +72 -0
- package/src/__tests__/lod-occlusion-visual-evidence.ts +91 -0
- package/src/__tests__/lod-occlusion.browser.test.ts +15 -0
- package/src/__tests__/lod-occlusion.dawn.test.ts +20 -0
- package/src/__tests__/lod-selector.profile.test.ts +35 -0
- package/src/__tests__/lod-selector.unit.test.ts +68 -0
- package/src/__tests__/lod-visibility-identity.unit.test.ts +198 -0
- package/src/__tests__/lod-visibility-lifecycle.integration.test.ts +132 -0
- package/src/__tests__/ltc-resources.unit.test.ts +32 -0
- package/src/__tests__/material-contract-inventory.unit.test.ts +17 -0
- package/src/__tests__/occlusion-confidence.unit.test.ts +168 -0
- package/src/__tests__/occlusion-invalidation.integration.test.ts +37 -0
- package/src/__tests__/occlusion-pass-routing.unit.test.ts +16 -0
- package/src/__tests__/occlusion-pass.dawn.test.ts +20 -0
- package/src/__tests__/occlusion-pass.integration.test.ts +43 -0
- package/src/__tests__/occlusion-pass.rhi-null.test.ts +22 -0
- package/src/__tests__/occlusion-query-pool.rhi-null.test.ts +21 -0
- package/src/__tests__/occlusion-query-pool.unit.test.ts +95 -0
- package/src/__tests__/occlusion-query-ticket.integration.test.ts +47 -0
- package/src/__tests__/occlusion-query.dawn.test.ts +16 -0
- package/src/__tests__/occlusion-query.evidence.ts +178 -0
- package/src/__tests__/occlusion-query.rhi-null.test.ts +31 -0
- package/src/__tests__/occlusion-runtime.unit.test.ts +120 -0
- package/src/__tests__/prepared-gpu-driven-pbr.integration.test.ts +196 -0
- package/src/__tests__/probe-bindings.unit.test.ts +200 -0
- package/src/__tests__/probe-blend-numeric.unit.test.ts +67 -0
- package/src/__tests__/probe-blend-oracle.unit.test.ts +136 -0
- package/src/__tests__/probe-capacity.integration.test.ts +97 -0
- package/src/__tests__/probe-recovery.integration.test.ts +104 -0
- package/src/__tests__/probe-scene-dirty.integration.test.ts +211 -0
- package/src/__tests__/profiler-phase-catalog.test.ts +4 -1
- package/src/__tests__/profiler-phase-token.test.ts +1 -0
- package/src/__tests__/rect-area-boundary.unit.test.ts +24 -0
- package/src/__tests__/reflection-fallback-graph.unit.test.ts +67 -0
- package/src/__tests__/reflection-fallback-inspection.unit.test.ts +77 -0
- package/src/__tests__/reflection-fallback-lifecycle.integration.test.ts +21 -0
- package/src/__tests__/reflection-fallback-projection.unit.test.ts +90 -0
- package/src/__tests__/reflection-fallback-source.unit.test.ts +32 -0
- package/src/__tests__/reflection-probe-owner-placement.unit.test.ts +39 -0
- package/src/__tests__/reflection-probe-record-owner.characterization.unit.test.ts +120 -0
- package/src/__tests__/render-error-code-owner.test-d.ts +1 -0
- package/src/__tests__/render-feature-docs.unit.test.ts +12 -7
- package/src/__tests__/render-graph-fallback.integration.test.ts +24 -0
- package/src/__tests__/render-perf/extended-lighting.bench.test.ts +66 -0
- package/src/__tests__/render-scene-projection.unit.test.ts +447 -18
- package/src/__tests__/renderer-factory-material-contract.unit.test.ts +76 -0
- package/src/__tests__/skin-motion-regression.unit.test.ts +22 -0
- package/src/__tests__/skinned-shadow-caster.test.ts +2 -2
- package/src/__tests__/spot-modifier-projection.unit.test.ts +70 -0
- package/src/__tests__/ssr-admission-matrix.integration.test.ts +206 -0
- package/src/__tests__/ssr-composition.unit.test.ts +46 -0
- package/src/__tests__/ssr-fallback-zero-work.bench.test.ts +94 -0
- package/src/__tests__/ssr-recovery-errors.unit.test.ts +58 -0
- package/src/__tests__/standard-cluster-variant-resolution.unit.test.ts +67 -0
- package/src/__tests__/standard-clustered-pipeline.unit.test.ts +7 -0
- package/src/__tests__/standard-lighting-inspection.integration.test.ts +1 -1
- package/src/__tests__/standard-lighting-write.unit.test.ts +66 -2
- package/src/__tests__/temporal-fallback-generation.integration.test.ts +16 -0
- package/src/__tests__/temporal-view.unit.test.ts +3 -3
- package/src/__tests__/transmission-prewarm.unit.test.ts +69 -0
- package/src/__tests__/visibility-budget.integration.test.ts +140 -0
- package/src/__tests__/visibility-budget.unit.test.ts +70 -0
- package/src/__tests__/visibility-extract.integration.test.ts +11 -6
- package/src/__tests__/volumetric-fog-point-spot-accumulation.integration.test.ts +6 -3
- package/src/__tests__/volumetric-fog-stage-readback.dawn.test.ts +31 -28
- package/src/assembly/backend-contract.ts +13 -0
- package/src/assembly/device-feature-admission.ts +16 -9
- package/src/assembly/factory.ts +547 -93
- package/src/assembly/host-contract.ts +10 -0
- package/src/cluster-binner.ts +31 -0
- package/src/components/__tests__/lighting-authoring.unit.test.ts +39 -0
- package/src/components/__tests__/rect-area-light.unit.test.ts +33 -0
- package/src/components/index.ts +3 -0
- package/src/components/light-helpers.ts +52 -1
- package/src/components/light-probe.ts +13 -0
- package/src/components/rect-area-light.ts +15 -0
- package/src/components/scene-instance.ts +6 -0
- package/src/components/spot-light.ts +3 -0
- package/src/device/__tests__/extended-lighting-recovery.unit.test.ts +24 -0
- package/src/device/gpu-residency.ts +140 -9
- package/src/device/lifecycle-transaction.ts +12 -0
- package/src/environment/lifecycle.ts +8 -1
- package/src/errors/gpu-driven.ts +92 -0
- package/src/errors/index.ts +1 -0
- package/src/errors/recover.ts +32 -0
- package/src/errors/render.ts +55 -1
- package/src/extract/camera.ts +3 -3
- package/src/extract/gpu-driven.ts +108 -0
- package/src/extract/visibility.ts +0 -23
- package/src/gpu-driven/batch-topology.ts +206 -28
- package/src/gpu-driven/prepared-draw.ts +208 -0
- package/src/gpu-driven/production-raster.ts +953 -41
- package/src/gpu-driven/view-gpu.ts +411 -29
- package/src/gpu-scene-schema.ts +13 -0
- package/src/gpu-scene.ts +134 -65
- package/src/gpu-usage.ts +0 -1
- package/src/hdrp-buffers.ts +6 -6
- package/src/index.ts +74 -0
- package/src/inspection-types.ts +220 -1
- package/src/internal.ts +38 -0
- package/src/light-buffer-layout.ts +154 -324
- package/src/materials.ts +16 -2
- package/src/pbr-pipeline.ts +151 -45
- package/src/pipeline/standard-forward-lane.ts +47 -0
- package/src/pipeline/standard-lighting/graph.ts +2 -1
- package/src/pipeline/standard-lighting/light-frame.ts +3 -2
- package/src/pipeline/standard-lighting/topology.ts +1 -1
- package/src/pipeline/standard-lighting/transport.ts +2 -1
- package/src/pipeline/standard-pipeline.ts +2 -0
- package/src/pipeline-builder.ts +5 -2
- package/src/pipeline-spec.ts +12 -1
- package/src/plugin.ts +4 -0
- package/src/prepare/__tests__/extended-lighting-capability.unit.test.ts +56 -0
- package/src/prepare/extended-lighting/ltc-resources.ts +136 -0
- package/src/prepare/extended-lighting/resources.ts +389 -0
- package/src/prepare/extended-lighting/spot-modifiers.ts +194 -0
- package/src/prepare/extended-lighting/state.ts +92 -0
- package/src/record/__tests__/gpu-timing.unit.test.ts +177 -0
- package/src/record/__tests__/temporal-payload.unit.test.ts +23 -1
- package/src/record/__tests__/typed-frame-graph-plan.unit.test.ts +20 -1
- package/src/record/frame-lighting.ts +252 -53
- package/src/record/frame-snapshot.ts +57 -12
- package/src/record/frame.ts +410 -93
- package/src/record/gpu-timing.ts +108 -44
- package/src/record/helpers.ts +0 -58
- package/src/record/main-pass-geometry.ts +204 -39
- package/src/record/main-pass-material.ts +8 -1
- package/src/record/main-pass-sprite-draws.ts +52 -85
- package/src/record/mesh-ssbo.ts +47 -36
- package/src/record/render-context.ts +65 -4
- package/src/record/shadow-pass.ts +66 -40
- package/src/record/typed-frame-graph.ts +225 -83
- package/src/record/view-ubo.ts +14 -24
- package/src/reflection/inspection.ts +67 -0
- package/src/reflection/projection.ts +196 -1
- package/src/reflection/record-owner.ts +1283 -0
- package/src/render-contract.ts +17 -5
- package/src/render-pipeline.ts +5 -0
- package/src/render-system-extract.ts +493 -134
- package/src/render-system.ts +811 -615
- package/src/scene/__tests__/changed-block-summary.candidate.test.ts +36 -0
- package/src/scene/probe-blend-record.ts +54 -0
- package/src/scene/probe-blend.ts +813 -0
- package/src/scene/render-scene-types.ts +0 -7
- package/src/scene/render-scene.ts +848 -183
- package/src/scene/visibility/bounds.ts +57 -0
- package/src/scene/visibility/budget.ts +40 -0
- package/src/scene/visibility/facet.ts +400 -0
- package/src/scene/visibility/gpu-frame-timing.ts +101 -0
- package/src/scene/visibility/gpu-lod.ts +119 -0
- package/src/scene/visibility/inspection.ts +313 -0
- package/src/scene/visibility/lod-selector.ts +84 -0
- package/src/scene/visibility/occlusion-confidence.ts +478 -0
- package/src/scene/visibility/occlusion-pass.ts +165 -0
- package/src/scene/visibility/occlusion-query-pool.ts +178 -0
- package/src/scene/visibility/occlusion-runtime.ts +672 -0
- package/src/scene/visibility/types.ts +50 -0
- package/src/ssr/admission.ts +451 -0
- package/src/ssr/composition.ts +73 -0
- package/src/ssr/errors.ts +76 -0
- package/src/ssr/identity.ts +12 -0
- package/src/systems/skin-palette-allocator.ts +1 -1
- package/src/temporal/frame-coordinator.ts +26 -0
- package/src/temporal/frame.ts +14 -1
- package/src/temporal/view.ts +11 -0
- package/src/tilemap-chunk-extract-system.ts +4 -4
- package/src/typed-render-graph-primitives.ts +48 -0
- package/src/volume/passes.ts +46 -49
- package/dist/.tsbuildinfo +0 -1
- package/dist/chunk-5YADUCA7.mjs.map +0 -1
- package/dist/chunk-6OPXDQ2E.mjs.map +0 -1
- package/dist/chunk-BXBQQKFQ.mjs +0 -67
- package/dist/chunk-BXBQQKFQ.mjs.map +0 -1
- package/dist/chunk-FS2KNUQH.mjs.map +0 -1
- package/dist/chunk-PCHBPYML.mjs.map +0 -1
- package/dist/chunk-VFPLTKCU.mjs.map +0 -1
|
@@ -132,7 +132,7 @@ describe('TemporalView v1', () => {
|
|
|
132
132
|
} as unknown as ExtractedLights;
|
|
133
133
|
const buffer = {} as Parameters<typeof writeViewUbo>[1];
|
|
134
134
|
const first = createTemporalView({ antialias: 'taa', width: 4, height: 4, frameIndex: 0 });
|
|
135
|
-
writeViewUbo(queue, buffer, camera, light, lights, [],
|
|
135
|
+
writeViewUbo(queue, buffer, camera, light, lights, [], first);
|
|
136
136
|
expect(Array.from(uploads[0]?.slice(212, 228) ?? [])).toEqual(new Array(16).fill(0));
|
|
137
137
|
|
|
138
138
|
const previous = Float32Array.from({ length: 16 }, (_value, index) => index + 1);
|
|
@@ -143,10 +143,10 @@ describe('TemporalView v1', () => {
|
|
|
143
143
|
frameIndex: 1,
|
|
144
144
|
previousUnjitteredViewProjection: previous,
|
|
145
145
|
});
|
|
146
|
-
writeViewUbo(queue, buffer, camera, light, lights, [],
|
|
146
|
+
writeViewUbo(queue, buffer, camera, light, lights, [], second);
|
|
147
147
|
expect(Array.from(uploads[1]?.slice(212, 228) ?? [])).toEqual(Array.from(previous));
|
|
148
148
|
|
|
149
|
-
writeViewUbo(queue, buffer, camera, light, lights, [],
|
|
149
|
+
writeViewUbo(queue, buffer, camera, light, lights, [], second);
|
|
150
150
|
expect(Array.from(uploads[2]?.slice(212, 228) ?? [])).toEqual(Array.from(previous));
|
|
151
151
|
});
|
|
152
152
|
});
|
|
@@ -13,6 +13,10 @@ const hdrpFalseKey =
|
|
|
13
13
|
'CLUSTER_FORWARD_AVAILABLE=true+STORAGE_BUFFER_AVAILABLE=true+TRANSMISSION_AVAILABLE=false+VERTEX_COLOR_AVAILABLE=false';
|
|
14
14
|
const hdrpTrueKey =
|
|
15
15
|
'CLUSTER_FORWARD_AVAILABLE=true+STORAGE_BUFFER_AVAILABLE=true+TRANSMISSION_AVAILABLE=true+VERTEX_COLOR_AVAILABLE=false';
|
|
16
|
+
const probeFalseKey =
|
|
17
|
+
'CLUSTER_FORWARD_AVAILABLE=false+PROBE_BLEND_AVAILABLE=true+STORAGE_BUFFER_AVAILABLE=true+TRANSMISSION_AVAILABLE=false+VERTEX_COLOR_AVAILABLE=false';
|
|
18
|
+
const probeTrueKey =
|
|
19
|
+
'CLUSTER_FORWARD_AVAILABLE=false+PROBE_BLEND_AVAILABLE=true+STORAGE_BUFFER_AVAILABLE=true+TRANSMISSION_AVAILABLE=true+VERTEX_COLOR_AVAILABLE=false';
|
|
16
20
|
|
|
17
21
|
function standardEntry(
|
|
18
22
|
variants: readonly MaterialShaderManifestEntry['variants'][number][],
|
|
@@ -52,6 +56,33 @@ function hdrpVariant(definesKey: string, transmission: boolean) {
|
|
|
52
56
|
};
|
|
53
57
|
}
|
|
54
58
|
|
|
59
|
+
function probeTransmissionVariant(definesKey: string, transmission: boolean) {
|
|
60
|
+
const base = transmissionVariant(definesKey, transmission);
|
|
61
|
+
return {
|
|
62
|
+
...base,
|
|
63
|
+
definesKey,
|
|
64
|
+
defines: { ...base.defines, PROBE_BLEND_AVAILABLE: true },
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function capabilityTransmissionVariant(
|
|
69
|
+
definesKey: string,
|
|
70
|
+
transmission: boolean,
|
|
71
|
+
extendedLighting: boolean,
|
|
72
|
+
) {
|
|
73
|
+
const base = transmissionVariant(definesKey, transmission);
|
|
74
|
+
return {
|
|
75
|
+
...base,
|
|
76
|
+
definesKey,
|
|
77
|
+
defines: {
|
|
78
|
+
...base.defines,
|
|
79
|
+
EXTENDED_LIGHTING_AVAILABLE: extendedLighting,
|
|
80
|
+
PROJECTOR_AVAILABLE: true,
|
|
81
|
+
},
|
|
82
|
+
composedWgsl: `standard-${extendedLighting ? 'extended' : 'fallback'}-${transmission}`,
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
|
|
55
86
|
describe('Standard transmission exact-key prewarm selection', () => {
|
|
56
87
|
it('returns both declared variants through exact manifest lookup', () => {
|
|
57
88
|
const entry = standardEntry([
|
|
@@ -74,6 +105,44 @@ describe('Standard transmission exact-key prewarm selection', () => {
|
|
|
74
105
|
'manifest row is missing',
|
|
75
106
|
);
|
|
76
107
|
});
|
|
108
|
+
|
|
109
|
+
it('keeps object-level probe variants out of the boot prewarm selection', () => {
|
|
110
|
+
const entry = standardEntry([
|
|
111
|
+
probeTransmissionVariant(probeFalseKey, false),
|
|
112
|
+
transmissionVariant(falseKey, false),
|
|
113
|
+
probeTransmissionVariant(probeTrueKey, true),
|
|
114
|
+
transmissionVariant(trueKey, true),
|
|
115
|
+
]);
|
|
116
|
+
expect(
|
|
117
|
+
selectStandardPbrTransmissionPrewarmVariants(entry, true).map(
|
|
118
|
+
(variant) => variant.definesKey,
|
|
119
|
+
),
|
|
120
|
+
).toEqual([falseKey, trueKey]);
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
it('selects the prewarm pair for the admitted extended-lighting capability', () => {
|
|
124
|
+
const fallbackFalseKey = `${falseKey}+EXTENDED_LIGHTING_AVAILABLE=false+PROJECTOR_AVAILABLE=true`;
|
|
125
|
+
const fallbackTrueKey = `${trueKey}+EXTENDED_LIGHTING_AVAILABLE=false+PROJECTOR_AVAILABLE=true`;
|
|
126
|
+
const extendedFalseKey = `${falseKey}+EXTENDED_LIGHTING_AVAILABLE=true+PROJECTOR_AVAILABLE=true`;
|
|
127
|
+
const extendedTrueKey = `${trueKey}+EXTENDED_LIGHTING_AVAILABLE=true+PROJECTOR_AVAILABLE=true`;
|
|
128
|
+
const entry = standardEntry([
|
|
129
|
+
capabilityTransmissionVariant(fallbackFalseKey, false, false),
|
|
130
|
+
capabilityTransmissionVariant(fallbackTrueKey, true, false),
|
|
131
|
+
capabilityTransmissionVariant(extendedFalseKey, false, true),
|
|
132
|
+
capabilityTransmissionVariant(extendedTrueKey, true, true),
|
|
133
|
+
]);
|
|
134
|
+
|
|
135
|
+
expect(
|
|
136
|
+
selectStandardPbrTransmissionPrewarmVariants(entry, true, true, true, false).map(
|
|
137
|
+
(variant) => variant.definesKey,
|
|
138
|
+
),
|
|
139
|
+
).toEqual([fallbackFalseKey, fallbackTrueKey]);
|
|
140
|
+
expect(
|
|
141
|
+
selectStandardPbrTransmissionPrewarmVariants(entry, true, true, true, true).map(
|
|
142
|
+
(variant) => variant.definesKey,
|
|
143
|
+
),
|
|
144
|
+
).toEqual([extendedFalseKey, extendedTrueKey]);
|
|
145
|
+
});
|
|
77
146
|
});
|
|
78
147
|
|
|
79
148
|
describe('HDRP PBR prewarm capability selection', () => {
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import { createVisibilityBudget } from '../scene/visibility/budget';
|
|
3
|
+
import {
|
|
4
|
+
primitiveKey,
|
|
5
|
+
primitiveKeyId,
|
|
6
|
+
VisibilityFacetStore,
|
|
7
|
+
viewKey,
|
|
8
|
+
viewKeyId,
|
|
9
|
+
} from '../scene/visibility/facet';
|
|
10
|
+
|
|
11
|
+
const view = (cameraEntity: number) =>
|
|
12
|
+
viewKey({
|
|
13
|
+
attachmentId: 'budget-scene',
|
|
14
|
+
cameraEntity,
|
|
15
|
+
viewRole: 'main',
|
|
16
|
+
viewGeneration: 1,
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
const primitive = (slot: number) =>
|
|
20
|
+
primitiveKey({
|
|
21
|
+
attachmentId: 'budget-scene',
|
|
22
|
+
worldGeneration: 1,
|
|
23
|
+
primitiveSlot: slot,
|
|
24
|
+
slotGeneration: 1,
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
describe('visibility budget integration', () => {
|
|
28
|
+
it('shares one derived window across views and LOD levels', () => {
|
|
29
|
+
const budget = createVisibilityBudget(2048);
|
|
30
|
+
const facets = new VisibilityFacetStore(budget);
|
|
31
|
+
const views = [view(1), view(2)];
|
|
32
|
+
for (const currentView of views) {
|
|
33
|
+
facets.activateView(currentView);
|
|
34
|
+
for (let level = 0; level < 8; level += 1) {
|
|
35
|
+
const currentPrimitive = primitive(currentView.cameraEntity * 10 + level);
|
|
36
|
+
facets.setCandidate(currentView, currentPrimitive, { level, confidence: 1 });
|
|
37
|
+
facets.applyConfidence(currentView, currentPrimitive, {
|
|
38
|
+
type: 'result',
|
|
39
|
+
samples: 0,
|
|
40
|
+
submissionGeneration: 1,
|
|
41
|
+
});
|
|
42
|
+
facets.applyConfidence(currentView, currentPrimitive, {
|
|
43
|
+
type: 'result',
|
|
44
|
+
samples: 0,
|
|
45
|
+
submissionGeneration: 2,
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
expect(facets.visibilityBudget()).toBe(budget);
|
|
51
|
+
expect(facets.visibilityBudget()).toMatchObject({
|
|
52
|
+
effectiveQueryBudget: 2048,
|
|
53
|
+
settleSubmits: 98,
|
|
54
|
+
retestSubmits: 44,
|
|
55
|
+
expirySubmits: 88,
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
facets.advanceSuccessfulSubmits(2 + budget.retestSubmits);
|
|
59
|
+
for (const currentView of views) {
|
|
60
|
+
expect(facets.shouldQuery(currentView, primitive(currentView.cameraEntity * 10))).toBe(true);
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it('keeps invalidation visible and requeues the same identity without extending evidence', () => {
|
|
65
|
+
const budget = createVisibilityBudget(4096);
|
|
66
|
+
const facets = new VisibilityFacetStore(budget);
|
|
67
|
+
const currentView = view(3);
|
|
68
|
+
const currentPrimitive = primitive(3);
|
|
69
|
+
facets.activateView(currentView);
|
|
70
|
+
facets.setCandidate(currentView, currentPrimitive, { level: 2, confidence: 1 });
|
|
71
|
+
facets.applyConfidence(currentView, currentPrimitive, {
|
|
72
|
+
type: 'result',
|
|
73
|
+
samples: 0,
|
|
74
|
+
submissionGeneration: 1,
|
|
75
|
+
});
|
|
76
|
+
facets.applyConfidence(currentView, currentPrimitive, {
|
|
77
|
+
type: 'result',
|
|
78
|
+
samples: 0,
|
|
79
|
+
submissionGeneration: 2,
|
|
80
|
+
});
|
|
81
|
+
facets.advanceSuccessfulSubmits(2 + budget.retestSubmits, [
|
|
82
|
+
{ view: currentView, primitive: currentPrimitive },
|
|
83
|
+
]);
|
|
84
|
+
expect(facets.getConfidence(currentView, currentPrimitive).status).toBe('hidden');
|
|
85
|
+
|
|
86
|
+
facets.applyConfidence(currentView, currentPrimitive, {
|
|
87
|
+
type: 'invalidate',
|
|
88
|
+
reason: 'world-reorder',
|
|
89
|
+
});
|
|
90
|
+
expect(facets.getConfidence(currentView, currentPrimitive)).toMatchObject({
|
|
91
|
+
status: 'visible',
|
|
92
|
+
dirty: true,
|
|
93
|
+
queryable: true,
|
|
94
|
+
});
|
|
95
|
+
expect(facets.dequeueQueryCandidates(currentView, 1)).toHaveLength(1);
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
it('uses expiry-only scheduling for a due hidden row while its query is in flight', () => {
|
|
99
|
+
const budget = createVisibilityBudget();
|
|
100
|
+
const facets = new VisibilityFacetStore(budget);
|
|
101
|
+
const currentView = view(4);
|
|
102
|
+
const currentPrimitive = primitive(4);
|
|
103
|
+
facets.activateView(currentView);
|
|
104
|
+
facets.setCandidate(currentView, currentPrimitive, { level: 0, confidence: 1 });
|
|
105
|
+
facets.applyConfidence(currentView, currentPrimitive, {
|
|
106
|
+
type: 'result',
|
|
107
|
+
samples: 0,
|
|
108
|
+
submissionGeneration: 1,
|
|
109
|
+
});
|
|
110
|
+
facets.applyConfidence(currentView, currentPrimitive, {
|
|
111
|
+
type: 'result',
|
|
112
|
+
samples: 0,
|
|
113
|
+
submissionGeneration: 2,
|
|
114
|
+
});
|
|
115
|
+
const dueGeneration = 2 + budget.retestSubmits;
|
|
116
|
+
facets.advanceSuccessfulSubmits(dueGeneration);
|
|
117
|
+
expect(facets.dequeueQueryCandidates(currentView, 1)).toHaveLength(1);
|
|
118
|
+
|
|
119
|
+
facets.applyConfidence(currentView, currentPrimitive, {
|
|
120
|
+
type: 'submit',
|
|
121
|
+
submissionGeneration: dueGeneration,
|
|
122
|
+
});
|
|
123
|
+
expect(facets.getConfidence(currentView, currentPrimitive).successfulSubmits).toBe(
|
|
124
|
+
budget.retestSubmits + 1,
|
|
125
|
+
);
|
|
126
|
+
const scheduler = facets as unknown as {
|
|
127
|
+
confidence: { wakeByGeneration: Map<number, Set<string>> };
|
|
128
|
+
};
|
|
129
|
+
const key = `${viewKeyId(currentView)}|${primitiveKeyId(currentPrimitive)}`;
|
|
130
|
+
expect([...scheduler.confidence.wakeByGeneration.values()].flat()).not.toContain(key);
|
|
131
|
+
|
|
132
|
+
facets.advanceSuccessfulSubmits(
|
|
133
|
+
dueGeneration + budget.expirySubmits - budget.retestSubmits - 1,
|
|
134
|
+
);
|
|
135
|
+
expect(facets.getConfidence(currentView, currentPrimitive)).toMatchObject({
|
|
136
|
+
status: 'visible',
|
|
137
|
+
dirty: true,
|
|
138
|
+
});
|
|
139
|
+
});
|
|
140
|
+
});
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import {
|
|
3
|
+
createVisibilityBudget,
|
|
4
|
+
DEFAULT_CONFIGURED_QUERY_BUDGET,
|
|
5
|
+
MAX_QUERY_BUDGET,
|
|
6
|
+
} from '../scene/visibility/budget';
|
|
7
|
+
|
|
8
|
+
describe('visibility budget derivation', () => {
|
|
9
|
+
it.each([
|
|
10
|
+
[
|
|
11
|
+
2048,
|
|
12
|
+
{
|
|
13
|
+
effectiveQueryBudget: 2048,
|
|
14
|
+
oneSweepCandidates: 49,
|
|
15
|
+
oneSweepOccluded: 44,
|
|
16
|
+
settleSubmits: 98,
|
|
17
|
+
retestSubmits: 44,
|
|
18
|
+
expirySubmits: 88,
|
|
19
|
+
},
|
|
20
|
+
],
|
|
21
|
+
[
|
|
22
|
+
4096,
|
|
23
|
+
{
|
|
24
|
+
effectiveQueryBudget: 4096,
|
|
25
|
+
oneSweepCandidates: 25,
|
|
26
|
+
oneSweepOccluded: 22,
|
|
27
|
+
settleSubmits: 50,
|
|
28
|
+
retestSubmits: 22,
|
|
29
|
+
expirySubmits: 44,
|
|
30
|
+
},
|
|
31
|
+
],
|
|
32
|
+
])('derives the approved windows for Q=%d', (configuredQueryBudget, expected) => {
|
|
33
|
+
expect(createVisibilityBudget(configuredQueryBudget)).toMatchObject({
|
|
34
|
+
configuredQueryBudget,
|
|
35
|
+
...expected,
|
|
36
|
+
});
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it('uses the default and clamps larger configured budgets without changing page policy', () => {
|
|
40
|
+
expect(createVisibilityBudget()).toMatchObject({
|
|
41
|
+
configuredQueryBudget: DEFAULT_CONFIGURED_QUERY_BUDGET,
|
|
42
|
+
effectiveQueryBudget: DEFAULT_CONFIGURED_QUERY_BUDGET,
|
|
43
|
+
});
|
|
44
|
+
expect(createVisibilityBudget(MAX_QUERY_BUDGET + 1).effectiveQueryBudget).toBe(
|
|
45
|
+
MAX_QUERY_BUDGET,
|
|
46
|
+
);
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it.each([
|
|
50
|
+
0,
|
|
51
|
+
-1,
|
|
52
|
+
1.5,
|
|
53
|
+
Number.NaN,
|
|
54
|
+
Number.POSITIVE_INFINITY,
|
|
55
|
+
])('rejects invalid configured budget %s', (configuredQueryBudget) => {
|
|
56
|
+
expect(() => createVisibilityBudget(configuredQueryBudget)).toThrow(
|
|
57
|
+
'configuredQueryBudget must be a positive safe integer',
|
|
58
|
+
);
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it.each([1, 2, 3, 4, 8])('keeps derived windows independent of %d LOD levels', (levels) => {
|
|
62
|
+
const budget = createVisibilityBudget(2048);
|
|
63
|
+
expect({ levels, ...budget }).toMatchObject({
|
|
64
|
+
levels,
|
|
65
|
+
settleSubmits: 98,
|
|
66
|
+
retestSubmits: 44,
|
|
67
|
+
expirySubmits: 88,
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
});
|
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
import { World } from '@forgeax/engine-ecs';
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
ChildOf,
|
|
4
|
+
GlobalTransform,
|
|
5
|
+
registerPropagateTransforms,
|
|
6
|
+
Transform,
|
|
7
|
+
} from '@forgeax/engine-scene';
|
|
3
8
|
import { describe, expect, it, vi } from 'vitest';
|
|
4
9
|
import { Fog } from '../components/fog';
|
|
5
10
|
import { Visibility, VisibilityStateValue } from '../components/visibility';
|
|
@@ -67,13 +72,13 @@ describe('visibility extract orchestration', () => {
|
|
|
67
72
|
const snapshot = frame.visibilitySnapshots[0];
|
|
68
73
|
expect(snapshot?.get(parent)?.effective).toBe('visible');
|
|
69
74
|
expect(snapshot?.get(child)?.effective).toBe('visible');
|
|
70
|
-
expect(world.get(child,
|
|
75
|
+
expect(world.get(child, GlobalTransform).unwrap().world[12]).toBeCloseTo(3);
|
|
71
76
|
});
|
|
72
77
|
|
|
73
|
-
it('keeps renderer extraction read-only over derived
|
|
78
|
+
it('keeps renderer extraction read-only over derived GlobalTransform.world', () => {
|
|
74
79
|
const { world, parent, child } = makeWorld();
|
|
75
80
|
world.update(0).unwrap();
|
|
76
|
-
const before = [...world.get(child,
|
|
81
|
+
const before = [...world.get(child, GlobalTransform).unwrap().world];
|
|
77
82
|
const beforeInspection = world.inspect();
|
|
78
83
|
const beforeShape = {
|
|
79
84
|
entityCount: beforeInspection.entityCount,
|
|
@@ -87,7 +92,7 @@ describe('visibility extract orchestration', () => {
|
|
|
87
92
|
world.set(parent, Transform, { pos: [9, 0, 0] }).unwrap();
|
|
88
93
|
extractFrames([world], 0);
|
|
89
94
|
|
|
90
|
-
expect([...world.get(child,
|
|
95
|
+
expect([...world.get(child, GlobalTransform).unwrap().world]).toEqual(before);
|
|
91
96
|
const afterInspection = world.inspect();
|
|
92
97
|
expect({
|
|
93
98
|
entityCount: afterInspection.entityCount,
|
|
@@ -98,7 +103,7 @@ describe('visibility extract orchestration', () => {
|
|
|
98
103
|
resourceKeys: afterInspection.resourceKeys,
|
|
99
104
|
}).toEqual(beforeShape);
|
|
100
105
|
world.update(0).unwrap();
|
|
101
|
-
expect(world.get(child,
|
|
106
|
+
expect(world.get(child, GlobalTransform).unwrap().world[12]).toBeCloseTo(11);
|
|
102
107
|
});
|
|
103
108
|
|
|
104
109
|
it('keeps direct prepared-kernel output aligned with extractFrames output', () => {
|
|
@@ -13,8 +13,10 @@ const passes = readFileSync(new URL('../volume/passes.ts', import.meta.url), 'ut
|
|
|
13
13
|
|
|
14
14
|
describe('volumetric fog Point and Spot accumulation', () => {
|
|
15
15
|
it('accumulates Point and Spot in one fixed inject stage', () => {
|
|
16
|
-
expect(inject).toContain('
|
|
17
|
-
expect(inject).toContain('
|
|
16
|
+
expect(inject).toContain('light_data');
|
|
17
|
+
expect(inject).toContain('cluster_uniform');
|
|
18
|
+
expect(inject).not.toContain('pointLightsBuffer');
|
|
19
|
+
expect(inject).not.toContain('spotLightsBuffer');
|
|
18
20
|
expect(inject).toContain('evalVolumePoint');
|
|
19
21
|
expect(inject).toContain('evalVolumeSpot');
|
|
20
22
|
expect(inject).toContain('shadow_visibility');
|
|
@@ -37,7 +39,8 @@ describe('volumetric fog Point and Spot accumulation', () => {
|
|
|
37
39
|
});
|
|
38
40
|
|
|
39
41
|
it('retains falsifier hooks for off lights, occluders, and shadow visibility', () => {
|
|
40
|
-
expect(inject).toContain('
|
|
42
|
+
expect(inject).toContain('selected_cluster_light_slot');
|
|
43
|
+
expect(inject).toContain('cluster_uniform.grid.w');
|
|
41
44
|
expect(inject).toContain('shadowAtlasTile');
|
|
42
45
|
expect(inject).toContain('return 0.0');
|
|
43
46
|
expect(integrate).toContain('evalSpotAttenuation');
|
|
@@ -2,12 +2,7 @@ import type { RhiDevice, Texture, TextureView } from '@forgeax/engine-rhi';
|
|
|
2
2
|
import { createShaderModule, rhi } from '@forgeax/engine-rhi-webgpu';
|
|
3
3
|
import { buildEngineShaderManifest } from '@forgeax/engine-vite-plugin-shader';
|
|
4
4
|
import { describe, expect, it } from 'vitest';
|
|
5
|
-
import {
|
|
6
|
-
LIGHT_ARRAY_HEADER_BYTES,
|
|
7
|
-
LIGHT_ARRAY_MAX_SLOTS,
|
|
8
|
-
POINT_LIGHT_STD430_BYTES,
|
|
9
|
-
SPOT_LIGHT_STD430_BYTES,
|
|
10
|
-
} from '../light-buffer-layout';
|
|
5
|
+
import { BYTES_PER_DIRECT_LIGHT_SLOT } from '../light-buffer-layout';
|
|
11
6
|
|
|
12
7
|
const MAP_READ = 0x0001;
|
|
13
8
|
const BUFFER_COPY_DST = 0x0008;
|
|
@@ -21,6 +16,9 @@ const SIZE = 8;
|
|
|
21
16
|
const PACKED_LAYERS = Math.ceil(SIZE / 4);
|
|
22
17
|
const BYTES_PER_ROW = 256;
|
|
23
18
|
const BYTES_PER_PIXEL = 8;
|
|
19
|
+
const MAX_CLUSTER_LIGHTS = 256;
|
|
20
|
+
const CLUSTER_LIGHT_DATA_BYTES = MAX_CLUSTER_LIGHTS * BYTES_PER_DIRECT_LIGHT_SLOT;
|
|
21
|
+
const CLUSTER_UNIFORM_BYTES = 32;
|
|
24
22
|
const engineManifest = await buildEngineShaderManifest();
|
|
25
23
|
|
|
26
24
|
interface StageValues {
|
|
@@ -190,15 +188,15 @@ async function runInjectReadback(sceneDepthClear = 1): Promise<VolumeStageReadba
|
|
|
190
188
|
size: 128,
|
|
191
189
|
usage: 0x0040 | BUFFER_COPY_DST,
|
|
192
190
|
});
|
|
193
|
-
const
|
|
194
|
-
label: 'stage-readback.
|
|
195
|
-
size:
|
|
191
|
+
const lightDataBuffer = device.createBuffer({
|
|
192
|
+
label: 'stage-readback.cluster-light-data',
|
|
193
|
+
size: CLUSTER_LIGHT_DATA_BYTES,
|
|
196
194
|
usage: STORAGE_BUFFER | BUFFER_COPY_DST,
|
|
197
195
|
});
|
|
198
|
-
const
|
|
199
|
-
label: 'stage-readback.
|
|
200
|
-
size:
|
|
201
|
-
usage:
|
|
196
|
+
const clusterUniformBuffer = device.createBuffer({
|
|
197
|
+
label: 'stage-readback.cluster-uniform',
|
|
198
|
+
size: CLUSTER_UNIFORM_BYTES,
|
|
199
|
+
usage: 0x0040 | BUFFER_COPY_DST,
|
|
202
200
|
});
|
|
203
201
|
const injectReadback = device.createBuffer({
|
|
204
202
|
label: 'stage-readback.inject',
|
|
@@ -218,8 +216,8 @@ async function runInjectReadback(sceneDepthClear = 1): Promise<VolumeStageReadba
|
|
|
218
216
|
if (
|
|
219
217
|
!viewBuffer.ok ||
|
|
220
218
|
!paramsBuffer.ok ||
|
|
221
|
-
!
|
|
222
|
-
!
|
|
219
|
+
!lightDataBuffer.ok ||
|
|
220
|
+
!clusterUniformBuffer.ok ||
|
|
223
221
|
!injectReadback.ok ||
|
|
224
222
|
!temporalReadback.ok ||
|
|
225
223
|
!integrateReadback.ok
|
|
@@ -245,19 +243,22 @@ async function runInjectReadback(sceneDepthClear = 1): Promise<VolumeStageReadba
|
|
|
245
243
|
paramsData.set([0, -1, 0, 0], 20);
|
|
246
244
|
paramsData.set([1, 1, 1, 0], 24);
|
|
247
245
|
paramsData.set([2, 0, 0, 0], 28);
|
|
246
|
+
const lightData = new Uint8Array(CLUSTER_LIGHT_DATA_BYTES);
|
|
247
|
+
const clusterUniformData = new Float32Array(8);
|
|
248
|
+
const clusterGrid = new Uint32Array(clusterUniformData.buffer);
|
|
249
|
+
clusterGrid[0] = 1;
|
|
250
|
+
clusterGrid[1] = 1;
|
|
251
|
+
clusterGrid[2] = 1;
|
|
252
|
+
clusterGrid[3] = 1;
|
|
248
253
|
const viewWrite = device.queue.writeBuffer(viewBuffer.value, 0, viewData);
|
|
249
254
|
const paramsWrite = device.queue.writeBuffer(paramsBuffer.value, 0, paramsData);
|
|
250
|
-
const
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
new Uint32Array([0, 0, 0, 0]),
|
|
254
|
-
);
|
|
255
|
-
const pointLightsWrite = device.queue.writeBuffer(
|
|
256
|
-
pointLightsBuffer.value,
|
|
255
|
+
const lightDataWrite = device.queue.writeBuffer(lightDataBuffer.value, 0, lightData);
|
|
256
|
+
const clusterUniformWrite = device.queue.writeBuffer(
|
|
257
|
+
clusterUniformBuffer.value,
|
|
257
258
|
0,
|
|
258
|
-
|
|
259
|
+
clusterUniformData,
|
|
259
260
|
);
|
|
260
|
-
if (!viewWrite.ok || !paramsWrite.ok || !
|
|
261
|
+
if (!viewWrite.ok || !paramsWrite.ok || !lightDataWrite.ok || !clusterUniformWrite.ok)
|
|
261
262
|
throw new Error('Dawn volume stage readback unavailable: uniform upload failed');
|
|
262
263
|
const densityData = new Uint8Array((BYTES_PER_PIXEL / 2) * SIZE * SIZE * SIZE);
|
|
263
264
|
densityData.fill(255);
|
|
@@ -291,6 +292,7 @@ async function runInjectReadback(sceneDepthClear = 1): Promise<VolumeStageReadba
|
|
|
291
292
|
storageTexture: { access: 'write-only', format: 'rgba8unorm', viewDimension: '2d-array' },
|
|
292
293
|
},
|
|
293
294
|
{ binding: 7, visibility: 4, buffer: { type: 'read-only-storage' } },
|
|
295
|
+
{ binding: 8, visibility: 4, buffer: { type: 'uniform' } },
|
|
294
296
|
],
|
|
295
297
|
});
|
|
296
298
|
if (!layout.ok) throw layout.error;
|
|
@@ -354,7 +356,7 @@ async function runInjectReadback(sceneDepthClear = 1): Promise<VolumeStageReadba
|
|
|
354
356
|
storageTexture: { access: 'write-only', format: 'rgba16float', viewDimension: '2d' },
|
|
355
357
|
},
|
|
356
358
|
{ binding: 10, visibility: 4, buffer: { type: 'read-only-storage' } },
|
|
357
|
-
{ binding: 11, visibility: 4, buffer: { type: '
|
|
359
|
+
{ binding: 11, visibility: 4, buffer: { type: 'uniform' } },
|
|
358
360
|
{ binding: 12, visibility: 4, texture: { sampleType: 'float', viewDimension: '2d' } },
|
|
359
361
|
{ binding: 13, visibility: 4, sampler: { type: 'filtering' } },
|
|
360
362
|
],
|
|
@@ -393,7 +395,8 @@ async function runInjectReadback(sceneDepthClear = 1): Promise<VolumeStageReadba
|
|
|
393
395
|
{ binding: 4, resource: { kind: 'sampler', value: comparisonSampler.value } },
|
|
394
396
|
{ binding: 5, resource: { kind: 'buffer', value: { buffer: paramsBuffer.value } } },
|
|
395
397
|
{ binding: 6, resource: { kind: 'textureView', value: outputView } },
|
|
396
|
-
{ binding: 7, resource: { kind: 'buffer', value: { buffer:
|
|
398
|
+
{ binding: 7, resource: { kind: 'buffer', value: { buffer: lightDataBuffer.value } } },
|
|
399
|
+
{ binding: 8, resource: { kind: 'buffer', value: { buffer: clusterUniformBuffer.value } } },
|
|
397
400
|
],
|
|
398
401
|
});
|
|
399
402
|
if (!bindings.ok) throw bindings.error;
|
|
@@ -420,8 +423,8 @@ async function runInjectReadback(sceneDepthClear = 1): Promise<VolumeStageReadba
|
|
|
420
423
|
{ binding: 7, resource: { kind: 'sampler', value: densitySampler.value } },
|
|
421
424
|
{ binding: 8, resource: { kind: 'textureView', value: historyView } },
|
|
422
425
|
{ binding: 9, resource: { kind: 'textureView', value: temporalView } },
|
|
423
|
-
{ binding: 10, resource: { kind: 'buffer', value: { buffer:
|
|
424
|
-
{ binding: 11, resource: { kind: 'buffer', value: { buffer:
|
|
426
|
+
{ binding: 10, resource: { kind: 'buffer', value: { buffer: lightDataBuffer.value } } },
|
|
427
|
+
{ binding: 11, resource: { kind: 'buffer', value: { buffer: clusterUniformBuffer.value } } },
|
|
425
428
|
{ binding: 12, resource: { kind: 'textureView', value: projectorView } },
|
|
426
429
|
{ binding: 13, resource: { kind: 'sampler', value: densitySampler.value } },
|
|
427
430
|
],
|
|
@@ -10,6 +10,19 @@ import type {
|
|
|
10
10
|
/** Optional host hooks for recorder and device-lifecycle capabilities. */
|
|
11
11
|
export interface RhiBackendInstrumentation {
|
|
12
12
|
readonly resolveSurfaceDevice?: (device: RhiDevice) => Result<RhiDevice, RhiError>;
|
|
13
|
+
/**
|
|
14
|
+
* Optional deterministic submit fault seam for backend-owned integration
|
|
15
|
+
* fixtures. The callback runs after `finish()` and before the queue submit;
|
|
16
|
+
* returning an error aborts the frame transaction without changing the
|
|
17
|
+
* production queue contract.
|
|
18
|
+
*/
|
|
19
|
+
readonly beforeSubmit?: (device: RhiDevice) => RhiError | undefined;
|
|
20
|
+
/**
|
|
21
|
+
* Optional device-loss projection for deterministic recovery fixtures. A
|
|
22
|
+
* backend may compose this promise with its native `device.lost` promise;
|
|
23
|
+
* normal production packs leave it undefined and use the native signal.
|
|
24
|
+
*/
|
|
25
|
+
readonly deviceLost?: (device: RhiDevice) => RhiDevice['lost'];
|
|
13
26
|
readonly onFrameBoundary?: () => void;
|
|
14
27
|
readonly onDeviceLost?: () => void;
|
|
15
28
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { RhiAdapter, RhiDevice } from '@forgeax/engine-rhi';
|
|
2
|
+
import { EXTENDED_LIGHTING_REQUIRED_SAMPLED_TEXTURES } from '../prepare/extended-lighting/resources';
|
|
2
3
|
|
|
3
4
|
const COMPRESSION_FEATURES: GPUFeatureName[] = [
|
|
4
5
|
'texture-compression-bc',
|
|
@@ -9,7 +10,9 @@ const COMPRESSION_FEATURES: GPUFeatureName[] = [
|
|
|
9
10
|
// The Standard transmission fragment ABI needs 17 sampled textures across its
|
|
10
11
|
// material, IBL, clustered-light, and SSAO bindings. Ordinary Standard draws
|
|
11
12
|
// use the non-transmission variant and remain valid on the WebGPU minimum of
|
|
12
|
-
// 16
|
|
13
|
+
// 16. The extended-lighting topology reserves 20, so a device descriptor must
|
|
14
|
+
// request that larger limit when the adapter can provide it; adapter limits are
|
|
15
|
+
// not automatically inherited by requestDevice().
|
|
13
16
|
export const STANDARD_PBR_REQUIRED_SAMPLED_TEXTURES = 17;
|
|
14
17
|
|
|
15
18
|
export interface DeviceFeatureAdmissionOptions {
|
|
@@ -36,18 +39,22 @@ export function deriveDeviceFeatureAdmission(
|
|
|
36
39
|
if (timestampRequested && adapter.features.has('timestamp-query')) {
|
|
37
40
|
requiredFeatures.push('timestamp-query');
|
|
38
41
|
}
|
|
39
|
-
const
|
|
40
|
-
|
|
41
|
-
|
|
42
|
+
const adapterSampledTextureLimit = adapter.limits?.maxSampledTexturesPerShaderStage ?? 0;
|
|
43
|
+
const requiredSampledTextureLimit =
|
|
44
|
+
adapterSampledTextureLimit >= EXTENDED_LIGHTING_REQUIRED_SAMPLED_TEXTURES
|
|
45
|
+
? EXTENDED_LIGHTING_REQUIRED_SAMPLED_TEXTURES
|
|
46
|
+
: adapterSampledTextureLimit >= STANDARD_PBR_REQUIRED_SAMPLED_TEXTURES
|
|
47
|
+
? STANDARD_PBR_REQUIRED_SAMPLED_TEXTURES
|
|
48
|
+
: undefined;
|
|
42
49
|
return {
|
|
43
50
|
requiredFeatures,
|
|
44
|
-
...(
|
|
45
|
-
? {
|
|
51
|
+
...(requiredSampledTextureLimit === undefined
|
|
52
|
+
? {}
|
|
53
|
+
: {
|
|
46
54
|
requiredLimits: {
|
|
47
|
-
maxSampledTexturesPerShaderStage:
|
|
55
|
+
maxSampledTexturesPerShaderStage: requiredSampledTextureLimit,
|
|
48
56
|
},
|
|
49
|
-
}
|
|
50
|
-
: {}),
|
|
57
|
+
}),
|
|
51
58
|
};
|
|
52
59
|
}
|
|
53
60
|
|