@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
package/src/record/frame.ts
CHANGED
|
@@ -29,11 +29,12 @@ import {
|
|
|
29
29
|
type ObservationUnavailableReason,
|
|
30
30
|
RendererOperationError,
|
|
31
31
|
} from '../errors/render';
|
|
32
|
-
import type { FogFrame } from '../extract/environment';
|
|
33
32
|
import type { GpuDrivenProduction, PreparedGpuDrivenFrame } from '../gpu-driven/production-raster';
|
|
34
33
|
import { GpuBuffer } from '../gpu-resource';
|
|
34
|
+
import { GPU_TEXTURE_USAGE_COPY_SRC } from '../gpu-texture-usage';
|
|
35
35
|
import {
|
|
36
36
|
GPU_BUFFER_USAGE_COPY_DST,
|
|
37
|
+
GPU_BUFFER_USAGE_MAP_READ,
|
|
37
38
|
GPU_BUFFER_USAGE_UNIFORM,
|
|
38
39
|
GPU_BUFFER_USAGE_VERTEX,
|
|
39
40
|
} from '../gpu-usage';
|
|
@@ -58,6 +59,7 @@ import type {
|
|
|
58
59
|
SkylightSnapshot,
|
|
59
60
|
} from '../render-system-extract';
|
|
60
61
|
import type { PersistentGpuDrivenState } from '../scene/render-scene';
|
|
62
|
+
import type { OcclusionFrameProjection } from '../scene/visibility/occlusion-runtime';
|
|
61
63
|
import { SHADOW_ATLAS_DEFAULT_LAYERS } from '../shadow-atlas';
|
|
62
64
|
import {
|
|
63
65
|
getTransparentSortConfig,
|
|
@@ -75,6 +77,7 @@ import {
|
|
|
75
77
|
warnZeroLightStandard,
|
|
76
78
|
writeHdrpClusterAndSsaoBuffers,
|
|
77
79
|
writeShadowParamsBuffer,
|
|
80
|
+
writeSpotModifierTextures,
|
|
78
81
|
} from './frame-lighting';
|
|
79
82
|
import {
|
|
80
83
|
type BindGroupCounts,
|
|
@@ -82,9 +85,12 @@ import {
|
|
|
82
85
|
type DirectionalShadowWorldState,
|
|
83
86
|
type DispatchCounts,
|
|
84
87
|
type FrameObservationSource,
|
|
88
|
+
getTextureIdentity,
|
|
85
89
|
makeZeroCameraFallbackSnapshot,
|
|
90
|
+
type ReflectionFallbackReadbackRequest,
|
|
86
91
|
type RenderFrameState,
|
|
87
92
|
type ValidatedRenderable,
|
|
93
|
+
validateGraphTargetCaptureReadback,
|
|
88
94
|
worldEntityKey,
|
|
89
95
|
} from './frame-snapshot';
|
|
90
96
|
// feat-20260622-chunk-gpu-instancing-sprite-tilemap M1 / w4 (D-1 record-stage
|
|
@@ -246,6 +252,75 @@ import {
|
|
|
246
252
|
writeViewUbo,
|
|
247
253
|
} from './view-ubo';
|
|
248
254
|
|
|
255
|
+
/**
|
|
256
|
+
* Resolve the GPU mesh view used by the optional production raster before its
|
|
257
|
+
* filtering pass runs. User meshes are pull-resident during record; relying
|
|
258
|
+
* only on the boot-time builtin map would make the first frame classify every
|
|
259
|
+
* imported mesh as a CPU fallback and would hide its LOD ranges from the GPU
|
|
260
|
+
* cull. Keep the map frame-local so the pipeline state remains the builtin
|
|
261
|
+
* compatibility owner while the residency cache remains the user-mesh SSOT.
|
|
262
|
+
*/
|
|
263
|
+
function gpuDrivenMeshesForFrame(
|
|
264
|
+
internals: RenderSystemInternals,
|
|
265
|
+
pipelineState: PipelineState,
|
|
266
|
+
worlds: readonly World[],
|
|
267
|
+
scene: PersistentGpuDrivenState | undefined,
|
|
268
|
+
): ReadonlyMap<number, MeshGpuHandles> {
|
|
269
|
+
const meshes = new Map(pipelineState.meshes);
|
|
270
|
+
if (scene === undefined) return meshes;
|
|
271
|
+
const cached = gpuDrivenMeshCache.get(scene.scene);
|
|
272
|
+
if (
|
|
273
|
+
cached !== undefined &&
|
|
274
|
+
cached.meshResidencyEpoch === internals.gpuStore.meshResidencyEpoch &&
|
|
275
|
+
cached.pipelineMeshes === pipelineState.meshes
|
|
276
|
+
) {
|
|
277
|
+
return cached.value;
|
|
278
|
+
}
|
|
279
|
+
for (const slot of scene.slots) {
|
|
280
|
+
const world = worlds[slot.snapshot.worldId];
|
|
281
|
+
if (world === undefined) continue;
|
|
282
|
+
const assetHandle = slot.snapshot.assetHandle;
|
|
283
|
+
const sharedHandle = toShared<'MeshAsset'>(assetHandle);
|
|
284
|
+
let gpu = internals.gpuStore.getMeshGpuHandles(sharedHandle, world);
|
|
285
|
+
if (gpu === undefined && !meshes.has(assetHandle)) {
|
|
286
|
+
const asset = resolveAssetHandle<MeshAsset>(world, sharedHandle);
|
|
287
|
+
if (asset.ok) {
|
|
288
|
+
const lodMeshes = slot.snapshot.lods?.map((lod) =>
|
|
289
|
+
internals.assets.lookup<MeshAsset>(lod.mesh),
|
|
290
|
+
);
|
|
291
|
+
const resolvedLodMeshes =
|
|
292
|
+
lodMeshes?.every((lod): lod is MeshAsset => lod?.kind === 'mesh') === true
|
|
293
|
+
? lodMeshes
|
|
294
|
+
: undefined;
|
|
295
|
+
const resident = internals.gpuStore.ensureResident(
|
|
296
|
+
sharedHandle,
|
|
297
|
+
asset.value,
|
|
298
|
+
world,
|
|
299
|
+
resolvedLodMeshes,
|
|
300
|
+
);
|
|
301
|
+
if (resident.ok) gpu = resident.value;
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
if (gpu !== undefined) meshes.set(assetHandle, gpu);
|
|
305
|
+
}
|
|
306
|
+
const value = meshes;
|
|
307
|
+
gpuDrivenMeshCache.set(scene.scene, {
|
|
308
|
+
meshResidencyEpoch: internals.gpuStore.meshResidencyEpoch,
|
|
309
|
+
pipelineMeshes: pipelineState.meshes,
|
|
310
|
+
value,
|
|
311
|
+
});
|
|
312
|
+
return value;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
const gpuDrivenMeshCache = new WeakMap<
|
|
316
|
+
object,
|
|
317
|
+
{
|
|
318
|
+
readonly meshResidencyEpoch: number;
|
|
319
|
+
readonly pipelineMeshes: ReadonlyMap<number, MeshGpuHandles>;
|
|
320
|
+
readonly value: ReadonlyMap<number, MeshGpuHandles>;
|
|
321
|
+
}
|
|
322
|
+
>();
|
|
323
|
+
|
|
249
324
|
/**
|
|
250
325
|
* A frame-local material table. Repeated snapshot objects share one UBO slot;
|
|
251
326
|
* each renderable keeps only the slot index used by each authored material.
|
|
@@ -388,6 +463,135 @@ function runRecordProfilePhase<T>(
|
|
|
388
463
|
return runner === undefined ? action() : runner(phase, action);
|
|
389
464
|
}
|
|
390
465
|
|
|
466
|
+
function halfFloatToNumber(bits: number): number {
|
|
467
|
+
const sign = (bits & 0x8000) === 0 ? 1 : -1;
|
|
468
|
+
const exponent = (bits >>> 10) & 0x1f;
|
|
469
|
+
const fraction = bits & 0x03ff;
|
|
470
|
+
if (exponent === 0) return sign * 2 ** -14 * (fraction / 1024);
|
|
471
|
+
if (exponent === 0x1f) return fraction === 0 ? sign * Infinity : Number.NaN;
|
|
472
|
+
return sign * 2 ** (exponent - 15) * (1 + fraction / 1024);
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
function createReflectionFallbackReadbackRequest(
|
|
476
|
+
internals: RenderSystemInternals,
|
|
477
|
+
frameState: RenderFrameState,
|
|
478
|
+
): ReflectionFallbackReadbackRequest | undefined {
|
|
479
|
+
if (!frameState.reflectionFallbackDemand || frameState.reflectionFallbackReadback !== undefined) {
|
|
480
|
+
return undefined;
|
|
481
|
+
}
|
|
482
|
+
const graph = frameState.perFrameGraph;
|
|
483
|
+
if (graph === undefined || graph === null) return undefined;
|
|
484
|
+
const descriptor = graph.getColorTargetDescriptor('reflection-fallback-linear-hdr');
|
|
485
|
+
const texture = graph.getColorTargetTexture('reflection-fallback-linear-hdr');
|
|
486
|
+
if (
|
|
487
|
+
descriptor === undefined ||
|
|
488
|
+
texture === undefined ||
|
|
489
|
+
descriptor.format !== 'rgba16float' ||
|
|
490
|
+
descriptor.sample !== 1
|
|
491
|
+
) {
|
|
492
|
+
return undefined;
|
|
493
|
+
}
|
|
494
|
+
const bytesPerRow = Math.ceil((descriptor.size.width * 8) / 256) * 256;
|
|
495
|
+
const created = internals.device.createBuffer({
|
|
496
|
+
label: 'reflection-fallback-linear-hdr.readback',
|
|
497
|
+
size: bytesPerRow * descriptor.size.height,
|
|
498
|
+
usage: GPU_BUFFER_USAGE_COPY_DST | GPU_BUFFER_USAGE_MAP_READ,
|
|
499
|
+
mappedAtCreation: false,
|
|
500
|
+
});
|
|
501
|
+
if (!created.ok) {
|
|
502
|
+
internals.errorRegistry.fire(created.error);
|
|
503
|
+
return undefined;
|
|
504
|
+
}
|
|
505
|
+
return {
|
|
506
|
+
name: 'reflection-fallback-linear-hdr',
|
|
507
|
+
buffer: created.value,
|
|
508
|
+
bytesPerRow,
|
|
509
|
+
width: descriptor.size.width,
|
|
510
|
+
height: descriptor.size.height,
|
|
511
|
+
expected: {
|
|
512
|
+
format: descriptor.format,
|
|
513
|
+
width: descriptor.size.width,
|
|
514
|
+
height: descriptor.size.height,
|
|
515
|
+
usage: GPU_TEXTURE_USAGE_COPY_SRC,
|
|
516
|
+
graphGeneration: graph.graphGeneration,
|
|
517
|
+
frameId: frameState.frameNumber,
|
|
518
|
+
textureIdentity: getTextureIdentity(texture),
|
|
519
|
+
},
|
|
520
|
+
encoded: false,
|
|
521
|
+
};
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
async function mapReflectionFallbackReadback(
|
|
525
|
+
internals: RenderSystemInternals,
|
|
526
|
+
request: ReflectionFallbackReadbackRequest,
|
|
527
|
+
allowZero: boolean,
|
|
528
|
+
): Promise<{
|
|
529
|
+
readonly linearHdr: readonly [number, number, number, number];
|
|
530
|
+
readonly hash: string;
|
|
531
|
+
readonly graphGeneration: number;
|
|
532
|
+
readonly textureIdentity: number;
|
|
533
|
+
}> {
|
|
534
|
+
try {
|
|
535
|
+
if (!request.encoded) throw new Error('reflection fallback copy was not encoded');
|
|
536
|
+
const mapped = await request.buffer.mapAsync(GPU_BUFFER_USAGE_MAP_READ);
|
|
537
|
+
if (!mapped.ok) throw mapped.error;
|
|
538
|
+
const range = mapped.value.getMappedRange();
|
|
539
|
+
if (!range.ok) throw range.error;
|
|
540
|
+
const bytes = new Uint8Array(range.value.slice(0));
|
|
541
|
+
mapped.value.unmap();
|
|
542
|
+
const validation = validateGraphTargetCaptureReadback({
|
|
543
|
+
bytes,
|
|
544
|
+
expectedByteLength: request.bytesPerRow * request.height,
|
|
545
|
+
allowZero,
|
|
546
|
+
});
|
|
547
|
+
if (!validation.ok) throw new Error(validation.code);
|
|
548
|
+
let linearHdr: readonly [number, number, number, number] = [0, 0, 0, 0];
|
|
549
|
+
const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
|
|
550
|
+
for (let y = 0; y < request.height; y += 1) {
|
|
551
|
+
for (let x = 0; x < request.width; x += 1) {
|
|
552
|
+
const offset = y * request.bytesPerRow + x * 8;
|
|
553
|
+
const pixel = [0, 1, 2, 3].map((channel) =>
|
|
554
|
+
halfFloatToNumber(view.getUint16(offset + channel * 2, true)),
|
|
555
|
+
) as [number, number, number, number];
|
|
556
|
+
// The clear attachment carries alpha=1, so alpha alone is not
|
|
557
|
+
// evidence that the Standard BRDF wrote a fallback lobe. Decode the
|
|
558
|
+
// RGB channels from the mapped MRT and admit the first finite
|
|
559
|
+
// non-zero color sample only.
|
|
560
|
+
if (pixel.slice(0, 3).some((value) => Number.isFinite(value) && value !== 0)) {
|
|
561
|
+
linearHdr = pixel;
|
|
562
|
+
y = request.height;
|
|
563
|
+
break;
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
// A cleared attachment has a non-zero alpha lane, so byte-level
|
|
568
|
+
// validation alone can incorrectly admit an otherwise empty MRT. When
|
|
569
|
+
// the selected producer is non-neutral, require an actual finite RGB
|
|
570
|
+
// sample before publishing a complete receipt; neutral rows explicitly
|
|
571
|
+
// retain the zero quartet through allowZero=true.
|
|
572
|
+
if (
|
|
573
|
+
!allowZero &&
|
|
574
|
+
!linearHdr.slice(0, 3).some((value) => Number.isFinite(value) && value !== 0)
|
|
575
|
+
) {
|
|
576
|
+
throw new Error('capture-readback-empty');
|
|
577
|
+
}
|
|
578
|
+
const subtle = globalThis.crypto?.subtle;
|
|
579
|
+
if (subtle === undefined) throw new Error('Web Crypto SHA-256 is unavailable');
|
|
580
|
+
const digest = await subtle.digest('SHA-256', bytes);
|
|
581
|
+
const hash = Array.from(new Uint8Array(digest), (value) =>
|
|
582
|
+
value.toString(16).padStart(2, '0'),
|
|
583
|
+
).join('');
|
|
584
|
+
return {
|
|
585
|
+
linearHdr,
|
|
586
|
+
hash: `sha256:${hash}`,
|
|
587
|
+
graphGeneration: request.expected.graphGeneration,
|
|
588
|
+
textureIdentity: request.expected.textureIdentity,
|
|
589
|
+
};
|
|
590
|
+
} finally {
|
|
591
|
+
internals.device.destroyBuffer(request.buffer);
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
|
|
391
595
|
const VOLUMETRIC_FOG_PASS_COUNT = 4;
|
|
392
596
|
|
|
393
597
|
type VolumetricFogParamsSlot = 0 | 1;
|
|
@@ -696,16 +900,21 @@ function prepareVolumetricFogFrame(
|
|
|
696
900
|
// sub-froxel jitter. The temporal resolver consumes it without growing the
|
|
697
901
|
// public fog component or allocating another uniform buffer.
|
|
698
902
|
params[23] = frameState.frameNumber % 1024;
|
|
903
|
+
const selectedPointIndex =
|
|
904
|
+
selectedPoint === undefined
|
|
905
|
+
? -1
|
|
906
|
+
: lights.point.findIndex((light) => light.entity === selectedPoint.entity);
|
|
699
907
|
const selectedSpotIndex =
|
|
700
908
|
selectedSpot === undefined
|
|
701
909
|
? -1
|
|
702
910
|
: lights.spot.findIndex((light) => light.entity === selectedSpot.entity);
|
|
911
|
+
// Cluster light_data is one point/spot/rect array. Point slots are emitted
|
|
912
|
+
// first, so volume stores the global slot rather than a per-kind array index.
|
|
913
|
+
const selectedSpotClusterIndex =
|
|
914
|
+
selectedSpotIndex < 0 ? -1 : lights.point.length + selectedSpotIndex;
|
|
703
915
|
params.set(lightColor, 24);
|
|
704
|
-
params[19] =
|
|
705
|
-
|
|
706
|
-
? -1
|
|
707
|
-
: lights.point.findIndex((light) => light.entity === selectedPoint.entity);
|
|
708
|
-
params[27] = selectedSpotIndex;
|
|
916
|
+
params[19] = selectedPointIndex;
|
|
917
|
+
params[27] = selectedSpotClusterIndex;
|
|
709
918
|
params[28] = fog.fog.maxDistance;
|
|
710
919
|
params[29] = fog.fog.anisotropy;
|
|
711
920
|
params[30] =
|
|
@@ -1102,7 +1311,6 @@ export function recordFrame(
|
|
|
1102
1311
|
skybox: SkyboxSnapshot | undefined,
|
|
1103
1312
|
skyboxCount: number,
|
|
1104
1313
|
postProcessParams: ReadonlyMap<string, Uint8Array>,
|
|
1105
|
-
fog: FogFrame | undefined,
|
|
1106
1314
|
// feat-20260709-editor-world-partition ENGINE-fix-round2 (defect 2): the
|
|
1107
1315
|
// full worlds[] list passed to `renderer.draw`, indexed by
|
|
1108
1316
|
// RenderableSnapshot.worldId so the record stage resolves each renderable's
|
|
@@ -1115,7 +1323,11 @@ export function recordFrame(
|
|
|
1115
1323
|
gpuDriven?: {
|
|
1116
1324
|
readonly owner: GpuDrivenProduction;
|
|
1117
1325
|
readonly scene: PersistentGpuDrivenState | undefined;
|
|
1118
|
-
readonly
|
|
1326
|
+
readonly onSceneDemand: (sceneRowsRequired: boolean) => void;
|
|
1327
|
+
readonly activeEntityKeys?: ReadonlySet<number>;
|
|
1328
|
+
readonly activeEntityRevision?: number;
|
|
1329
|
+
readonly telemetryCandidateCount?: number;
|
|
1330
|
+
readonly occlusion?: OcclusionFrameProjection;
|
|
1119
1331
|
},
|
|
1120
1332
|
renderReadLeases?: readonly RenderReadLease[],
|
|
1121
1333
|
featureGraphCandidate?: RenderFeatureGraphCandidate,
|
|
@@ -1128,6 +1340,8 @@ export function recordFrame(
|
|
|
1128
1340
|
volumetricFog?: ExtractedVolumetricFog,
|
|
1129
1341
|
timingCapture?: GpuTimingCapture,
|
|
1130
1342
|
): boolean {
|
|
1343
|
+
frameState.reflectionFallbackObservationSource = undefined;
|
|
1344
|
+
frameState.reflectionFallbackCompletion = undefined;
|
|
1131
1345
|
// The `try / finally` wrapper advances `frameState.frameNumber` exactly
|
|
1132
1346
|
// once per `recordFrame` invocation regardless of which early-return
|
|
1133
1347
|
// branch is taken (camera missing, cap exceeded, pipeline pending,
|
|
@@ -1195,6 +1409,10 @@ export function recordFrame(
|
|
|
1195
1409
|
return false;
|
|
1196
1410
|
}
|
|
1197
1411
|
frameState.currentFrameObservationSource = undefined;
|
|
1412
|
+
if (frameState.reflectionFallbackReadback !== undefined) {
|
|
1413
|
+
internals.device.destroyBuffer(frameState.reflectionFallbackReadback.buffer);
|
|
1414
|
+
frameState.reflectionFallbackReadback = undefined;
|
|
1415
|
+
}
|
|
1198
1416
|
frameState.currentDirectionalShadowView = null;
|
|
1199
1417
|
frameState.currentSpotShadowView = null;
|
|
1200
1418
|
|
|
@@ -1210,7 +1428,7 @@ export function recordFrame(
|
|
|
1210
1428
|
|
|
1211
1429
|
// Multi-light warnings + point/spot shadow-snapshot pin + point-shadow atlas
|
|
1212
1430
|
// ensure + ExtractedLights three-arm destructure (directional fallback,
|
|
1213
|
-
// point/spot arrays, totalLightCount). Extracted to prepareFrameLighting
|
|
1431
|
+
// point/spot/Rect arrays, totalLightCount). Extracted to prepareFrameLighting
|
|
1214
1432
|
// (M3/w18) so recordFrame stays a skeleton.
|
|
1215
1433
|
const lighting = runRecordProfilePhase(profilePhase, 'record/scene-state/lighting-prep', () =>
|
|
1216
1434
|
prepareFrameLighting(internals, frameState, lights, camera, pipelineState),
|
|
@@ -1359,12 +1577,32 @@ export function recordFrame(
|
|
|
1359
1577
|
|
|
1360
1578
|
let preparedGpuDriven: PreparedGpuDrivenFrame | undefined;
|
|
1361
1579
|
if (gpuDriven !== undefined) {
|
|
1580
|
+
const standardPbrArtifact = internals.getMaterialShaderArtifact?.(
|
|
1581
|
+
'forgeax::default-standard-pbr',
|
|
1582
|
+
);
|
|
1362
1583
|
const prepared = gpuDriven.owner.prepare({
|
|
1363
1584
|
scene: gpuDriven.scene,
|
|
1364
1585
|
camera,
|
|
1365
|
-
meshes: pipelineState.
|
|
1586
|
+
meshes: gpuDrivenMeshesForFrame(internals, pipelineState, worlds, gpuDriven.scene),
|
|
1366
1587
|
viewBindGroupLayout: pipelineState.viewBindGroupLayout,
|
|
1367
1588
|
meshResidencyEpoch: internals.gpuStore.meshResidencyEpoch,
|
|
1589
|
+
// The built-in Standard graph (including its clustered transport) is
|
|
1590
|
+
// eligible for the GPU-driven LOD lane. The old HDRP boolean no
|
|
1591
|
+
// longer exists in the unified pipeline state, so it must not be
|
|
1592
|
+
// inferred from `standard.kind`.
|
|
1593
|
+
hdrp: false,
|
|
1594
|
+
...(gpuDriven.activeEntityKeys === undefined
|
|
1595
|
+
? {}
|
|
1596
|
+
: { activeEntityKeys: gpuDriven.activeEntityKeys }),
|
|
1597
|
+
...(gpuDriven.activeEntityRevision === undefined
|
|
1598
|
+
? {}
|
|
1599
|
+
: { activeEntityRevision: gpuDriven.activeEntityRevision }),
|
|
1600
|
+
...(gpuDriven.telemetryCandidateCount === undefined
|
|
1601
|
+
? {}
|
|
1602
|
+
: { telemetryCandidateCount: gpuDriven.telemetryCandidateCount }),
|
|
1603
|
+
...(gpuDriven.occlusion === undefined ? {} : { occlusion: gpuDriven.occlusion }),
|
|
1604
|
+
...(standardPbrArtifact === undefined ? {} : { standardPbrArtifact }),
|
|
1605
|
+
standardPbrPipelineState: pipelineState,
|
|
1368
1606
|
});
|
|
1369
1607
|
if (prepared.ok) preparedGpuDriven = prepared.value;
|
|
1370
1608
|
else if (prepared.error.code !== 'rhi-not-available')
|
|
@@ -1378,18 +1616,17 @@ export function recordFrame(
|
|
|
1378
1616
|
lights.pointShadow.length > 0 ||
|
|
1379
1617
|
lights.spot.some((spot) => spot.castShadow);
|
|
1380
1618
|
const gpuOwnsAllPrimaryRaster = preparedGpuDriven?.ownsAllRenderables === true;
|
|
1381
|
-
gpuDriven?.
|
|
1382
|
-
gpuOwnsAllPrimaryRaster && !cpuShadowCastersActive,
|
|
1383
|
-
standard.kind === 'clustered',
|
|
1384
|
-
);
|
|
1619
|
+
gpuDriven?.onSceneDemand(gpuDriven.owner.requiresSceneRows());
|
|
1385
1620
|
|
|
1386
1621
|
const cubeCaptureWork = prepareCubeCapture(internals, cubeCapture, camera);
|
|
1622
|
+
const reflectionFallbackCandidate = cubeCapture?.reflectionProbes?.fallbackDemand === true;
|
|
1387
1623
|
|
|
1388
1624
|
// Validate renderables before graph admission. Besides producing the draw
|
|
1389
1625
|
// plan, this is the owner of per-frame cache eviction; running it before a
|
|
1390
1626
|
// graph candidate can fail guarantees despawned instance buffers are
|
|
1391
1627
|
// released even when the frame cannot be submitted.
|
|
1392
1628
|
const gpuOwnedEntityKeys = preparedGpuDriven?.entityKeys ?? EMPTY_ENTITY_KEYS;
|
|
1629
|
+
const gpuDrivenWorldKeys = gpuDriven?.scene?.worldKeys;
|
|
1393
1630
|
const validated = runRecordProfilePhase(profilePhase, 'record/validation', () =>
|
|
1394
1631
|
gpuOwnsAllPrimaryRaster && !cpuShadowCastersActive && cubeCaptureWork.length === 0
|
|
1395
1632
|
? []
|
|
@@ -1404,11 +1641,24 @@ export function recordFrame(
|
|
|
1404
1641
|
cpuShadowCastersActive || cubeCaptureWork.length > 0
|
|
1405
1642
|
? EMPTY_ENTITY_KEYS
|
|
1406
1643
|
: gpuOwnedEntityKeys,
|
|
1644
|
+
gpuDrivenWorldKeys,
|
|
1407
1645
|
),
|
|
1408
1646
|
);
|
|
1409
|
-
gpuDriven?.owner.recordCpuValidation(validated, gpuOwnedEntityKeys);
|
|
1647
|
+
gpuDriven?.owner.recordCpuValidation(validated, gpuOwnedEntityKeys, gpuDrivenWorldKeys);
|
|
1410
1648
|
cleanPerFrameCaches(internals, frameState, validated, gpuOwnedEntityKeys);
|
|
1411
1649
|
|
|
1650
|
+
// S_fallback is the second output of the built-in Standard PBR BRDF. A
|
|
1651
|
+
// graph may still carry the detached owner tickets for inspection, but
|
|
1652
|
+
// the MRT is admitted only when every CPU-rendered primary row in this
|
|
1653
|
+
// frame uses that exact output contract. Unsupported compositions remain
|
|
1654
|
+
// fail-closed for SSR instead of submitting a device-invalid command.
|
|
1655
|
+
frameState.reflectionFallbackDemand =
|
|
1656
|
+
reflectionFallbackCandidate &&
|
|
1657
|
+
validated.length > 0 &&
|
|
1658
|
+
validated.every(
|
|
1659
|
+
(entry) => entry.source.material.materialShaderId === 'forgeax::default-standard-pbr',
|
|
1660
|
+
);
|
|
1661
|
+
|
|
1412
1662
|
const preflightGraph = runRecordProfilePhase(profilePhase, 'record/render-graph', () =>
|
|
1413
1663
|
ensureCompiledFrameGraph(
|
|
1414
1664
|
internals,
|
|
@@ -1424,6 +1674,7 @@ export function recordFrame(
|
|
|
1424
1674
|
cubeCapture?.state,
|
|
1425
1675
|
cameras.length === 0,
|
|
1426
1676
|
transmissionDemand,
|
|
1677
|
+
gpuDriven?.occlusion,
|
|
1427
1678
|
graphVolumetricFog,
|
|
1428
1679
|
volumeTopologyCandidate,
|
|
1429
1680
|
standard,
|
|
@@ -1453,6 +1704,12 @@ export function recordFrame(
|
|
|
1453
1704
|
return false;
|
|
1454
1705
|
}
|
|
1455
1706
|
if (standard.kind === 'clustered') {
|
|
1707
|
+
// The clustered HDRP payload owns the direct-light slot upload, so it
|
|
1708
|
+
// must also drive the shared Spot IES/Cookie resource upload from the
|
|
1709
|
+
// authoritative extracted-light corpus. The prepared local carrier can
|
|
1710
|
+
// omit the source payload on this path, leaving the shader bound to its
|
|
1711
|
+
// white Cookie fallback even though the authored handle is valid.
|
|
1712
|
+
writeSpotModifierTextures(internals, pipelineState, lights.spot);
|
|
1456
1713
|
const clusterWrite = runRecordProfilePhase(
|
|
1457
1714
|
profilePhase,
|
|
1458
1715
|
'record/scene-state/hdrp-cluster',
|
|
@@ -1467,6 +1724,7 @@ export function recordFrame(
|
|
|
1467
1724
|
pipelineState.hdrpClusterMembershipPipeline !== null,
|
|
1468
1725
|
pipelineState.hdrpClusterMembershipBindGroupLayout,
|
|
1469
1726
|
preparedSpotLightProjector?.lightSlotIndex,
|
|
1727
|
+
pipelineState,
|
|
1470
1728
|
),
|
|
1471
1729
|
);
|
|
1472
1730
|
if (!clusterWrite.ok) {
|
|
@@ -1489,78 +1747,58 @@ export function recordFrame(
|
|
|
1489
1747
|
const targetW = swapTarget.targetW;
|
|
1490
1748
|
const targetH = swapTarget.targetH;
|
|
1491
1749
|
|
|
1492
|
-
const
|
|
1750
|
+
const previousTemporalView = frameState.lastSuccessfulTemporalView;
|
|
1751
|
+
const currentUnjitteredViewProjection = mat4.multiply(
|
|
1752
|
+
mat4.create(),
|
|
1753
|
+
computeProjectionMatrix(camera),
|
|
1754
|
+
computeViewMatrix(camera),
|
|
1755
|
+
);
|
|
1756
|
+
const currentCameraPosition = [
|
|
1757
|
+
camera.position[0] ?? 0,
|
|
1758
|
+
camera.position[1] ?? 0,
|
|
1759
|
+
camera.position[2] ?? 0,
|
|
1760
|
+
] as const;
|
|
1761
|
+
const temporalCandidate = createTemporalView({
|
|
1762
|
+
antialias: camera.antialias,
|
|
1763
|
+
width: Math.max(1, targetW),
|
|
1764
|
+
height: Math.max(1, targetH),
|
|
1765
|
+
frameIndex: frameState.successfulTemporalFrameIndex ?? 0,
|
|
1766
|
+
viewIdentity: `camera:${camera.entityKey ?? 0}`,
|
|
1767
|
+
environmentSignature,
|
|
1768
|
+
fogSignature,
|
|
1769
|
+
deviceGeneration: internals.deviceScope?.generation ?? 0,
|
|
1770
|
+
...(camera.historyVersion === undefined ? {} : { historyVersion: camera.historyVersion }),
|
|
1771
|
+
historyValid: false,
|
|
1772
|
+
currentUnjitteredViewProjection,
|
|
1773
|
+
currentCameraPosition,
|
|
1774
|
+
});
|
|
1775
|
+
const resetReason =
|
|
1493
1776
|
camera.antialias === 'taa' && environmentReady
|
|
1494
|
-
? (
|
|
1495
|
-
const created = createTemporalView({
|
|
1496
|
-
antialias: camera.antialias,
|
|
1497
|
-
width: targetW,
|
|
1498
|
-
height: targetH,
|
|
1499
|
-
frameIndex: frameState.successfulTemporalFrameIndex ?? 0,
|
|
1500
|
-
viewIdentity: `camera:${camera.entityKey ?? 0}`,
|
|
1501
|
-
environmentSignature,
|
|
1502
|
-
fogSignature,
|
|
1503
|
-
deviceGeneration: internals.deviceScope.generation,
|
|
1504
|
-
...(camera.historyVersion === undefined
|
|
1505
|
-
? {}
|
|
1506
|
-
: { historyVersion: camera.historyVersion }),
|
|
1507
|
-
});
|
|
1508
|
-
const previous = frameState.lastSuccessfulTemporalView;
|
|
1509
|
-
const currentUnjitteredViewProjection = mat4.multiply(
|
|
1510
|
-
mat4.create(),
|
|
1511
|
-
computeProjectionMatrix(camera),
|
|
1512
|
-
computeViewMatrix(camera),
|
|
1513
|
-
);
|
|
1514
|
-
const resetCandidate = createTemporalView({
|
|
1515
|
-
antialias: created.input.antialias,
|
|
1516
|
-
width: created.input.width,
|
|
1517
|
-
height: created.input.height,
|
|
1518
|
-
frameIndex: created.input.frameIndex,
|
|
1519
|
-
historyVersion: created.input.historyVersion,
|
|
1520
|
-
viewIdentity: created.input.viewIdentity,
|
|
1521
|
-
environmentSignature,
|
|
1522
|
-
fogSignature,
|
|
1523
|
-
deviceGeneration: internals.deviceScope.generation,
|
|
1524
|
-
cameraCut: created.input.cameraCut,
|
|
1525
|
-
historyValid: false,
|
|
1526
|
-
currentUnjitteredViewProjection,
|
|
1527
|
-
});
|
|
1528
|
-
const resetReason = resolveTemporalReset(previous, resetCandidate);
|
|
1529
|
-
return createTemporalView({
|
|
1530
|
-
...resetCandidate.input,
|
|
1531
|
-
frameIndex: resetReason === undefined ? resetCandidate.input.frameIndex : 0,
|
|
1532
|
-
historyValid: previous !== undefined && resetReason === undefined,
|
|
1533
|
-
currentUnjitteredViewProjection,
|
|
1534
|
-
resetReason,
|
|
1535
|
-
...(resetReason !== undefined ||
|
|
1536
|
-
previous?.currentUnjitteredViewProjection === undefined
|
|
1537
|
-
? {}
|
|
1538
|
-
: {
|
|
1539
|
-
previousUnjitteredViewProjection: previous.currentUnjitteredViewProjection,
|
|
1540
|
-
}),
|
|
1541
|
-
});
|
|
1542
|
-
})()
|
|
1777
|
+
? resolveTemporalReset(previousTemporalView, temporalCandidate)
|
|
1543
1778
|
: undefined;
|
|
1779
|
+
const canReusePrevious = previousTemporalView !== undefined && resetReason === undefined;
|
|
1780
|
+
const temporalView = createTemporalView({
|
|
1781
|
+
...temporalCandidate.input,
|
|
1782
|
+
frameIndex: resetReason === undefined ? temporalCandidate.input.frameIndex : 0,
|
|
1783
|
+
historyValid: camera.antialias === 'taa' && environmentReady && canReusePrevious,
|
|
1784
|
+
resetReason,
|
|
1785
|
+
...(canReusePrevious && previousTemporalView.currentUnjitteredViewProjection !== undefined
|
|
1786
|
+
? {
|
|
1787
|
+
previousUnjitteredViewProjection: previousTemporalView.currentUnjitteredViewProjection,
|
|
1788
|
+
}
|
|
1789
|
+
: {}),
|
|
1790
|
+
...(canReusePrevious && previousTemporalView.currentCameraPosition !== undefined
|
|
1791
|
+
? { previousCameraPosition: previousTemporalView.currentCameraPosition }
|
|
1792
|
+
: {}),
|
|
1793
|
+
});
|
|
1544
1794
|
frameState.pendingTemporalCommit =
|
|
1545
1795
|
cameras.length === 0 || !environmentReady || internals.deviceScope === undefined
|
|
1546
1796
|
? { kind: 'none' }
|
|
1547
|
-
: temporalView ===
|
|
1548
|
-
? {
|
|
1549
|
-
|
|
1550
|
-
view: createTemporalView({
|
|
1551
|
-
antialias: camera.antialias,
|
|
1552
|
-
width: targetW,
|
|
1553
|
-
height: targetH,
|
|
1554
|
-
frameIndex: frameState.successfulTemporalFrameIndex ?? 0,
|
|
1555
|
-
viewIdentity: `camera:${camera.entityKey ?? 0}`,
|
|
1556
|
-
environmentSignature,
|
|
1557
|
-
fogSignature,
|
|
1558
|
-
deviceGeneration: internals.deviceScope.generation,
|
|
1559
|
-
}),
|
|
1560
|
-
}
|
|
1561
|
-
: { kind: 'taa', view: temporalView };
|
|
1797
|
+
: temporalView.mode === 'taa'
|
|
1798
|
+
? { kind: 'taa', view: temporalView }
|
|
1799
|
+
: { kind: 'off', view: temporalView };
|
|
1562
1800
|
const recordCamera: CameraSnapshot =
|
|
1563
|
-
temporalView ===
|
|
1801
|
+
temporalView.mode === 'taa' ? { ...camera, temporal: temporalView } : camera;
|
|
1564
1802
|
let activeVolumetricFogContext: VolumetricFogFrameContext | undefined;
|
|
1565
1803
|
let activeVolumetricFogSignature: VolumeTemporalSignature | undefined;
|
|
1566
1804
|
if (graphVolumetricFog?.status === 'available' && baseVolumetricFogContext !== undefined) {
|
|
@@ -1727,7 +1965,6 @@ export function recordFrame(
|
|
|
1727
1965
|
light,
|
|
1728
1966
|
lights,
|
|
1729
1967
|
frameState.spotShadowSnapshots,
|
|
1730
|
-
fog,
|
|
1731
1968
|
temporalView,
|
|
1732
1969
|
preparedSpotLightProjector?.spotIndex,
|
|
1733
1970
|
);
|
|
@@ -1808,7 +2045,6 @@ export function recordFrame(
|
|
|
1808
2045
|
lights,
|
|
1809
2046
|
frameState.spotShadowSnapshots,
|
|
1810
2047
|
capture.viewBindGroupDynamicOffset,
|
|
1811
|
-
undefined,
|
|
1812
2048
|
preparedSpotLightProjector?.spotIndex,
|
|
1813
2049
|
);
|
|
1814
2050
|
}
|
|
@@ -1823,7 +2059,6 @@ export function recordFrame(
|
|
|
1823
2059
|
lights,
|
|
1824
2060
|
frameState.spotShadowSnapshots,
|
|
1825
2061
|
probe.viewBindGroupDynamicOffset,
|
|
1826
|
-
undefined,
|
|
1827
2062
|
preparedSpotLightProjector?.spotIndex,
|
|
1828
2063
|
);
|
|
1829
2064
|
}
|
|
@@ -1859,6 +2094,7 @@ export function recordFrame(
|
|
|
1859
2094
|
assets: internals.assets,
|
|
1860
2095
|
world,
|
|
1861
2096
|
gpuDrivenEntityKeys: gpuOwnedEntityKeys,
|
|
2097
|
+
...(gpuDrivenWorldKeys === undefined ? {} : { gpuDrivenWorldKeys }),
|
|
1862
2098
|
store: internals.gpuStore,
|
|
1863
2099
|
pipelineState,
|
|
1864
2100
|
bloomResources: pipelineState.perPassResources.getBloomResources?.() ?? null,
|
|
@@ -1903,6 +2139,7 @@ export function recordFrame(
|
|
|
1903
2139
|
dispatch: transparentDispatch,
|
|
1904
2140
|
hdrpClusterBindGroup,
|
|
1905
2141
|
hdrpClusterMembershipBindGroup,
|
|
2142
|
+
...(gpuDriven?.occlusion === undefined ? {} : { occlusion: gpuDriven.occlusion }),
|
|
1906
2143
|
standardLighting: standard,
|
|
1907
2144
|
foldDispatchPlan,
|
|
1908
2145
|
materialSlotIndices,
|
|
@@ -1917,7 +2154,19 @@ export function recordFrame(
|
|
|
1917
2154
|
directionalShadowCacheReuse: directionalShadowCache.reuse,
|
|
1918
2155
|
...(profilePhase !== undefined ? { profilePhase } : {}),
|
|
1919
2156
|
};
|
|
2157
|
+
const fallbackReadbackRequest = createReflectionFallbackReadbackRequest(internals, frameState);
|
|
2158
|
+
if (fallbackReadbackRequest !== undefined) {
|
|
2159
|
+
frameState.reflectionFallbackReadback = fallbackReadbackRequest;
|
|
2160
|
+
}
|
|
1920
2161
|
let completion: Promise<unknown> | undefined;
|
|
2162
|
+
let fallbackReadback:
|
|
2163
|
+
| Promise<{
|
|
2164
|
+
readonly linearHdr: readonly [number, number, number, number];
|
|
2165
|
+
readonly hash: string;
|
|
2166
|
+
readonly graphGeneration: number;
|
|
2167
|
+
readonly textureIdentity: number;
|
|
2168
|
+
}>
|
|
2169
|
+
| undefined;
|
|
1921
2170
|
const stagedTemporalFrame = {
|
|
1922
2171
|
frameId: frameState.frameNumber,
|
|
1923
2172
|
currentViewProjection: new Float32Array(currentViewProjection),
|
|
@@ -1941,9 +2190,34 @@ export function recordFrame(
|
|
|
1941
2190
|
profilePhase === undefined
|
|
1942
2191
|
? undefined
|
|
1943
2192
|
: (pass, encode) => profilePhase(graphExecutionPhase(pass.name), encode),
|
|
2193
|
+
gpuDriven === undefined
|
|
2194
|
+
? undefined
|
|
2195
|
+
: {
|
|
2196
|
+
afterGraphExecute: () => gpuDriven.occlusion?.recordResolve(encoder) ?? ok(undefined),
|
|
2197
|
+
onSubmitted: () => {
|
|
2198
|
+
gpuDriven.occlusion?.commit(true, frameState.frameNumber, profilePhase);
|
|
2199
|
+
},
|
|
2200
|
+
onAborted: () => {
|
|
2201
|
+
gpuDriven.occlusion?.commit(false, frameState.frameNumber);
|
|
2202
|
+
},
|
|
2203
|
+
},
|
|
1944
2204
|
cubeCaptureWork.length === 0 ? undefined : cubeCaptureWork.map((work) => work.faceIndex),
|
|
1945
2205
|
(done) => {
|
|
1946
2206
|
completion = done;
|
|
2207
|
+
if (fallbackReadbackRequest !== undefined) {
|
|
2208
|
+
fallbackReadback = done.then(
|
|
2209
|
+
() =>
|
|
2210
|
+
mapReflectionFallbackReadback(
|
|
2211
|
+
internals,
|
|
2212
|
+
fallbackReadbackRequest,
|
|
2213
|
+
cubeCapture?.reflectionProbes?.fallbackHasNonNeutral !== true,
|
|
2214
|
+
),
|
|
2215
|
+
(cause) => {
|
|
2216
|
+
internals.device.destroyBuffer(fallbackReadbackRequest.buffer);
|
|
2217
|
+
throw cause;
|
|
2218
|
+
},
|
|
2219
|
+
);
|
|
2220
|
+
}
|
|
1947
2221
|
},
|
|
1948
2222
|
timingCapture,
|
|
1949
2223
|
),
|
|
@@ -1952,7 +2226,29 @@ export function recordFrame(
|
|
|
1952
2226
|
const completed = cubeCapture.scheduler.completeSubmission(submitted, completion);
|
|
1953
2227
|
if (!completed.ok) internals.errorRegistry.fire(completed.error);
|
|
1954
2228
|
}
|
|
1955
|
-
|
|
2229
|
+
if (!submitted && fallbackReadbackRequest !== undefined) {
|
|
2230
|
+
internals.device.destroyBuffer(fallbackReadbackRequest.buffer);
|
|
2231
|
+
}
|
|
2232
|
+
const reflectionFallbackCompletion = cubeCapture?.reflectionProbes?.completeSubmission(
|
|
2233
|
+
submitted,
|
|
2234
|
+
completion,
|
|
2235
|
+
fallbackReadbackRequest === undefined || fallbackReadback === undefined
|
|
2236
|
+
? undefined
|
|
2237
|
+
: {
|
|
2238
|
+
format: fallbackReadbackRequest.expected.format,
|
|
2239
|
+
size: {
|
|
2240
|
+
width: fallbackReadbackRequest.expected.width,
|
|
2241
|
+
height: fallbackReadbackRequest.expected.height,
|
|
2242
|
+
},
|
|
2243
|
+
frameId: fallbackReadbackRequest.expected.frameId,
|
|
2244
|
+
graphGeneration: fallbackReadbackRequest.expected.graphGeneration,
|
|
2245
|
+
textureIdentity: fallbackReadbackRequest.expected.textureIdentity,
|
|
2246
|
+
readback: fallbackReadback,
|
|
2247
|
+
},
|
|
2248
|
+
frameState.reflectionFallbackDemand,
|
|
2249
|
+
);
|
|
2250
|
+
frameState.reflectionFallbackCompletion = reflectionFallbackCompletion;
|
|
2251
|
+
frameState.reflectionFallbackObservationSource = undefined;
|
|
1956
2252
|
if (submitted && !directionalShadowCache.reuse) {
|
|
1957
2253
|
frameState.directionalShadowCache = frameState.directionalShadowCacheRecorded
|
|
1958
2254
|
? directionalShadowCache.next
|
|
@@ -2038,7 +2334,7 @@ interface DirectionalShadowCacheDecision {
|
|
|
2038
2334
|
function readWorldState(lease: RenderReadLease): DirectionalShadowWorldState {
|
|
2039
2335
|
return {
|
|
2040
2336
|
worldIdentity: lease.worldIdentity,
|
|
2041
|
-
|
|
2337
|
+
version: lease.captureVersion(),
|
|
2042
2338
|
};
|
|
2043
2339
|
}
|
|
2044
2340
|
|
|
@@ -2060,16 +2356,14 @@ function sameWorldState(
|
|
|
2060
2356
|
if (cachedState.worldIdentity !== lease.worldIdentity) return false;
|
|
2061
2357
|
let changes: ReturnType<RenderReadLease['readChanges']>;
|
|
2062
2358
|
try {
|
|
2063
|
-
changes = lease.readChanges(cachedState.
|
|
2359
|
+
changes = lease.readChanges(cachedState.version);
|
|
2064
2360
|
} catch {
|
|
2065
|
-
//
|
|
2066
|
-
//
|
|
2067
|
-
// rebuild the atlas from the current lease rather than reaching into
|
|
2068
|
-
// World for a second mutation clock.
|
|
2361
|
+
// Treat malformed or foreign version evidence as stale and rebuild the
|
|
2362
|
+
// atlas rather than reaching through World for a second mutation clock.
|
|
2069
2363
|
return false;
|
|
2070
2364
|
}
|
|
2071
2365
|
if (changes.status !== 'ok') return false;
|
|
2072
|
-
if (changes.world.
|
|
2366
|
+
if (changes.world.changedComponentIds.length !== 0 || changes.sharedRefs.records.length !== 0) {
|
|
2073
2367
|
return false;
|
|
2074
2368
|
}
|
|
2075
2369
|
}
|
|
@@ -2205,6 +2499,7 @@ function validateRenderables(
|
|
|
2205
2499
|
renderables: readonly RenderableSnapshot[],
|
|
2206
2500
|
transparentDispatch: readonly DispatchEntry[],
|
|
2207
2501
|
excludedEntityKeys: ReadonlySet<number> = new Set<number>(),
|
|
2502
|
+
worldKeys?: readonly number[],
|
|
2208
2503
|
): ValidatedRenderable[] {
|
|
2209
2504
|
// bug-20260527-renderstate-pipeline-dispatch-gap D-4:
|
|
2210
2505
|
// build a renderableIndex -> renderState map from dispatch entries
|
|
@@ -2230,7 +2525,8 @@ function validateRenderables(
|
|
|
2230
2525
|
for (let rIdx = 0; rIdx < renderables.length; rIdx++) {
|
|
2231
2526
|
const r = renderables[rIdx];
|
|
2232
2527
|
if (r === undefined) continue;
|
|
2233
|
-
if (excludedEntityKeys.has(worldEntityKey(r.worldId, r.entityKey)))
|
|
2528
|
+
if (excludedEntityKeys.has(worldEntityKey(worldKeys?.[r.worldId] ?? r.worldId, r.entityKey)))
|
|
2529
|
+
continue;
|
|
2234
2530
|
// feat-20260709-editor-world-partition ENGINE-fix-round2 (defect 2): resolve
|
|
2235
2531
|
// this renderable's mesh against the world it was EXTRACTED from
|
|
2236
2532
|
// (worlds[r.worldId]) — NOT the single resource-owner `world`. Builtin mesh
|
|
@@ -2265,11 +2561,17 @@ function validateRenderables(
|
|
|
2265
2561
|
// frames hit the O(1) cache.
|
|
2266
2562
|
const meshAssetHandle = toShared<'MeshAsset'>(r.assetHandle);
|
|
2267
2563
|
let meshHandles = internals.gpuStore.getMeshGpuHandles(meshAssetHandle, renderableWorld);
|
|
2564
|
+
const lodMeshes = r.lods?.map((lod) => internals.assets.lookup<MeshAsset>(lod.mesh));
|
|
2565
|
+
const resolvedLodMeshes =
|
|
2566
|
+
lodMeshes?.every((lod): lod is MeshAsset => lod?.kind === 'mesh') === true
|
|
2567
|
+
? lodMeshes
|
|
2568
|
+
: undefined;
|
|
2268
2569
|
if (meshHandles === undefined && r.assetHandle > handleSlot(HANDLE_NINESLICE_QUAD)) {
|
|
2269
2570
|
const residentRes = internals.gpuStore.ensureResident(
|
|
2270
2571
|
meshAssetHandle,
|
|
2271
2572
|
assetRes.value,
|
|
2272
2573
|
renderableWorld,
|
|
2574
|
+
resolvedLodMeshes,
|
|
2273
2575
|
);
|
|
2274
2576
|
if (residentRes.ok) {
|
|
2275
2577
|
meshHandles = residentRes.value;
|
|
@@ -2451,6 +2753,21 @@ function buildDispatchPlan(
|
|
|
2451
2753
|
materialSlotOwners: readonly number[];
|
|
2452
2754
|
materialSlotCount: number;
|
|
2453
2755
|
} {
|
|
2756
|
+
// A production GPU-owned frame has no CPU validated rows by design. The
|
|
2757
|
+
// dispatch list can still contain one entry per authored entity, but no
|
|
2758
|
+
// CPU plan, material table, or fold bucket is consumed in that lane. Return
|
|
2759
|
+
// the empty plan without walking that list so a steady 100k scene remains
|
|
2760
|
+
// bounded by the persistent GPU batches rather than per-entity record work.
|
|
2761
|
+
if (validated.length === 0) {
|
|
2762
|
+
return {
|
|
2763
|
+
validatedOrdered: [],
|
|
2764
|
+
foldDispatchPlan: null,
|
|
2765
|
+
materialSlotIndices: [],
|
|
2766
|
+
materialSlots: [],
|
|
2767
|
+
materialSlotOwners: [],
|
|
2768
|
+
materialSlotCount: 0,
|
|
2769
|
+
};
|
|
2770
|
+
}
|
|
2454
2771
|
// M3 / w26: dispatch-ordered render. The dispatch list is pre-sorted
|
|
2455
2772
|
// by queue (ascending, stable) by the extract stage per plan-strategy D-3.
|
|
2456
2773
|
// Reorder validated renderables to follow the dispatch order, falling
|