@forgeax/engine-render 0.1.19 → 0.1.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +215 -0
- package/dist/.tsbuildinfo +1 -1
- package/dist/assembly/device-feature-admission.d.ts +18 -0
- package/dist/assembly/device-feature-admission.d.ts.map +1 -0
- package/dist/assembly/directional-shadow-inspection.d.ts +38 -0
- package/dist/assembly/directional-shadow-inspection.d.ts.map +1 -0
- package/dist/assembly/factory.d.ts +34 -20
- package/dist/assembly/factory.d.ts.map +1 -1
- package/dist/assembly/host-contract.d.ts +9 -0
- package/dist/assembly/host-contract.d.ts.map +1 -1
- package/dist/assembly/render-target-host.d.ts +46 -0
- package/dist/assembly/render-target-host.d.ts.map +1 -0
- package/dist/assets/render-asset-port.d.ts.map +1 -1
- package/dist/authoring.mjs +3 -0
- package/dist/authoring.mjs.map +1 -1
- package/dist/capture/cube-views.d.ts +21 -0
- package/dist/capture/cube-views.d.ts.map +1 -0
- package/dist/capture/scheduler.d.ts +54 -0
- package/dist/capture/scheduler.d.ts.map +1 -0
- package/dist/{chunk-RJRUS55L.mjs → chunk-5YADUCA7.mjs} +1896 -1624
- package/dist/chunk-5YADUCA7.mjs.map +1 -0
- package/dist/{chunk-LOSO4CTV.mjs → chunk-6OPXDQ2E.mjs} +423 -46
- package/dist/chunk-6OPXDQ2E.mjs.map +1 -0
- package/dist/{chunk-IPXCABEP.mjs → chunk-BXBQQKFQ.mjs} +3 -9
- package/dist/chunk-BXBQQKFQ.mjs.map +1 -0
- package/dist/chunk-FS2KNUQH.mjs +1294 -0
- package/dist/chunk-FS2KNUQH.mjs.map +1 -0
- package/dist/components/camera.d.ts +1 -0
- package/dist/components/camera.d.ts.map +1 -1
- package/dist/components/cube-camera.d.ts +20 -0
- package/dist/components/cube-camera.d.ts.map +1 -0
- package/dist/components/directional-light.d.ts +11 -2
- package/dist/components/directional-light.d.ts.map +1 -1
- package/dist/components/directional-shadow-filter.d.ts +25 -0
- package/dist/components/directional-shadow-filter.d.ts.map +1 -0
- package/dist/components/index.d.ts +2 -0
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/light-helpers.d.ts.map +1 -1
- package/dist/components/reflection-probe.d.ts +17 -0
- package/dist/components/reflection-probe.d.ts.map +1 -0
- package/dist/components/spot-light.d.ts +12 -0
- package/dist/components/spot-light.d.ts.map +1 -1
- package/dist/construct-renderer.mjs +8552 -1612
- package/dist/construct-renderer.mjs.map +1 -1
- package/dist/device/gpu-residency.d.ts +19 -2
- package/dist/device/gpu-residency.d.ts.map +1 -1
- package/dist/environment/frame.d.ts.map +1 -1
- package/dist/environment/lifecycle.d.ts +5 -0
- package/dist/environment/lifecycle.d.ts.map +1 -1
- package/dist/errors/render.d.ts +209 -93
- package/dist/errors/render.d.ts.map +1 -1
- package/dist/extract/directional-shadow-projection.d.ts +23 -0
- package/dist/extract/directional-shadow-projection.d.ts.map +1 -0
- package/dist/extract/environment.d.ts +14 -0
- package/dist/extract/environment.d.ts.map +1 -1
- package/dist/extract/visibility.d.ts.map +1 -1
- package/dist/features/fullscreen.d.ts.map +1 -1
- package/dist/features/targets.d.ts.map +1 -1
- package/dist/features/types.d.ts +10 -0
- package/dist/features/types.d.ts.map +1 -1
- package/dist/fullscreen-post-process-pass.d.ts +13 -2
- package/dist/fullscreen-post-process-pass.d.ts.map +1 -1
- package/dist/gpu-driven/batch-topology.d.ts.map +1 -1
- package/dist/gpu-driven/production-raster.d.ts +0 -1
- package/dist/gpu-driven/production-raster.d.ts.map +1 -1
- package/dist/gpu-scene.d.ts.map +1 -1
- package/dist/gpu-usage.d.ts +2 -0
- package/dist/gpu-usage.d.ts.map +1 -1
- package/dist/hdrp-buffers.d.ts +19 -17
- package/dist/hdrp-buffers.d.ts.map +1 -1
- package/dist/ibl/IblPipelineCache.d.ts +4 -0
- package/dist/ibl/IblPipelineCache.d.ts.map +1 -1
- package/dist/ibl/kernel-cache.d.ts +36 -0
- package/dist/ibl/kernel-cache.d.ts.map +1 -0
- package/dist/index.d.ts +35 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.mjs +4 -4
- package/dist/index.mjs.map +1 -1
- package/dist/inspection-types.d.ts +51 -0
- package/dist/inspection-types.d.ts.map +1 -1
- package/dist/instances-derived-bounds.d.ts +50 -0
- package/dist/instances-derived-bounds.d.ts.map +1 -0
- package/dist/internal.mjs +1 -1
- package/dist/light-buffer-layout.d.ts +30 -13
- package/dist/light-buffer-layout.d.ts.map +1 -1
- package/dist/mesh-material-bindings.d.ts +54 -0
- package/dist/mesh-material-bindings.d.ts.map +1 -1
- package/dist/pbr-pipeline.d.ts +20 -7
- package/dist/pbr-pipeline.d.ts.map +1 -1
- package/dist/pipeline/standard-forward-lane.d.ts +2 -1
- package/dist/pipeline/standard-forward-lane.d.ts.map +1 -1
- package/dist/pipeline/standard-lighting/errors.d.ts +4 -0
- package/dist/pipeline/standard-lighting/errors.d.ts.map +1 -0
- package/dist/pipeline/standard-lighting/graph.d.ts +24 -0
- package/dist/pipeline/standard-lighting/graph.d.ts.map +1 -0
- package/dist/pipeline/standard-lighting/inspection.d.ts +38 -0
- package/dist/pipeline/standard-lighting/inspection.d.ts.map +1 -0
- package/dist/pipeline/standard-lighting/layout.d.ts +28 -0
- package/dist/pipeline/standard-lighting/layout.d.ts.map +1 -0
- package/dist/pipeline/standard-lighting/light-frame.d.ts +33 -0
- package/dist/pipeline/standard-lighting/light-frame.d.ts.map +1 -0
- package/dist/pipeline/standard-lighting/membership.d.ts +14 -0
- package/dist/pipeline/standard-lighting/membership.d.ts.map +1 -0
- package/dist/pipeline/standard-lighting/prepare.d.ts +16 -0
- package/dist/pipeline/standard-lighting/prepare.d.ts.map +1 -0
- package/dist/pipeline/standard-lighting/topology.d.ts +45 -0
- package/dist/pipeline/standard-lighting/topology.d.ts.map +1 -0
- package/dist/pipeline/standard-lighting/transport.d.ts +36 -0
- package/dist/pipeline/standard-lighting/transport.d.ts.map +1 -0
- package/dist/pipeline/standard-pipeline.d.ts +4 -13
- package/dist/pipeline/standard-pipeline.d.ts.map +1 -1
- package/dist/pipeline/standard-post.d.ts.map +1 -1
- package/dist/pipeline/standard-profile.d.ts +12 -20
- package/dist/pipeline/standard-profile.d.ts.map +1 -1
- package/dist/pipeline-spec.d.ts +40 -7
- package/dist/pipeline-spec.d.ts.map +1 -1
- package/dist/point-shadow-inspection.d.ts +21 -0
- package/dist/point-shadow-inspection.d.ts.map +1 -0
- package/dist/record/frame-lighting.d.ts +29 -32
- package/dist/record/frame-lighting.d.ts.map +1 -1
- package/dist/record/frame-snapshot.d.ts +65 -15
- package/dist/record/frame-snapshot.d.ts.map +1 -1
- package/dist/record/frame-targets.d.ts +5 -0
- package/dist/record/frame-targets.d.ts.map +1 -1
- package/dist/record/frame.d.ts +12 -5
- package/dist/record/frame.d.ts.map +1 -1
- package/dist/record/gpu-pass-timing/contract.d.ts +96 -0
- package/dist/record/gpu-pass-timing/contract.d.ts.map +1 -0
- package/dist/record/gpu-pass-timing/errors.d.ts +18 -0
- package/dist/record/gpu-pass-timing/errors.d.ts.map +1 -0
- package/dist/record/gpu-pass-timing/index.d.ts +8 -0
- package/dist/record/gpu-pass-timing/index.d.ts.map +1 -0
- package/dist/record/gpu-pass-timing/parser.d.ts +11 -0
- package/dist/record/gpu-pass-timing/parser.d.ts.map +1 -0
- package/dist/record/gpu-pass-timing/session.d.ts +43 -0
- package/dist/record/gpu-pass-timing/session.d.ts.map +1 -0
- package/dist/record/gpu-timing.d.ts +37 -0
- package/dist/record/gpu-timing.d.ts.map +1 -0
- package/dist/record/main-pass-geometry.d.ts.map +1 -1
- package/dist/record/main-pass-material.d.ts +23 -2
- package/dist/record/main-pass-material.d.ts.map +1 -1
- package/dist/record/main-pass-sprite-draws.d.ts.map +1 -1
- package/dist/record/main-pass.d.ts +2 -0
- package/dist/record/main-pass.d.ts.map +1 -1
- package/dist/record/render-context.d.ts +48 -3
- package/dist/record/render-context.d.ts.map +1 -1
- package/dist/record/shadow-pass.d.ts.map +1 -1
- package/dist/record/skybox-post-pass.d.ts.map +1 -1
- package/dist/record/typed-frame-graph.d.ts +81 -5
- package/dist/record/typed-frame-graph.d.ts.map +1 -1
- package/dist/record/view-ubo.d.ts +7 -4
- package/dist/record/view-ubo.d.ts.map +1 -1
- package/dist/reflection/filter.d.ts +22 -0
- package/dist/reflection/filter.d.ts.map +1 -0
- package/dist/reflection/gpu-table.d.ts +25 -0
- package/dist/reflection/gpu-table.d.ts.map +1 -0
- package/dist/reflection/projection.d.ts +91 -0
- package/dist/reflection/projection.d.ts.map +1 -0
- package/dist/render-contract.d.ts +114 -7
- package/dist/render-contract.d.ts.map +1 -1
- package/dist/render-data.d.ts +10 -6
- package/dist/render-data.d.ts.map +1 -1
- package/dist/render-graph-primitives.d.ts +1 -0
- package/dist/render-graph-primitives.d.ts.map +1 -1
- package/dist/render-pipeline.d.ts +78 -2
- package/dist/render-pipeline.d.ts.map +1 -1
- package/dist/render-system-extract.d.ts +113 -20
- package/dist/render-system-extract.d.ts.map +1 -1
- package/dist/render-system.d.ts +24 -3
- package/dist/render-system.d.ts.map +1 -1
- package/dist/renderer-inspect.d.ts +29 -0
- package/dist/renderer-inspect.d.ts.map +1 -0
- package/dist/renderer.d.ts +43 -0
- package/dist/renderer.d.ts.map +1 -0
- package/dist/scene/render-scene.d.ts +14 -0
- package/dist/scene/render-scene.d.ts.map +1 -1
- package/dist/shadow-atlas.d.ts +3 -3
- package/dist/shadow-atlas.d.ts.map +1 -1
- package/dist/ssao-buffers.d.ts +3 -0
- package/dist/ssao-buffers.d.ts.map +1 -1
- package/dist/targets/contracts.d.ts +66 -0
- package/dist/targets/contracts.d.ts.map +1 -0
- package/dist/targets/graph-projection.d.ts +29 -0
- package/dist/targets/graph-projection.d.ts.map +1 -0
- package/dist/targets/material-source.d.ts +34 -0
- package/dist/targets/material-source.d.ts.map +1 -0
- package/dist/targets/owner.d.ts +32 -0
- package/dist/targets/owner.d.ts.map +1 -0
- package/dist/targets/physical.d.ts +18 -0
- package/dist/targets/physical.d.ts.map +1 -0
- package/dist/targets/readback.d.ts +39 -0
- package/dist/targets/readback.d.ts.map +1 -0
- package/dist/temporal/frame.d.ts +44 -0
- package/dist/temporal/frame.d.ts.map +1 -0
- package/dist/temporal/index.mjs +3 -3
- package/dist/typed-render-graph-primitives.d.ts +6 -1
- package/dist/typed-render-graph-primitives.d.ts.map +1 -1
- package/dist/typed-shadow-atlas.d.ts +10 -0
- package/dist/typed-shadow-atlas.d.ts.map +1 -0
- package/dist/typed-shadow-passes.d.ts +1 -1
- package/dist/typed-shadow-passes.d.ts.map +1 -1
- package/dist/volume/capability.d.ts +57 -0
- package/dist/volume/capability.d.ts.map +1 -0
- package/dist/volume/component.d.ts +61 -0
- package/dist/volume/component.d.ts.map +1 -0
- package/dist/volume/extract.d.ts +11 -0
- package/dist/volume/extract.d.ts.map +1 -0
- package/dist/volume/inspection.d.ts +38 -0
- package/dist/volume/inspection.d.ts.map +1 -0
- package/dist/volume/passes.d.ts +38 -0
- package/dist/volume/passes.d.ts.map +1 -0
- package/dist/volume/recovery.d.ts +38 -0
- package/dist/volume/recovery.d.ts.map +1 -0
- package/dist/volume/resources.d.ts +57 -0
- package/dist/volume/resources.d.ts.map +1 -0
- package/dist/volume/temporal.d.ts +35 -0
- package/dist/volume/temporal.d.ts.map +1 -0
- package/package.json +20 -20
- package/src/__tests__/bloom-exact-zero.unit.test.ts +48 -19
- package/src/__tests__/bloom-lifecycle.integration.test.ts +41 -13
- package/src/__tests__/camera-target-consumption.unit.test.ts +53 -0
- package/src/__tests__/cluster-binner.unit.test.ts +35 -0
- package/src/__tests__/cluster-grid-default-surface.unit.test.ts +7 -2
- package/src/__tests__/cube-camera-scheduler.unit.test.ts +70 -0
- package/src/__tests__/cube-camera-single-submit.perf.test.ts +75 -0
- package/src/__tests__/cube-camera-view-matrices.unit.test.ts +41 -0
- package/src/__tests__/cube-camera-vocabulary.unit.test.ts +47 -0
- package/src/__tests__/cube-camera.integration.test.ts +42 -0
- package/src/__tests__/device-feature-admission.unit.test.ts +73 -0
- package/src/__tests__/direct-light-snapshot.unit.test.ts +3 -3
- package/src/__tests__/docs-gate-green.unit.test.ts +38 -0
- package/src/__tests__/factory-contract.integration.test.ts +255 -29
- package/src/__tests__/fog-component.unit.test.ts +67 -0
- package/src/__tests__/fog.integration.test.ts +86 -0
- package/src/__tests__/fullscreen-feature-plan.unit.test.ts +37 -0
- package/src/__tests__/gpu-driven-indirect-raster-evidence.ts +10 -9
- package/src/__tests__/gpu-driven-indirect-raster.dawn.test.ts +17 -1
- package/src/__tests__/gpu-driven-production.integration.test.ts +16 -17
- package/src/__tests__/gpu-driven-view-graph.integration.test.ts +12 -4
- package/src/__tests__/gpu-pass-timing-browser-runner.ts +281 -0
- package/src/__tests__/gpu-pass-timing-coexistence.integration.test.ts +80 -0
- package/src/__tests__/gpu-pass-timing-contract.unit.test.ts +243 -0
- package/src/__tests__/gpu-pass-timing-exact-zero.unit.test.ts +131 -0
- package/src/__tests__/gpu-pass-timing-lifecycle.integration.test.ts +230 -0
- package/src/__tests__/gpu-pass-timing-observation.unit.test.ts +233 -0
- package/src/__tests__/gpu-pass-timing-session.unit.test.ts +438 -0
- package/src/__tests__/gpu-pass-timing.browser.test.ts +26 -0
- package/src/__tests__/gpu-pass-timing.rhi-null.unit.test.ts +125 -0
- package/src/__tests__/hdrp-group2-visibility.unit.test.ts +24 -0
- package/src/__tests__/instances-culling.integration.test.ts +94 -0
- package/src/__tests__/instances-derived-bounds.unit.test.ts +118 -0
- package/src/__tests__/ktx2-basis-gpu-consumer.dawn.test.ts +14 -14
- package/src/__tests__/material-observation.integration.test.ts +101 -0
- package/src/__tests__/mesh-buffer-usage-surface.unit.test.ts +1 -1
- package/src/__tests__/pbr-view-layout.unit.test.ts +16 -0
- package/src/__tests__/point-shadow-inspection.unit.test.ts +60 -0
- package/src/__tests__/public-surface.test-d.ts +10 -0
- package/src/__tests__/reflection-probe-authoring.unit.test.ts +71 -0
- package/src/__tests__/reflection-probe-filter.unit.test.ts +54 -0
- package/src/__tests__/reflection-probe-ibl-topology.unit.test.ts +45 -0
- package/src/__tests__/reflection-probe-pass-encode.integration.test.ts +101 -0
- package/src/__tests__/reflection-probe-performance.perf.test.ts +60 -0
- package/src/__tests__/reflection-probe-recovery.integration.test.ts +55 -0
- package/src/__tests__/reflection-probe-selection.unit.test.ts +46 -0
- package/src/__tests__/render-error-code-owner.test-d.ts +23 -3
- package/src/__tests__/render-feature-docs.unit.test.ts +1 -1
- package/src/__tests__/render-target-admission.unit.test.ts +80 -0
- package/src/__tests__/render-target-graph-projection.unit.test.ts +102 -0
- package/src/__tests__/render-target-inspection.unit.test.ts +52 -0
- package/src/__tests__/render-target-material-source.test-d.ts +30 -0
- package/src/__tests__/render-target-material-source.unit.test.ts +97 -0
- package/src/__tests__/render-target-owner-placement.unit.test.ts +203 -0
- package/src/__tests__/render-target-owner.unit.test.ts +122 -0
- package/src/__tests__/render-target-probe-soak.perf.test.ts +94 -0
- package/src/__tests__/render-target-public-schema.json +107 -0
- package/src/__tests__/render-target-public-schema.unit.test.ts +91 -0
- package/src/__tests__/render-target-public-surface.test-d.ts +83 -0
- package/src/__tests__/render-target-readback.integration.test.ts +90 -0
- package/src/__tests__/render-target-recovery.integration.test.ts +85 -0
- package/src/__tests__/renderer-factory-material-contract.unit.test.ts +76 -0
- package/src/__tests__/renderer-frame-transaction.integration.test.ts +1 -1
- package/src/__tests__/renderer-lifecycle.integration.test.ts +14 -0
- package/src/__tests__/shader-stage-surface.unit.test.ts +19 -4
- package/src/__tests__/skin-motion-regression.unit.test.ts +132 -0
- package/src/__tests__/skinned-shadow-caster.test.ts +32 -2
- package/src/__tests__/standard-cluster-capability.integration.test.ts +63 -0
- package/src/__tests__/standard-cluster-transport.unit.test.ts +121 -0
- package/src/__tests__/standard-cluster-variant-resolution.unit.test.ts +232 -0
- package/src/__tests__/standard-clustered-pipeline.unit.test.ts +8 -5
- package/src/__tests__/standard-lighting-inspection.integration.test.ts +138 -0
- package/src/__tests__/standard-lighting-ssot.unit.test.ts +18 -0
- package/src/__tests__/standard-lighting-write.unit.test.ts +377 -0
- package/src/__tests__/standard-lighting.integration.test.ts +67 -0
- package/src/__tests__/standard-pipeline.dawn.test.ts +206 -5
- package/src/__tests__/standard-pipeline.integration.test.ts +181 -150
- package/src/__tests__/standard-probe-binding.unit.test.ts +25 -0
- package/src/__tests__/standard-profile-oracle.unit.test.ts +23 -36
- package/src/__tests__/typed-pipeline-topology.unit.test.ts +395 -14
- package/src/__tests__/urp-pipeline-targets.unit.test.ts +2 -2
- package/src/__tests__/visibility-resolver.unit.test.ts +15 -0
- package/src/__tests__/volume-optics-oracle.unit.test.ts +85 -0
- package/src/__tests__/volumetric-fog-budget-recovery.integration.test.ts +655 -0
- package/src/__tests__/volumetric-fog-component.unit.test.ts +71 -0
- package/src/__tests__/volumetric-fog-composite-stage-readback.dawn.test.ts +376 -0
- package/src/__tests__/volumetric-fog-errors.unit.test.ts +51 -0
- package/src/__tests__/volumetric-fog-inspection.unit.test.ts +77 -0
- package/src/__tests__/volumetric-fog-light-capability.unit.test.ts +19 -0
- package/src/__tests__/volumetric-fog-light-consumers.integration.test.ts +18 -0
- package/src/__tests__/volumetric-fog-light-errors.unit.test.ts +17 -0
- package/src/__tests__/volumetric-fog-light-topology.unit.test.ts +21 -0
- package/src/__tests__/volumetric-fog-light-transaction.integration.test.ts +53 -0
- package/src/__tests__/volumetric-fog-m9-watcher.integration.test.ts +27 -0
- package/src/__tests__/volumetric-fog-point-light-owner.integration.test.ts +44 -0
- package/src/__tests__/volumetric-fog-point-spot-accumulation.integration.test.ts +49 -0
- package/src/__tests__/volumetric-fog-point-spot-contract.unit.test.ts +28 -0
- package/src/__tests__/volumetric-fog-point-spot-lkg.integration.test.ts +65 -0
- package/src/__tests__/volumetric-fog-point-spot-selection.integration.test.ts +49 -0
- package/src/__tests__/volumetric-fog-point-spot-temporal.unit.test.ts +55 -0
- package/src/__tests__/volumetric-fog-projector-contract.unit.test.ts +22 -0
- package/src/__tests__/volumetric-fog-projector-inspection.unit.test.ts +12 -0
- package/src/__tests__/volumetric-fog-projector-surface-volume.integration.test.ts +11 -0
- package/src/__tests__/volumetric-fog-projector-transaction.integration.test.ts +26 -0
- package/src/__tests__/volumetric-fog-recovery.integration.test.ts +47 -0
- package/src/__tests__/volumetric-fog-selected-light-resolution.integration.test.ts +63 -0
- package/src/__tests__/volumetric-fog-spot-closure.integration.test.ts +26 -0
- package/src/__tests__/volumetric-fog-spot-contract.test-d.ts +21 -0
- package/src/__tests__/volumetric-fog-spot-contract.unit.test.ts +27 -0
- package/src/__tests__/volumetric-fog-spot-frame-optics.integration.test.ts +14 -0
- package/src/__tests__/volumetric-fog-spot-optics.integration.test.ts +29 -0
- package/src/__tests__/volumetric-fog-stage-readback.dawn.test.ts +550 -0
- package/src/__tests__/volumetric-fog-temporal-selected-light.unit.test.ts +33 -0
- package/src/__tests__/volumetric-fog-temporal.unit.test.ts +45 -0
- package/src/__tests__/volumetric-fog-topology.unit.test.ts +237 -0
- package/src/__tests__/volumetric-fog-transparent.integration.test.ts +27 -0
- package/src/assembly/device-feature-admission.ts +73 -0
- package/src/assembly/directional-shadow-inspection.ts +122 -0
- package/src/assembly/factory.ts +1093 -246
- package/src/assembly/host-contract.ts +25 -0
- package/src/assembly/render-target-host.ts +847 -0
- package/src/assets/asset-decoders.ts +1 -1
- package/src/assets/render-asset-port.ts +7 -1
- package/src/capture/cube-views.ts +69 -0
- package/src/capture/scheduler.ts +265 -0
- package/src/components/__tests__/schema-contract.unit.test.ts +12 -0
- package/src/components/__tests__/schema-parity.unit.test.ts +9 -0
- package/src/components/camera.ts +4 -0
- package/src/components/cube-camera.ts +52 -0
- package/src/components/directional-light.ts +22 -2
- package/src/components/directional-shadow-filter.ts +57 -0
- package/src/components/index.ts +2 -0
- package/src/components/light-helpers.ts +85 -7
- package/src/components/reflection-probe.ts +49 -0
- package/src/components/spot-light.ts +22 -3
- package/src/device/gpu-residency.ts +168 -58
- package/src/environment/frame.ts +6 -24
- package/src/environment/lifecycle.ts +12 -0
- package/src/errors/render.ts +405 -143
- package/src/extract/directional-shadow-projection.ts +61 -0
- package/src/extract/environment.ts +57 -0
- package/src/extract/visibility.ts +25 -1
- package/src/features/fullscreen.ts +3 -0
- package/src/features/targets.ts +4 -1
- package/src/features/types.ts +10 -0
- package/src/fullscreen-post-process-pass.ts +43 -2
- package/src/gpu-driven/batch-topology.ts +1 -0
- package/src/gpu-driven/production-raster.ts +1 -3
- package/src/gpu-scene.ts +8 -1
- package/src/gpu-usage.ts +2 -0
- package/src/hdrp-buffers.ts +165 -59
- package/src/ibl/IblPipelineCache.ts +11 -0
- package/src/ibl/kernel-cache.ts +88 -0
- package/src/index.ts +186 -1
- package/src/inspection-types.ts +56 -0
- package/src/instances-derived-bounds.ts +171 -0
- package/src/light-buffer-layout.ts +74 -26
- package/src/mesh-material-bindings.ts +132 -0
- package/src/pbr-pipeline.ts +139 -27
- package/src/pipeline/standard-forward-lane.ts +65 -15
- package/src/pipeline/standard-lighting/errors.ts +6 -0
- package/src/pipeline/standard-lighting/graph.ts +157 -0
- package/src/pipeline/standard-lighting/inspection.ts +88 -0
- package/src/pipeline/standard-lighting/layout.ts +31 -0
- package/src/pipeline/standard-lighting/light-frame.ts +34 -0
- package/src/pipeline/standard-lighting/membership.ts +43 -0
- package/src/pipeline/standard-lighting/prepare.ts +37 -0
- package/src/pipeline/standard-lighting/topology.ts +120 -0
- package/src/pipeline/standard-lighting/transport.ts +77 -0
- package/src/pipeline/standard-pipeline.ts +141 -192
- package/src/pipeline/standard-post.ts +26 -7
- package/src/pipeline/standard-profile.ts +23 -30
- package/src/pipeline-spec.ts +84 -21
- package/src/point-shadow-inspection.ts +55 -0
- package/src/record/__tests__/temporal-payload.unit.test.ts +42 -1
- package/src/record/__tests__/transparent-group2-selection.unit.test.ts +73 -0
- package/src/record/__tests__/view-ubo-layout.unit.test.ts +40 -0
- package/src/record/frame-lighting.ts +470 -516
- package/src/record/frame-snapshot.ts +76 -28
- package/src/record/frame-targets.ts +23 -2
- package/src/record/frame.ts +1169 -79
- package/src/record/gpu-pass-timing/contract.ts +180 -0
- package/src/record/gpu-pass-timing/errors.ts +34 -0
- package/src/record/gpu-pass-timing/index.ts +37 -0
- package/src/record/gpu-pass-timing/parser.ts +97 -0
- package/src/record/gpu-pass-timing/session.ts +938 -0
- package/src/record/gpu-timing.ts +233 -0
- package/src/record/main-pass-geometry.ts +120 -80
- package/src/record/main-pass-material.ts +101 -11
- package/src/record/main-pass-sprite-draws.ts +54 -25
- package/src/record/main-pass.ts +71 -15
- package/src/record/render-context.ts +77 -0
- package/src/record/shadow-pass.ts +104 -66
- package/src/record/skybox-post-pass.ts +20 -4
- package/src/record/typed-frame-graph.ts +1016 -32
- package/src/record/view-ubo.ts +63 -28
- package/src/reflection/filter.ts +81 -0
- package/src/reflection/gpu-table.ts +44 -0
- package/src/reflection/projection.ts +281 -0
- package/src/render-contract.ts +147 -4
- package/src/render-data.ts +50 -22
- package/src/render-graph-primitives.ts +9 -4
- package/src/render-pipeline.ts +161 -2
- package/src/render-system-extract.ts +886 -103
- package/src/render-system.ts +1174 -66
- package/src/renderer-inspect.ts +66 -0
- package/src/renderer.ts +222 -0
- package/src/scene/render-scene.ts +117 -9
- package/src/shadow-atlas.ts +5 -5
- package/src/ssao-buffers.ts +9 -2
- package/src/targets/contracts.ts +182 -0
- package/src/targets/graph-projection.ts +169 -0
- package/src/targets/material-source.ts +143 -0
- package/src/targets/owner.ts +214 -0
- package/src/targets/physical.ts +18 -0
- package/src/targets/readback.ts +153 -0
- package/src/temporal/frame.ts +128 -0
- package/src/transmission/__tests__/standard-transmission.dawn.test.ts +61 -23
- package/src/typed-render-graph-primitives.ts +34 -2
- package/src/typed-shadow-atlas.ts +17 -0
- package/src/typed-shadow-passes.ts +47 -40
- package/src/volume/capability.ts +173 -0
- package/src/volume/component.ts +110 -0
- package/src/volume/extract.ts +21 -0
- package/src/volume/inspection.ts +78 -0
- package/src/volume/passes.ts +686 -0
- package/src/volume/recovery.ts +86 -0
- package/src/volume/resources.ts +236 -0
- package/src/volume/temporal.ts +89 -0
- package/dist/chunk-IPXCABEP.mjs.map +0 -1
- package/dist/chunk-LOSO4CTV.mjs.map +0 -1
- package/dist/chunk-RJRUS55L.mjs.map +0 -1
- package/dist/chunk-YTQ5C7YQ.mjs +0 -584
- package/dist/chunk-YTQ5C7YQ.mjs.map +0 -1
|
@@ -17,12 +17,17 @@
|
|
|
17
17
|
import { err, ok, type Result } from '@forgeax/engine-types';
|
|
18
18
|
import { SpawnLightInvalidBoundsError } from '../errors/ecs-validation';
|
|
19
19
|
import { ShadowInvalidConfigError } from '../errors/render';
|
|
20
|
+
import { DirectionalShadowFilterValue } from './directional-shadow-filter';
|
|
20
21
|
|
|
21
22
|
export type LightValidationError = SpawnLightInvalidBoundsError | ShadowInvalidConfigError;
|
|
22
23
|
export type LightValidationResult = Result<void, LightValidationError>;
|
|
23
24
|
|
|
24
25
|
const RANGE_ZERO_FALLBACK_INV_R2 = 1e8;
|
|
25
26
|
const DEG_TO_RAD = Math.PI / 180;
|
|
27
|
+
const PCSS_RADIUS_MIN = 0.0001;
|
|
28
|
+
const PCSS_RADIUS_MAX = 0.05;
|
|
29
|
+
const PCSS_PENUMBRA_MIN = 1;
|
|
30
|
+
const PCSS_PENUMBRA_MAX = 64;
|
|
26
31
|
|
|
27
32
|
/**
|
|
28
33
|
* Convert SpotLight cone half-angle (degrees) to its cosine.
|
|
@@ -97,7 +102,9 @@ export function validateDirectionalLightData(
|
|
|
97
102
|
if (data.castShadow === false) return ok(undefined);
|
|
98
103
|
|
|
99
104
|
const mapSize = (data.mapSize as number | undefined) ?? 2048;
|
|
100
|
-
if (mapSize < 1)
|
|
105
|
+
if (mapSize < 1) {
|
|
106
|
+
return err(new ShadowInvalidConfigError('mapSize', mapSize, 1));
|
|
107
|
+
}
|
|
101
108
|
const cascadeCount = (data.cascadeCount as number | undefined) ?? 4;
|
|
102
109
|
if (cascadeCount < 1 || cascadeCount > 4 || !Number.isInteger(cascadeCount)) {
|
|
103
110
|
return err(new ShadowInvalidConfigError('cascadeCount', cascadeCount, 1, 4));
|
|
@@ -110,14 +117,65 @@ export function validateDirectionalLightData(
|
|
|
110
117
|
if (cascadeBlend < 0 || cascadeBlend > 0.5) {
|
|
111
118
|
return err(new ShadowInvalidConfigError('cascadeBlend', cascadeBlend, 0, 0.5));
|
|
112
119
|
}
|
|
113
|
-
const pcfKernelSize = (data.pcfKernelSize as number | undefined) ?? 3;
|
|
114
|
-
if (pcfKernelSize < 1 || pcfKernelSize % 2 === 0) {
|
|
115
|
-
return err(new ShadowInvalidConfigError('pcfKernelSize', pcfKernelSize, 1));
|
|
116
|
-
}
|
|
117
120
|
const shadowDistance = (data.shadowDistance as number | undefined) ?? 200;
|
|
118
121
|
if (shadowDistance <= 0) {
|
|
119
122
|
return err(new ShadowInvalidConfigError('shadowDistance', shadowDistance, 0, '>'));
|
|
120
123
|
}
|
|
124
|
+
const shadowFilter =
|
|
125
|
+
(data.shadowFilter as number | undefined) ?? DirectionalShadowFilterValue.pcf3;
|
|
126
|
+
const allowedFilters = Object.values(DirectionalShadowFilterValue);
|
|
127
|
+
if (!Number.isFinite(shadowFilter) || !allowedFilters.includes(shadowFilter as never)) {
|
|
128
|
+
return err(
|
|
129
|
+
new ShadowInvalidConfigError(
|
|
130
|
+
'shadowFilter',
|
|
131
|
+
shadowFilter,
|
|
132
|
+
{ kind: 'allowed-values', values: allowedFilters },
|
|
133
|
+
undefined,
|
|
134
|
+
'one of [pcf1, pcf3, pcf5, pcssMedium, pcssHigh]',
|
|
135
|
+
),
|
|
136
|
+
);
|
|
137
|
+
}
|
|
138
|
+
if (
|
|
139
|
+
shadowFilter === DirectionalShadowFilterValue.pcssMedium ||
|
|
140
|
+
shadowFilter === DirectionalShadowFilterValue.pcssHigh
|
|
141
|
+
) {
|
|
142
|
+
const shadowAngularRadius = (data.shadowAngularRadius as number | undefined) ?? 0.00465;
|
|
143
|
+
if (!Number.isFinite(shadowAngularRadius)) {
|
|
144
|
+
return err(
|
|
145
|
+
new ShadowInvalidConfigError('shadowAngularRadius', shadowAngularRadius, {
|
|
146
|
+
kind: 'range',
|
|
147
|
+
min: PCSS_RADIUS_MIN,
|
|
148
|
+
max: PCSS_RADIUS_MAX,
|
|
149
|
+
}),
|
|
150
|
+
);
|
|
151
|
+
}
|
|
152
|
+
if (shadowAngularRadius < PCSS_RADIUS_MIN || shadowAngularRadius > PCSS_RADIUS_MAX) {
|
|
153
|
+
return err(
|
|
154
|
+
new ShadowInvalidConfigError('shadowAngularRadius', shadowAngularRadius, {
|
|
155
|
+
kind: 'range',
|
|
156
|
+
min: PCSS_RADIUS_MIN,
|
|
157
|
+
max: PCSS_RADIUS_MAX,
|
|
158
|
+
}),
|
|
159
|
+
);
|
|
160
|
+
}
|
|
161
|
+
const maxPenumbraTexels = (data.maxPenumbraTexels as number | undefined) ?? 32;
|
|
162
|
+
if (
|
|
163
|
+
!Number.isFinite(maxPenumbraTexels) ||
|
|
164
|
+
!Number.isInteger(maxPenumbraTexels) ||
|
|
165
|
+
maxPenumbraTexels < PCSS_PENUMBRA_MIN ||
|
|
166
|
+
maxPenumbraTexels > PCSS_PENUMBRA_MAX
|
|
167
|
+
) {
|
|
168
|
+
return err(
|
|
169
|
+
new ShadowInvalidConfigError(
|
|
170
|
+
'maxPenumbraTexels',
|
|
171
|
+
maxPenumbraTexels,
|
|
172
|
+
{ kind: 'range', min: PCSS_PENUMBRA_MIN, max: PCSS_PENUMBRA_MAX },
|
|
173
|
+
undefined,
|
|
174
|
+
'a finite integer in [1, 64]',
|
|
175
|
+
),
|
|
176
|
+
);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
121
179
|
return ok(undefined);
|
|
122
180
|
}
|
|
123
181
|
|
|
@@ -153,7 +211,19 @@ export function validateSpotLightData(
|
|
|
153
211
|
}
|
|
154
212
|
const pcfKernelSize = (data.pcfKernelSize as number | undefined) ?? 3;
|
|
155
213
|
if (pcfKernelSize < 1 || pcfKernelSize % 2 === 0) {
|
|
156
|
-
return err(
|
|
214
|
+
return err(
|
|
215
|
+
new ShadowInvalidConfigError(
|
|
216
|
+
'pcfKernelSize',
|
|
217
|
+
pcfKernelSize,
|
|
218
|
+
{ kind: 'lower-bound', operator: '>=', value: 1 },
|
|
219
|
+
undefined,
|
|
220
|
+
'an odd integer >= 1',
|
|
221
|
+
),
|
|
222
|
+
);
|
|
223
|
+
}
|
|
224
|
+
const shadowIntensity = (data.shadowIntensity as number | undefined) ?? 1;
|
|
225
|
+
if (!Number.isFinite(shadowIntensity) || shadowIntensity < 0 || shadowIntensity > 1) {
|
|
226
|
+
return err(new ShadowInvalidConfigError('shadowIntensity', shadowIntensity, 0, 1));
|
|
157
227
|
}
|
|
158
228
|
return ok(undefined);
|
|
159
229
|
}
|
|
@@ -182,7 +252,15 @@ export function validatePointLightShadowData(
|
|
|
182
252
|
}
|
|
183
253
|
const pcfKernelSize = (data.pcfKernelSize as number | undefined) ?? 3;
|
|
184
254
|
if (pcfKernelSize < 1 || pcfKernelSize % 2 === 0) {
|
|
185
|
-
return err(
|
|
255
|
+
return err(
|
|
256
|
+
new ShadowInvalidConfigError(
|
|
257
|
+
'pcfKernelSize',
|
|
258
|
+
pcfKernelSize,
|
|
259
|
+
{ kind: 'lower-bound', operator: '>=', value: 1 },
|
|
260
|
+
undefined,
|
|
261
|
+
'an odd integer >= 1',
|
|
262
|
+
),
|
|
263
|
+
);
|
|
186
264
|
}
|
|
187
265
|
return ok(undefined);
|
|
188
266
|
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
// @forgeax/engine-render - local reflection probe vocabulary.
|
|
2
|
+
//
|
|
3
|
+
// A ReflectionProbe is an ECS authoring fact. The renderer owns its six-face
|
|
4
|
+
// capture, PMREM output, box selection, and Skylight fallback; this component
|
|
5
|
+
// never carries a GPU handle or an authored material reference.
|
|
6
|
+
|
|
7
|
+
import { defineComponent, type SchemaOf, type ShapeOf } from '@forgeax/engine-ecs';
|
|
8
|
+
import { RenderIntentInvalidError } from '../errors/render';
|
|
9
|
+
|
|
10
|
+
export const REFLECTION_PROBE_UPDATE_ONCE = 0;
|
|
11
|
+
export const REFLECTION_PROBE_UPDATE_ON_CHANGE = 1;
|
|
12
|
+
export const REFLECTION_PROBE_UPDATE_CONTINUOUS = 2;
|
|
13
|
+
|
|
14
|
+
export type ReflectionProbeUpdateIntent = 'once' | 'on-change' | 'continuous';
|
|
15
|
+
|
|
16
|
+
export function reflectionProbeUpdateIntentFromF32(value: number): ReflectionProbeUpdateIntent {
|
|
17
|
+
switch (value) {
|
|
18
|
+
case REFLECTION_PROBE_UPDATE_ONCE:
|
|
19
|
+
return 'once';
|
|
20
|
+
case REFLECTION_PROBE_UPDATE_ON_CHANGE:
|
|
21
|
+
return 'on-change';
|
|
22
|
+
case REFLECTION_PROBE_UPDATE_CONTINUOUS:
|
|
23
|
+
return 'continuous';
|
|
24
|
+
default:
|
|
25
|
+
throw new RenderIntentInvalidError('ReflectionProbe', value);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function reflectionProbeUpdateIntentToF32(intent: ReflectionProbeUpdateIntent): number {
|
|
30
|
+
switch (intent) {
|
|
31
|
+
case 'once':
|
|
32
|
+
return REFLECTION_PROBE_UPDATE_ONCE;
|
|
33
|
+
case 'on-change':
|
|
34
|
+
return REFLECTION_PROBE_UPDATE_ON_CHANGE;
|
|
35
|
+
case 'continuous':
|
|
36
|
+
return REFLECTION_PROBE_UPDATE_CONTINUOUS;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export const ReflectionProbe = defineComponent('ReflectionProbe', {
|
|
41
|
+
halfExtents: { type: 'array<f32, 3>', default: new Float32Array([1, 1, 1]) },
|
|
42
|
+
priority: { type: 'f32', default: 0 },
|
|
43
|
+
intensity: { type: 'f32', default: 1 },
|
|
44
|
+
resolution: { type: 'u32', default: 256 },
|
|
45
|
+
updateIntent: { type: 'f32', default: REFLECTION_PROBE_UPDATE_ONCE },
|
|
46
|
+
invalidationVersion: { type: 'u32', default: 0 },
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
export type ReflectionProbeData = ShapeOf<SchemaOf<typeof ReflectionProbe>>;
|
|
@@ -21,8 +21,8 @@
|
|
|
21
21
|
// spotCount === 0" (M5 / w25).
|
|
22
22
|
//
|
|
23
23
|
// feat-20260625-spot-light-shadow-mapping M1 w4: embedded castShadow (default true)
|
|
24
|
-
// +
|
|
25
|
-
// pcfKernelSize) aligned with DirectionalLight vocabulary (plan-strategy D-6;
|
|
24
|
+
// + 7 shadow fields (mapSize / depthBias / normalBias / nearPlane / farPlane /
|
|
25
|
+
// pcfKernelSize / shadowIntensity) aligned with DirectionalLight vocabulary (plan-strategy D-6;
|
|
26
26
|
// charter P4 consistent abstraction). Zero-config spawns cast spot shadows;
|
|
27
27
|
// set castShadow:false to opt out (validate short-circuits on false, AC-03).
|
|
28
28
|
// Shadow atlas cap of 4 is enforced at extract stage, not component layer (OOS-5).
|
|
@@ -37,6 +37,17 @@
|
|
|
37
37
|
|
|
38
38
|
import { defineComponent } from '@forgeax/engine-ecs';
|
|
39
39
|
|
|
40
|
+
export interface SpotLightProjector {
|
|
41
|
+
readonly guid: string;
|
|
42
|
+
readonly generation: number;
|
|
43
|
+
readonly revision: number;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export interface SpotLightAuthoring {
|
|
47
|
+
/** Optional GUID-backed TextureAsset projector; absent keeps the normal spot path. */
|
|
48
|
+
readonly projector?: SpotLightProjector;
|
|
49
|
+
}
|
|
50
|
+
|
|
40
51
|
/**
|
|
41
52
|
* Cone-restricted spot light (KHR_lights_punctual `spot` type). Casts shadows
|
|
42
53
|
* by default (castShadow defaults to true) — zero-config spawns project hard
|
|
@@ -71,6 +82,7 @@ import { defineComponent } from '@forgeax/engine-ecs';
|
|
|
71
82
|
* nearPlane — shadow-camera near (default 0.1)
|
|
72
83
|
* farPlane — shadow-camera far (default 50)
|
|
73
84
|
* pcfKernelSize odd >= 1 — PCF kernel width (default 3)
|
|
85
|
+
* shadowIntensity in [0,1] — residual light in shadow (default 1)
|
|
74
86
|
*
|
|
75
87
|
* Atlas capacity is capped at 4 castShadow spot lights by the extract stage;
|
|
76
88
|
* the 5th light onward keeps direct illumination but shadowAtlasTile = -1
|
|
@@ -114,11 +126,18 @@ export const SpotLight = defineComponent('SpotLight', {
|
|
|
114
126
|
outerConeDeg: { type: 'f32', default: 45 },
|
|
115
127
|
// Shadow opt-out gate: defaults to true so zero-config spawns cast shadows.
|
|
116
128
|
castShadow: { type: 'bool', default: true },
|
|
117
|
-
//
|
|
129
|
+
// 7 shadow fields aligned with the shared light shadow vocabulary.
|
|
118
130
|
mapSize: { type: 'f32', default: 2048 },
|
|
119
131
|
depthBias: { type: 'f32', default: 0.005 },
|
|
120
132
|
normalBias: { type: 'f32', default: 0.05 },
|
|
121
133
|
nearPlane: { type: 'f32', default: 0.1 },
|
|
122
134
|
farPlane: { type: 'f32', default: 50 },
|
|
123
135
|
pcfKernelSize: { type: 'f32', default: 3 },
|
|
136
|
+
// Three's SpotLight.shadow.intensity is the fraction of visibility applied
|
|
137
|
+
// to a shadowed contribution. Keep it in the author-facing [0,1] domain;
|
|
138
|
+
// extract/record transport this one fact to surface and volume consumers.
|
|
139
|
+
shadowIntensity: { type: 'f32', default: 1 },
|
|
140
|
+
// Shared TextureAsset identity; publication and residency remain owned by
|
|
141
|
+
// the existing asset and GPU resource owners.
|
|
142
|
+
projector: { type: 'shared<TextureAsset>', simulationTransient: true },
|
|
124
143
|
});
|
|
@@ -60,6 +60,7 @@ import {
|
|
|
60
60
|
type AssetError,
|
|
61
61
|
countExtraUvSets,
|
|
62
62
|
type DecodedImage,
|
|
63
|
+
deriveTextureLayout,
|
|
63
64
|
type EquirectAsset,
|
|
64
65
|
type Handle,
|
|
65
66
|
handleSlot,
|
|
@@ -72,6 +73,7 @@ import {
|
|
|
72
73
|
type SamplerAsset,
|
|
73
74
|
type Submesh,
|
|
74
75
|
type TextureAsset,
|
|
76
|
+
type TextureShape,
|
|
75
77
|
type MeshAsset as TypesMeshAsset,
|
|
76
78
|
toShared,
|
|
77
79
|
} from '@forgeax/engine-types';
|
|
@@ -98,7 +100,6 @@ import {
|
|
|
98
100
|
import type { RhiErrorListenerRegistry } from '../lifecycle';
|
|
99
101
|
import {
|
|
100
102
|
type CubeRenderData,
|
|
101
|
-
deriveMipUploadLayout,
|
|
102
103
|
deriveRenderDataCubemap,
|
|
103
104
|
deriveRenderDataMesh,
|
|
104
105
|
deriveRenderDataTexture,
|
|
@@ -281,10 +282,25 @@ type RegisterCube = (
|
|
|
281
282
|
// not destroyable on their own; their lifetime is bound to the parent
|
|
282
283
|
// GpuTexture, which the wrapper owns. destroyAll() walks the GpuResource
|
|
283
284
|
// fields and forwards .destroy() to the RHI shim.
|
|
284
|
-
interface
|
|
285
|
+
export interface TextureResidencyReceipt {
|
|
286
|
+
readonly shape: TextureShape;
|
|
287
|
+
readonly format: GPUTextureFormat;
|
|
288
|
+
readonly extent: {
|
|
289
|
+
readonly width: number;
|
|
290
|
+
readonly height: number;
|
|
291
|
+
readonly depthOrArrayLayers: number;
|
|
292
|
+
};
|
|
293
|
+
readonly bytes: number;
|
|
294
|
+
readonly view: '2d' | '2d-array' | '3d';
|
|
295
|
+
readonly generation: number;
|
|
296
|
+
readonly deviceEpoch: number;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
export interface TextureGpuEntry {
|
|
285
300
|
readonly texture: GpuTexture;
|
|
286
301
|
/** Opaque RHI view handle; lifetime is bound to the parent texture. */
|
|
287
302
|
readonly view: TextureView;
|
|
303
|
+
readonly receipt: TextureResidencyReceipt;
|
|
288
304
|
}
|
|
289
305
|
|
|
290
306
|
// feat-20260630-equirect-kind-internalized-ibl-declarative-skyligh M2 / w11
|
|
@@ -388,6 +404,8 @@ export class GpuResidencyCache {
|
|
|
388
404
|
// Hardware-probe caps injected at `configureGpuDevice`; guards the HDR cubemap
|
|
389
405
|
// path (_uploadCubemapFromEquirect) when `rgba16floatRenderable` is false.
|
|
390
406
|
private caps: RhiCaps | undefined = undefined;
|
|
407
|
+
private deviceEpoch = 0;
|
|
408
|
+
private textureGeneration = 0;
|
|
391
409
|
|
|
392
410
|
private readonly textureGpuHandles: Map<string | number, TextureGpuEntry> = new Map();
|
|
393
411
|
private readonly samplerGpuHandles: Map<string | number, Sampler> = new Map();
|
|
@@ -432,6 +450,12 @@ export class GpuResidencyCache {
|
|
|
432
450
|
registerCube: RegisterCube,
|
|
433
451
|
caps: RhiCaps,
|
|
434
452
|
): void {
|
|
453
|
+
for (const entry of this.textureGpuHandles.values()) {
|
|
454
|
+
if (!entry.texture.isDestroyed) entry.texture.destroy();
|
|
455
|
+
}
|
|
456
|
+
if (this.textureGpuHandles.size > 0) this.materialResourceEpoch += 1;
|
|
457
|
+
this.textureGpuHandles.clear();
|
|
458
|
+
this.deviceEpoch += 1;
|
|
435
459
|
this.meshResidencyEpoch += 1;
|
|
436
460
|
this.gpuDevice = device;
|
|
437
461
|
this.asyncCreateShaderModule = asyncCreateShaderModule;
|
|
@@ -997,7 +1021,7 @@ export class GpuResidencyCache {
|
|
|
997
1021
|
const cacheKey = this.worldKey(handleSlot(handle), worldId);
|
|
998
1022
|
if (gpuTexture === undefined) return ok(undefined);
|
|
999
1023
|
|
|
1000
|
-
if (!projected.value.compressed &&
|
|
1024
|
+
if (!projected.value.compressed && tex.mips.kind === 'generate' && levels > 1) {
|
|
1001
1025
|
const factory = this.asyncCreateShaderModule;
|
|
1002
1026
|
if (factory === undefined) {
|
|
1003
1027
|
return err(
|
|
@@ -1020,8 +1044,8 @@ export class GpuResidencyCache {
|
|
|
1020
1044
|
}
|
|
1021
1045
|
const blitRes = blitMipmapsSync(device, gpuTexture, {
|
|
1022
1046
|
format: tex.format,
|
|
1023
|
-
width: tex.width,
|
|
1024
|
-
height: tex.height,
|
|
1047
|
+
width: tex.shape.extent.width,
|
|
1048
|
+
height: tex.shape.extent.height,
|
|
1025
1049
|
levels,
|
|
1026
1050
|
});
|
|
1027
1051
|
if (!blitRes.ok) return blitRes as Result<void, RhiError>;
|
|
@@ -1029,13 +1053,14 @@ export class GpuResidencyCache {
|
|
|
1029
1053
|
|
|
1030
1054
|
const viewRes = device.createTextureView(gpuTexture, {
|
|
1031
1055
|
label: `texture-view-${cacheKey}`,
|
|
1032
|
-
dimension:
|
|
1056
|
+
dimension: projected.value.shape.viewDimension,
|
|
1033
1057
|
});
|
|
1034
1058
|
if (!viewRes.ok) return viewRes;
|
|
1035
1059
|
const previous = this.textureGpuHandles.get(cacheKey);
|
|
1036
|
-
const next = {
|
|
1060
|
+
const next: TextureGpuEntry = {
|
|
1037
1061
|
texture: this.wrapTex(gpuTexture),
|
|
1038
1062
|
view: viewRes.value,
|
|
1063
|
+
receipt: this.textureReceipt(pod, projected.value),
|
|
1039
1064
|
};
|
|
1040
1065
|
this.textureGpuHandles.set(cacheKey, next);
|
|
1041
1066
|
this.materialResourceEpoch += 1;
|
|
@@ -1077,11 +1102,11 @@ export class GpuResidencyCache {
|
|
|
1077
1102
|
const { tex, levels, gpuTexture } = prepared.value;
|
|
1078
1103
|
const cacheKey = this.worldKey(handleSlot(handle), worldId);
|
|
1079
1104
|
|
|
1080
|
-
if (!renderData.compressed &&
|
|
1105
|
+
if (!renderData.compressed && tex.mips.kind === 'generate' && levels > 1) {
|
|
1081
1106
|
const blitRes = blitMipmapsSync(device, gpuTexture, {
|
|
1082
1107
|
format: tex.format,
|
|
1083
|
-
width: tex.width,
|
|
1084
|
-
height: tex.height,
|
|
1108
|
+
width: tex.shape.extent.width,
|
|
1109
|
+
height: tex.shape.extent.height,
|
|
1085
1110
|
levels,
|
|
1086
1111
|
});
|
|
1087
1112
|
if (!blitRes.ok) return blitRes as Result<TextureGpuEntry, RhiError>;
|
|
@@ -1089,10 +1114,14 @@ export class GpuResidencyCache {
|
|
|
1089
1114
|
|
|
1090
1115
|
const viewRes = device.createTextureView(gpuTexture, {
|
|
1091
1116
|
label: `texture-view-${cacheKey}`,
|
|
1092
|
-
dimension:
|
|
1117
|
+
dimension: renderData.shape.viewDimension,
|
|
1093
1118
|
});
|
|
1094
1119
|
if (!viewRes.ok) return viewRes;
|
|
1095
|
-
const entry: TextureGpuEntry = {
|
|
1120
|
+
const entry: TextureGpuEntry = {
|
|
1121
|
+
texture: this.wrapTex(gpuTexture),
|
|
1122
|
+
view: viewRes.value,
|
|
1123
|
+
receipt: this.textureReceipt(pod, renderData),
|
|
1124
|
+
};
|
|
1096
1125
|
const previous = this.textureGpuHandles.get(cacheKey);
|
|
1097
1126
|
this.textureGpuHandles.set(cacheKey, entry);
|
|
1098
1127
|
this.materialResourceEpoch += 1;
|
|
@@ -1106,6 +1135,25 @@ export class GpuResidencyCache {
|
|
|
1106
1135
|
return ok(entry);
|
|
1107
1136
|
}
|
|
1108
1137
|
|
|
1138
|
+
private textureReceipt(
|
|
1139
|
+
pod: TextureAsset,
|
|
1140
|
+
renderData: TextureRenderData,
|
|
1141
|
+
): TextureResidencyReceipt {
|
|
1142
|
+
return {
|
|
1143
|
+
shape: pod.shape,
|
|
1144
|
+
format: renderData.format,
|
|
1145
|
+
extent: {
|
|
1146
|
+
width: renderData.physicalExtent.width,
|
|
1147
|
+
height: renderData.physicalExtent.height,
|
|
1148
|
+
depthOrArrayLayers: renderData.depthOrArrayLayers,
|
|
1149
|
+
},
|
|
1150
|
+
bytes: pod.data.byteLength,
|
|
1151
|
+
view: renderData.shape.viewDimension,
|
|
1152
|
+
generation: ++this.textureGeneration,
|
|
1153
|
+
deviceEpoch: this.deviceEpoch,
|
|
1154
|
+
};
|
|
1155
|
+
}
|
|
1156
|
+
|
|
1109
1157
|
/**
|
|
1110
1158
|
* Shared texture-upload prelude: format / colorSpace consistency assertion,
|
|
1111
1159
|
* GPU texture allocation + writeTexture. Returns `gpuTexture: undefined`
|
|
@@ -1155,13 +1203,21 @@ export class GpuResidencyCache {
|
|
|
1155
1203
|
// upload before allocating a handle; binding a texture that the backend
|
|
1156
1204
|
// accepted syntactically but cannot use later surfaces only as a generic
|
|
1157
1205
|
// invalid-bind-group submit error.
|
|
1158
|
-
const maxDimension =
|
|
1159
|
-
|
|
1206
|
+
const maxDimension =
|
|
1207
|
+
tex.shape.viewDimension === '3d'
|
|
1208
|
+
? device.limits.maxTextureDimension3D
|
|
1209
|
+
: device.limits.maxTextureDimension2D;
|
|
1210
|
+
const width = tex.shape.extent.width;
|
|
1211
|
+
const height = tex.shape.extent.height;
|
|
1212
|
+
const layers = renderData.depthOrArrayLayers;
|
|
1213
|
+
const exceedsLayerLimit =
|
|
1214
|
+
tex.shape.viewDimension === '2d-array' && layers > device.limits.maxTextureArrayLayers;
|
|
1215
|
+
if (width > maxDimension || height > maxDimension || exceedsLayerLimit) {
|
|
1160
1216
|
return err(
|
|
1161
1217
|
makeImageError({
|
|
1162
1218
|
code: 'image-dimension-out-of-bounds',
|
|
1163
|
-
requested: { width
|
|
1164
|
-
limit: maxDimension,
|
|
1219
|
+
requested: { width, height },
|
|
1220
|
+
limit: exceedsLayerLimit ? device.limits.maxTextureArrayLayers : maxDimension,
|
|
1165
1221
|
}),
|
|
1166
1222
|
);
|
|
1167
1223
|
}
|
|
@@ -1171,11 +1227,11 @@ export class GpuResidencyCache {
|
|
|
1171
1227
|
size: {
|
|
1172
1228
|
width: renderData.physicalExtent.width,
|
|
1173
1229
|
height: renderData.physicalExtent.height,
|
|
1174
|
-
depthOrArrayLayers:
|
|
1230
|
+
depthOrArrayLayers: renderData.depthOrArrayLayers,
|
|
1175
1231
|
},
|
|
1176
1232
|
mipLevelCount: levels,
|
|
1177
1233
|
sampleCount: 1,
|
|
1178
|
-
dimension: '2d',
|
|
1234
|
+
dimension: tex.shape.viewDimension === '3d' ? '3d' : '2d',
|
|
1179
1235
|
format: renderData.format,
|
|
1180
1236
|
usage: renderData.usage,
|
|
1181
1237
|
viewFormats: [],
|
|
@@ -1193,28 +1249,77 @@ export class GpuResidencyCache {
|
|
|
1193
1249
|
// block math). Full-subresource copies retain their logical size, including
|
|
1194
1250
|
// non-block-aligned dimensions. queue.writeTexture avoids the 256 B
|
|
1195
1251
|
// copyBufferToTexture alignment trap.
|
|
1196
|
-
const layout =
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
{
|
|
1252
|
+
const layout = deriveTextureLayout({
|
|
1253
|
+
shape: tex.shape,
|
|
1254
|
+
format: renderData.format,
|
|
1255
|
+
mips: tex.mips,
|
|
1256
|
+
});
|
|
1257
|
+
if (!layout.ok) {
|
|
1258
|
+
return err(
|
|
1259
|
+
makeAssetError({
|
|
1260
|
+
code: 'invalid-source-format',
|
|
1261
|
+
expected: layout.error.expected,
|
|
1262
|
+
hint: layout.error.hint,
|
|
1263
|
+
}),
|
|
1204
1264
|
);
|
|
1205
|
-
|
|
1265
|
+
}
|
|
1266
|
+
for (const level of layout.value.levels) {
|
|
1267
|
+
for (let image = 0; image < level.imagesPerMip; image++) {
|
|
1268
|
+
const imageBytes = level.bytesPerRow * level.rowsPerImage;
|
|
1269
|
+
const offset = level.byteOffset + image * imageBytes;
|
|
1270
|
+
const slice = decoded.bytes.subarray(offset, offset + imageBytes);
|
|
1271
|
+
const writeRes = queue.writeTexture(
|
|
1272
|
+
{
|
|
1273
|
+
texture: gpuTexture,
|
|
1274
|
+
mipLevel: level.level,
|
|
1275
|
+
origin: { x: 0, y: 0, z: image },
|
|
1276
|
+
},
|
|
1277
|
+
slice,
|
|
1278
|
+
{ offset: 0, bytesPerRow: level.bytesPerRow, rowsPerImage: level.rowsPerImage },
|
|
1279
|
+
{
|
|
1280
|
+
width: level.physicalWidth,
|
|
1281
|
+
height: level.physicalHeight,
|
|
1282
|
+
depthOrArrayLayers: 1,
|
|
1283
|
+
},
|
|
1284
|
+
);
|
|
1285
|
+
if (!writeRes.ok) return writeRes;
|
|
1286
|
+
}
|
|
1206
1287
|
}
|
|
1207
1288
|
return ok({ id, tex, levels, gpuTexture });
|
|
1208
1289
|
}
|
|
1209
1290
|
|
|
1210
1291
|
// Uncompressed base-mip write; higher mips (when mipmap) are GPU-generated by
|
|
1211
1292
|
// the caller's blit pass. rowsPerImage is the pixel height for linear RGBA.
|
|
1212
|
-
const
|
|
1293
|
+
const textureLayout = deriveTextureLayout({
|
|
1294
|
+
shape: tex.shape,
|
|
1295
|
+
format: renderData.format,
|
|
1296
|
+
mips: tex.mips,
|
|
1297
|
+
});
|
|
1298
|
+
if (!textureLayout.ok) {
|
|
1299
|
+
return err(
|
|
1300
|
+
makeAssetError({
|
|
1301
|
+
code: 'invalid-source-format',
|
|
1302
|
+
expected: textureLayout.error.expected,
|
|
1303
|
+
hint: textureLayout.error.hint,
|
|
1304
|
+
}),
|
|
1305
|
+
);
|
|
1306
|
+
}
|
|
1307
|
+
const baseLevel = textureLayout.value.levels[0];
|
|
1308
|
+
if (baseLevel === undefined) {
|
|
1309
|
+
return err(
|
|
1310
|
+
makeAssetError({
|
|
1311
|
+
code: 'invalid-source-format',
|
|
1312
|
+
expected: 'texture layout contains a base mip level',
|
|
1313
|
+
hint: ASSET_ERROR_HINTS['invalid-source-format'],
|
|
1314
|
+
}),
|
|
1315
|
+
);
|
|
1316
|
+
}
|
|
1317
|
+
const bytesPerRow = baseLevel.bytesPerRow;
|
|
1213
1318
|
const writeTextureRes = queue.writeTexture(
|
|
1214
1319
|
{ texture: gpuTexture, mipLevel: 0, origin: { x: 0, y: 0, z: 0 } },
|
|
1215
1320
|
decoded.bytes,
|
|
1216
|
-
{ offset: 0, bytesPerRow, rowsPerImage:
|
|
1217
|
-
{ width
|
|
1321
|
+
{ offset: 0, bytesPerRow, rowsPerImage: height },
|
|
1322
|
+
{ width, height, depthOrArrayLayers: renderData.depthOrArrayLayers },
|
|
1218
1323
|
);
|
|
1219
1324
|
if (!writeTextureRes.ok) return writeTextureRes;
|
|
1220
1325
|
|
|
@@ -1333,14 +1438,21 @@ export class GpuResidencyCache {
|
|
|
1333
1438
|
// / format / data / colorSpace) but has no CPU mip chain, so the derived
|
|
1334
1439
|
// texture view declares `mipmap:false` (the IBL prefilter mip chain is a
|
|
1335
1440
|
// GPU-side pass, not a CPU-authored level set).
|
|
1441
|
+
const sourceData =
|
|
1442
|
+
sourcePod.data instanceof Uint8ClampedArray
|
|
1443
|
+
? new Uint8Array(
|
|
1444
|
+
sourcePod.data.buffer,
|
|
1445
|
+
sourcePod.data.byteOffset,
|
|
1446
|
+
sourcePod.data.byteLength,
|
|
1447
|
+
)
|
|
1448
|
+
: sourcePod.data;
|
|
1336
1449
|
const sourceTex: TextureAsset = {
|
|
1337
1450
|
kind: 'texture',
|
|
1338
|
-
width: sourcePod.width,
|
|
1339
|
-
height: sourcePod.height,
|
|
1451
|
+
shape: { viewDimension: '2d', extent: { width: sourcePod.width, height: sourcePod.height } },
|
|
1340
1452
|
format: sourcePod.format,
|
|
1341
|
-
data:
|
|
1453
|
+
data: sourceData,
|
|
1342
1454
|
colorSpace: sourcePod.colorSpace,
|
|
1343
|
-
|
|
1455
|
+
mips: { kind: 'none' },
|
|
1344
1456
|
};
|
|
1345
1457
|
|
|
1346
1458
|
// Project the equirect source POD into the cubemap descriptor (D-5): the
|
|
@@ -1365,20 +1477,11 @@ export class GpuResidencyCache {
|
|
|
1365
1477
|
const tex: TextureAsset = projected.needsHalfConversion
|
|
1366
1478
|
? {
|
|
1367
1479
|
kind: 'texture',
|
|
1368
|
-
|
|
1369
|
-
height: sourceTex.height,
|
|
1480
|
+
shape: sourceTex.shape,
|
|
1370
1481
|
format: projected.outputFormat,
|
|
1371
|
-
data: halfFloat.f32ToF16Bytes(
|
|
1372
|
-
sourceTex.data instanceof Uint8ClampedArray
|
|
1373
|
-
? new Uint8Array(
|
|
1374
|
-
sourceTex.data.buffer,
|
|
1375
|
-
sourceTex.data.byteOffset,
|
|
1376
|
-
sourceTex.data.byteLength,
|
|
1377
|
-
)
|
|
1378
|
-
: sourceTex.data,
|
|
1379
|
-
),
|
|
1482
|
+
data: halfFloat.f32ToF16Bytes(sourceTex.data),
|
|
1380
1483
|
colorSpace: 'linear',
|
|
1381
|
-
|
|
1484
|
+
mips: { kind: 'none' },
|
|
1382
1485
|
}
|
|
1383
1486
|
: sourceTex;
|
|
1384
1487
|
|
|
@@ -1503,7 +1606,11 @@ export class GpuResidencyCache {
|
|
|
1503
1606
|
|
|
1504
1607
|
const equirectTextureResult = device.createTexture({
|
|
1505
1608
|
label: `equirect-${sourceId}`,
|
|
1506
|
-
size: {
|
|
1609
|
+
size: {
|
|
1610
|
+
width: tex.shape.extent.width,
|
|
1611
|
+
height: tex.shape.extent.height,
|
|
1612
|
+
depthOrArrayLayers: 1,
|
|
1613
|
+
},
|
|
1507
1614
|
mipLevelCount: 1,
|
|
1508
1615
|
sampleCount: 1,
|
|
1509
1616
|
dimension: '2d',
|
|
@@ -1526,8 +1633,15 @@ export class GpuResidencyCache {
|
|
|
1526
1633
|
const equirectWriteResult = device.queue.writeTexture(
|
|
1527
1634
|
{ texture: equirectGpuTex },
|
|
1528
1635
|
tex.data,
|
|
1529
|
-
{
|
|
1530
|
-
|
|
1636
|
+
{
|
|
1637
|
+
bytesPerRow: tex.shape.extent.width * bytesPerPixel,
|
|
1638
|
+
rowsPerImage: tex.shape.extent.height,
|
|
1639
|
+
},
|
|
1640
|
+
{
|
|
1641
|
+
width: tex.shape.extent.width,
|
|
1642
|
+
height: tex.shape.extent.height,
|
|
1643
|
+
depthOrArrayLayers: 1,
|
|
1644
|
+
},
|
|
1531
1645
|
);
|
|
1532
1646
|
if (!equirectWriteResult.ok) return recordFailed(equirectWriteResult.error);
|
|
1533
1647
|
|
|
@@ -1803,20 +1917,16 @@ export class GpuResidencyCache {
|
|
|
1803
1917
|
/**
|
|
1804
1918
|
* Synthesize the `DecodedImage` view the texture-upload prelude consumes from
|
|
1805
1919
|
* a `TextureAsset` POD (the record-stage pull path holds only the POD). The
|
|
1806
|
-
* POD's `data` is the pixel bytes; `colorSpace` + `
|
|
1920
|
+
* POD's `data` is the pixel bytes; `colorSpace` + `mips` drive the
|
|
1807
1921
|
* consistency assertion + mip count.
|
|
1808
1922
|
*/
|
|
1809
1923
|
function decodedFromTexture(tex: TextureAsset): DecodedImage {
|
|
1810
|
-
const bytes =
|
|
1811
|
-
tex.data instanceof Uint8ClampedArray
|
|
1812
|
-
? new Uint8Array(tex.data.buffer, tex.data.byteOffset, tex.data.byteLength)
|
|
1813
|
-
: tex.data;
|
|
1814
1924
|
return {
|
|
1815
|
-
bytes,
|
|
1816
|
-
width: tex.width,
|
|
1817
|
-
height: tex.height,
|
|
1925
|
+
bytes: tex.data,
|
|
1926
|
+
width: tex.shape.extent.width,
|
|
1927
|
+
height: tex.shape.extent.height,
|
|
1818
1928
|
mime: 'image/png',
|
|
1819
1929
|
colorSpace: tex.colorSpace,
|
|
1820
|
-
mipmap: tex.
|
|
1930
|
+
mipmap: tex.mips.kind === 'generate',
|
|
1821
1931
|
};
|
|
1822
1932
|
}
|