@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
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
import type { Buffer, QuerySet, RhiCommandEncoder, RhiDevice, RhiError } from '@forgeax/engine-rhi';
|
|
2
|
+
import { ok, type Result } from '@forgeax/engine-types';
|
|
3
|
+
import {
|
|
4
|
+
GPU_BUFFER_USAGE_COPY_DST,
|
|
5
|
+
GPU_BUFFER_USAGE_COPY_SRC,
|
|
6
|
+
GPU_BUFFER_USAGE_MAP_READ,
|
|
7
|
+
GPU_BUFFER_USAGE_QUERY_RESOLVE,
|
|
8
|
+
} from '../gpu-usage';
|
|
9
|
+
|
|
10
|
+
const MAX_VOLUME_PASSES = 4;
|
|
11
|
+
const QUERY_COUNT = MAX_VOLUME_PASSES * 2;
|
|
12
|
+
const QUERY_STRIDE_BYTES = 256;
|
|
13
|
+
const READBACK_BYTES = QUERY_COUNT * QUERY_STRIDE_BYTES;
|
|
14
|
+
const PASS_NAMES = [
|
|
15
|
+
'volume-inject',
|
|
16
|
+
'volume-integrate',
|
|
17
|
+
'volume-temporal',
|
|
18
|
+
'volume-composite',
|
|
19
|
+
] as const;
|
|
20
|
+
|
|
21
|
+
export type VolumeTimingObservation =
|
|
22
|
+
| {
|
|
23
|
+
readonly status: 'ready';
|
|
24
|
+
readonly unit: 'ms';
|
|
25
|
+
readonly totalMs: number;
|
|
26
|
+
readonly passes: readonly { readonly name: string; readonly milliseconds: number }[];
|
|
27
|
+
}
|
|
28
|
+
| {
|
|
29
|
+
readonly status: 'unavailable';
|
|
30
|
+
readonly reason: string;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
function unavailable(reason: string): VolumeTimingObservation {
|
|
34
|
+
return Object.freeze({ status: 'unavailable', reason });
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export interface VolumeTimingTimestampWrites {
|
|
38
|
+
readonly querySet: QuerySet;
|
|
39
|
+
readonly beginningOfPassWriteIndex: number;
|
|
40
|
+
readonly endOfPassWriteIndex: number;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Renderer-owned timestamp capture for the authored volume graph. Query
|
|
45
|
+
* resources are private to one accepted submit and never cross the receipt
|
|
46
|
+
* boundary. This publishes raw renderer timings; a benchmark runner owns
|
|
47
|
+
* runner class, frame-count, and threshold qualification.
|
|
48
|
+
*/
|
|
49
|
+
export class GpuTimingCapture {
|
|
50
|
+
readonly #device: RhiDevice;
|
|
51
|
+
readonly #querySet: QuerySet;
|
|
52
|
+
readonly #resolveBuffer: Buffer;
|
|
53
|
+
readonly #readbackBuffer: Buffer;
|
|
54
|
+
readonly #periodNanoseconds: number;
|
|
55
|
+
readonly #started = new Map<string, number>();
|
|
56
|
+
readonly #finished = new Map<string, number>();
|
|
57
|
+
#resolved = false;
|
|
58
|
+
#submitted = false;
|
|
59
|
+
#discarded = false;
|
|
60
|
+
#disposed = false;
|
|
61
|
+
#observation: Promise<VolumeTimingObservation> | undefined;
|
|
62
|
+
|
|
63
|
+
private constructor(
|
|
64
|
+
device: RhiDevice,
|
|
65
|
+
querySet: QuerySet,
|
|
66
|
+
resolveBuffer: Buffer,
|
|
67
|
+
readbackBuffer: Buffer,
|
|
68
|
+
periodNanoseconds: number,
|
|
69
|
+
) {
|
|
70
|
+
this.#device = device;
|
|
71
|
+
this.#querySet = querySet;
|
|
72
|
+
this.#resolveBuffer = resolveBuffer;
|
|
73
|
+
this.#readbackBuffer = readbackBuffer;
|
|
74
|
+
this.#periodNanoseconds = periodNanoseconds;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
static create(device: RhiDevice): Result<GpuTimingCapture | undefined, RhiError> {
|
|
78
|
+
const period = device.caps.timestampPeriodNanoseconds;
|
|
79
|
+
if (!device.caps.timestampQuery || period === null || !Number.isFinite(period) || period <= 0) {
|
|
80
|
+
return ok(undefined);
|
|
81
|
+
}
|
|
82
|
+
const querySet = device.createQuerySet({
|
|
83
|
+
label: 'volume-timing',
|
|
84
|
+
type: 'timestamp',
|
|
85
|
+
count: QUERY_COUNT,
|
|
86
|
+
});
|
|
87
|
+
if (!querySet.ok) return querySet;
|
|
88
|
+
const resolveBuffer = device.createBuffer({
|
|
89
|
+
label: 'volume-timing.resolve',
|
|
90
|
+
size: READBACK_BYTES,
|
|
91
|
+
usage: GPU_BUFFER_USAGE_QUERY_RESOLVE | GPU_BUFFER_USAGE_COPY_SRC,
|
|
92
|
+
});
|
|
93
|
+
if (!resolveBuffer.ok) {
|
|
94
|
+
device.destroyQuerySet(querySet.value);
|
|
95
|
+
return resolveBuffer;
|
|
96
|
+
}
|
|
97
|
+
const readbackBuffer = device.createBuffer({
|
|
98
|
+
label: 'volume-timing.readback',
|
|
99
|
+
size: READBACK_BYTES,
|
|
100
|
+
usage: GPU_BUFFER_USAGE_MAP_READ | GPU_BUFFER_USAGE_COPY_DST,
|
|
101
|
+
});
|
|
102
|
+
if (!readbackBuffer.ok) {
|
|
103
|
+
device.destroyBuffer(resolveBuffer.value);
|
|
104
|
+
device.destroyQuerySet(querySet.value);
|
|
105
|
+
return readbackBuffer;
|
|
106
|
+
}
|
|
107
|
+
return ok(
|
|
108
|
+
new GpuTimingCapture(
|
|
109
|
+
device,
|
|
110
|
+
querySet.value,
|
|
111
|
+
resolveBuffer.value,
|
|
112
|
+
readbackBuffer.value,
|
|
113
|
+
period,
|
|
114
|
+
),
|
|
115
|
+
);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
recordPass(name: string): VolumeTimingTimestampWrites | undefined {
|
|
119
|
+
const index = PASS_NAMES.indexOf(name as (typeof PASS_NAMES)[number]);
|
|
120
|
+
if (index < 0 || this.#started.has(name) || this.#discarded) return undefined;
|
|
121
|
+
this.#started.set(name, index);
|
|
122
|
+
this.#finished.set(name, index);
|
|
123
|
+
return {
|
|
124
|
+
querySet: this.#querySet,
|
|
125
|
+
beginningOfPassWriteIndex: index * 2,
|
|
126
|
+
endOfPassWriteIndex: index * 2 + 1,
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
skipPass(name: string): void {
|
|
131
|
+
this.#started.delete(name);
|
|
132
|
+
this.#finished.delete(name);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
resolve(encoder: RhiCommandEncoder): Result<void, RhiError> {
|
|
136
|
+
if (this.#started.size === 0) {
|
|
137
|
+
this.#resolved = true;
|
|
138
|
+
return ok(undefined);
|
|
139
|
+
}
|
|
140
|
+
const resolved = encoder.resolveQuerySet(
|
|
141
|
+
this.#querySet,
|
|
142
|
+
0,
|
|
143
|
+
QUERY_COUNT,
|
|
144
|
+
this.#resolveBuffer,
|
|
145
|
+
0,
|
|
146
|
+
);
|
|
147
|
+
if (!resolved.ok) return resolved;
|
|
148
|
+
encoder.copyBufferToBuffer(this.#resolveBuffer, this.#readbackBuffer, READBACK_BYTES);
|
|
149
|
+
this.#resolved = true;
|
|
150
|
+
return ok(undefined);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
markSubmitted(): void {
|
|
154
|
+
if (!this.#discarded) this.#submitted = true;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
discard(): void {
|
|
158
|
+
if (this.#discarded) return;
|
|
159
|
+
this.#discarded = true;
|
|
160
|
+
this.#resolved = true;
|
|
161
|
+
this.#submitted = false;
|
|
162
|
+
this.#dispose();
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
observation(): Promise<VolumeTimingObservation> {
|
|
166
|
+
if (this.#observation !== undefined) return this.#observation;
|
|
167
|
+
if (this.#discarded || !this.#resolved || !this.#submitted || this.#started.size === 0) {
|
|
168
|
+
this.#observation = Promise.resolve(
|
|
169
|
+
unavailable('timestamp capture did not reach an accepted volume submit'),
|
|
170
|
+
);
|
|
171
|
+
this.#dispose();
|
|
172
|
+
return this.#observation;
|
|
173
|
+
}
|
|
174
|
+
this.#observation = this.#readbackBuffer
|
|
175
|
+
.mapAsync(GPU_BUFFER_USAGE_MAP_READ)
|
|
176
|
+
.then((mapped) => {
|
|
177
|
+
if (!mapped.ok) return unavailable(`timestamp readback failed: ${mapped.error.code}`);
|
|
178
|
+
const range = mapped.value.getMappedRange();
|
|
179
|
+
if (!range.ok) {
|
|
180
|
+
mapped.value.unmap();
|
|
181
|
+
return unavailable(`timestamp mapping failed: ${range.error.code}`);
|
|
182
|
+
}
|
|
183
|
+
const values = new DataView(range.value);
|
|
184
|
+
const decoded = [...this.#finished.entries()]
|
|
185
|
+
.sort((a, b) => a[1] - b[1])
|
|
186
|
+
.map(([name, index]) => ({
|
|
187
|
+
name,
|
|
188
|
+
begin: values.getBigUint64(index * 2 * QUERY_STRIDE_BYTES, true),
|
|
189
|
+
end: values.getBigUint64((index * 2 + 1) * QUERY_STRIDE_BYTES, true),
|
|
190
|
+
}));
|
|
191
|
+
if (decoded.some(({ end, begin }) => end < begin)) {
|
|
192
|
+
mapped.value.unmap();
|
|
193
|
+
this.#dispose();
|
|
194
|
+
return unavailable('timestamp query returned an end before its begin');
|
|
195
|
+
}
|
|
196
|
+
const passes = decoded.map(({ name, begin, end }) => ({
|
|
197
|
+
name,
|
|
198
|
+
milliseconds: (Number(end - begin) * this.#periodNanoseconds) / 1_000_000,
|
|
199
|
+
}));
|
|
200
|
+
const firstBegin = decoded.reduce(
|
|
201
|
+
(first, sample) => (sample.begin < first ? sample.begin : first),
|
|
202
|
+
decoded[0]?.begin ?? 0n,
|
|
203
|
+
);
|
|
204
|
+
const lastEnd = decoded.reduce(
|
|
205
|
+
(last, sample) => (sample.end > last ? sample.end : last),
|
|
206
|
+
decoded[0]?.end ?? 0n,
|
|
207
|
+
);
|
|
208
|
+
const totalMs = (Number(lastEnd - firstBegin) * this.#periodNanoseconds) / 1_000_000;
|
|
209
|
+
mapped.value.unmap();
|
|
210
|
+
this.#dispose();
|
|
211
|
+
if (
|
|
212
|
+
!Number.isFinite(totalMs) ||
|
|
213
|
+
passes.some((pass) => !Number.isFinite(pass.milliseconds))
|
|
214
|
+
) {
|
|
215
|
+
return unavailable('timestamp query returned a non-finite duration');
|
|
216
|
+
}
|
|
217
|
+
return Object.freeze({ status: 'ready', unit: 'ms', totalMs, passes });
|
|
218
|
+
})
|
|
219
|
+
.catch((cause: unknown) => {
|
|
220
|
+
this.#dispose();
|
|
221
|
+
return unavailable(`timestamp readback failed: ${String(cause)}`);
|
|
222
|
+
});
|
|
223
|
+
return this.#observation;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
#dispose(): void {
|
|
227
|
+
if (this.#disposed) return;
|
|
228
|
+
this.#disposed = true;
|
|
229
|
+
this.#device.destroyBuffer(this.#resolveBuffer);
|
|
230
|
+
this.#device.destroyBuffer(this.#readbackBuffer);
|
|
231
|
+
this.#device.destroyQuerySet(this.#querySet);
|
|
232
|
+
}
|
|
233
|
+
}
|
|
@@ -17,10 +17,20 @@ import {
|
|
|
17
17
|
GPU_BUFFER_USAGE_STORAGE,
|
|
18
18
|
GPU_BUFFER_USAGE_UNIFORM,
|
|
19
19
|
} from '../gpu-usage';
|
|
20
|
+
import { createHdrpSkinUnifiedBindGroup, getOrCreateHdrpBuffers } from '../hdrp-buffers';
|
|
20
21
|
import type { InstanceBufferCacheEntry } from '../instance-buffer-cache';
|
|
21
22
|
import { SPRITE_PREMULTIPLIED_ALPHA_BLEND } from '../materials';
|
|
22
|
-
import {
|
|
23
|
-
|
|
23
|
+
import {
|
|
24
|
+
createPbrSkinMeshBindGroupEntries,
|
|
25
|
+
pbrSkinMeshDynamicOffsets,
|
|
26
|
+
SKIN_MATERIAL_SHADER_ID,
|
|
27
|
+
} from '../pbr-pipeline';
|
|
28
|
+
import {
|
|
29
|
+
renderStateHash,
|
|
30
|
+
standardStorageVariantSet,
|
|
31
|
+
standardTopologyVariantSet,
|
|
32
|
+
variantSetFromVertexLayoutProjection,
|
|
33
|
+
} from '../pipeline-spec';
|
|
24
34
|
import type { PointsLinesRecordPlan } from '../points-lines/record';
|
|
25
35
|
import { POINTS_LINES_MATERIAL_SHADER_ID } from '../points-lines/record';
|
|
26
36
|
import type { RenderRecordPhase } from '../render-contract';
|
|
@@ -30,6 +40,7 @@ import {
|
|
|
30
40
|
geometryRenderStateForTopology,
|
|
31
41
|
isEntityFullyTransparent,
|
|
32
42
|
selectGeometryPipeline,
|
|
43
|
+
selectMaterialGroup2,
|
|
33
44
|
} from './main-pass-material';
|
|
34
45
|
import {
|
|
35
46
|
getOrCreateFromChain,
|
|
@@ -40,7 +51,7 @@ import {
|
|
|
40
51
|
MESH_UBO_FULL_ARRAY_BYTES,
|
|
41
52
|
packInstanceStorageBuffer,
|
|
42
53
|
} from './mesh-ssbo';
|
|
43
|
-
import type { _InternalRenderPipelineContext } from './render-context';
|
|
54
|
+
import type { _InternalRenderPipelineContext, MaterialShaderPipelineEntry } from './render-context';
|
|
44
55
|
import { MATERIAL_PER_ENTITY_STRIDE } from './render-context';
|
|
45
56
|
import { POINTS_LINES_VIEW_SLOT_STRIDE, writePointsLinesViewUbo } from './view-ubo';
|
|
46
57
|
|
|
@@ -66,7 +77,7 @@ type MaterialPipelineLookup = {
|
|
|
66
77
|
readonly layoutProjection: import('@forgeax/engine-geometry').VertexLayoutProjection;
|
|
67
78
|
readonly sampleCount: number;
|
|
68
79
|
readonly colorFormatOverride: GPUTextureFormat | undefined;
|
|
69
|
-
readonly handle:
|
|
80
|
+
readonly handle: MaterialShaderPipelineEntry | null;
|
|
70
81
|
};
|
|
71
82
|
|
|
72
83
|
type GeometryRecordProfileSegment = 'material-bind-groups' | 'pipeline-selection' | 'draw-submit';
|
|
@@ -197,8 +208,13 @@ export function recordGeometryDraws(
|
|
|
197
208
|
validatedOrdered,
|
|
198
209
|
splitLdrSprite,
|
|
199
210
|
viewBindGroup,
|
|
211
|
+
viewBindGroupDynamicOffset = 0,
|
|
200
212
|
} = c;
|
|
201
213
|
const colorFormatOverride = c.transparentColorFormat as GPUTextureFormat | undefined;
|
|
214
|
+
// The prepared Standard topology is the frame authority. A bind-group
|
|
215
|
+
// identity is only a resource result; using it to infer the shader lane
|
|
216
|
+
// would silently fall back to URP when the clustered resource is missing.
|
|
217
|
+
const clusteredLighting = c.standardLighting?.kind === 'clustered';
|
|
202
218
|
// A no-tone frame may still render into the graph-owned rgba16float target
|
|
203
219
|
// (the linear-LDR route). Shader variants must follow the attachment's
|
|
204
220
|
// numeric domain rather than the camera's tone-map switch, otherwise the
|
|
@@ -222,7 +238,6 @@ export function recordGeometryDraws(
|
|
|
222
238
|
const profilePhase = c.profilePhase;
|
|
223
239
|
const materialGroup1DynamicOffsets = new Uint32Array(1);
|
|
224
240
|
const meshGroup2DynamicOffsets = [0];
|
|
225
|
-
const skinGroup2DynamicOffsets = [0, 0];
|
|
226
241
|
let lastStencilReference: number | null = null;
|
|
227
242
|
// feat-20260625-refactor-sprite-as-transparent-mesh M3 / w14 (D-7):
|
|
228
243
|
// sprite PSO selection no longer maintains a dedicated tag — the
|
|
@@ -246,7 +261,7 @@ export function recordGeometryDraws(
|
|
|
246
261
|
variantSet: string | undefined,
|
|
247
262
|
colorFormat: GPUTextureFormat | undefined,
|
|
248
263
|
layoutProjection: import('@forgeax/engine-geometry').VertexLayoutProjection,
|
|
249
|
-
):
|
|
264
|
+
): MaterialShaderPipelineEntry | null => {
|
|
250
265
|
const renderStateKey = renderStateHash(renderState);
|
|
251
266
|
const shaderLookupCache = materialPipelineLookupCache.get(materialShaderId);
|
|
252
267
|
const cachedLookups = shaderLookupCache?.get(renderStateKey);
|
|
@@ -278,7 +293,7 @@ export function recordGeometryDraws(
|
|
|
278
293
|
}
|
|
279
294
|
const resolvedVariantSet = resolvedVariantSetResult.value;
|
|
280
295
|
const resolvePipeline = () =>
|
|
281
|
-
runtime.
|
|
296
|
+
runtime.getMaterialShaderPipelineEntry?.(
|
|
282
297
|
materialShaderId,
|
|
283
298
|
isHdrTarget,
|
|
284
299
|
renderState,
|
|
@@ -340,7 +355,7 @@ export function recordGeometryDraws(
|
|
|
340
355
|
// Points/Lines share the Standard geometry pass. Their retained source
|
|
341
356
|
// is prepared once by the renderer owner, while this loop remains the
|
|
342
357
|
// sole pass/draw submission owner and preserves the authored topology.
|
|
343
|
-
const pointsLinesSubmission = c.pointsLines?.prepare(entry,
|
|
358
|
+
const pointsLinesSubmission = c.pointsLines?.prepare(entry, clusteredLighting);
|
|
344
359
|
if (entry.source.pointsLines !== undefined && pointsLinesSubmission?.plan.drawCount !== 1)
|
|
345
360
|
continue;
|
|
346
361
|
|
|
@@ -399,7 +414,7 @@ export function recordGeometryDraws(
|
|
|
399
414
|
entry.source.entityKey,
|
|
400
415
|
entry.world ?? c.world,
|
|
401
416
|
);
|
|
402
|
-
const
|
|
417
|
+
const pointsLinesPipelineEntry = resolveMaterialPipeline(
|
|
403
418
|
POINTS_LINES_MATERIAL_SHADER_ID,
|
|
404
419
|
{
|
|
405
420
|
...pointsLinesMaterial.renderState,
|
|
@@ -411,7 +426,8 @@ export function recordGeometryDraws(
|
|
|
411
426
|
colorFormatOverride,
|
|
412
427
|
pointsLinesSubmission.layoutProjection,
|
|
413
428
|
);
|
|
414
|
-
if (
|
|
429
|
+
if (pointsLinesPipelineEntry === null) continue;
|
|
430
|
+
const pointsLinesPipeline = pointsLinesPipelineEntry.pipeline;
|
|
415
431
|
if (pipelineState.pointsLinesViewBuffer === undefined) continue;
|
|
416
432
|
writePointsLinesViewUbo(
|
|
417
433
|
runtime.device.queue,
|
|
@@ -426,9 +442,9 @@ export function recordGeometryDraws(
|
|
|
426
442
|
pass.setBindGroup(
|
|
427
443
|
0,
|
|
428
444
|
viewBindGroup as BindGroup,
|
|
429
|
-
new Uint32Array([i * POINTS_LINES_VIEW_SLOT_STRIDE]),
|
|
445
|
+
new Uint32Array([0, i * POINTS_LINES_VIEW_SLOT_STRIDE]),
|
|
430
446
|
0,
|
|
431
|
-
|
|
447
|
+
2,
|
|
432
448
|
);
|
|
433
449
|
pass.setPipeline(pointsLinesPipeline);
|
|
434
450
|
pass.setVertexBuffer(0, pointsLinesSubmission.vertexBuffer);
|
|
@@ -444,7 +460,7 @@ export function recordGeometryDraws(
|
|
|
444
460
|
resolveGeometryInstancesBindGroup(c, identityInstanceBuffer),
|
|
445
461
|
);
|
|
446
462
|
recordPointsLinesDraw(pass, pointsLinesSubmission.plan);
|
|
447
|
-
pass.setBindGroup(0, viewBindGroup as BindGroup, [0]);
|
|
463
|
+
pass.setBindGroup(0, viewBindGroup as BindGroup, [viewBindGroupDynamicOffset, 0]);
|
|
448
464
|
continue;
|
|
449
465
|
}
|
|
450
466
|
|
|
@@ -474,11 +490,12 @@ export function recordGeometryDraws(
|
|
|
474
490
|
const instanceDraws = resolveGeometryInstanceBuffer(c, entry, identityInstanceDraws);
|
|
475
491
|
if (instanceDraws === null) continue;
|
|
476
492
|
|
|
477
|
-
// feat-20260611 R2 / M8 / w28 (IS-14): skin entries need a
|
|
493
|
+
// feat-20260611 R2 / M8 / w28 (IS-14): skin entries need a 3-binding
|
|
478
494
|
// group(2) BG matching `pbr-skin-pl` (binding 0 mesh-array UBO +
|
|
479
|
-
// binding 1 palette UBO
|
|
495
|
+
// binding 1 current palette UBO + binding 2 previous palette UBO).
|
|
496
|
+
// Building this here -- not in the
|
|
480
497
|
// `meshBindGroup` factory above -- because the binding-shape
|
|
481
|
-
// (1-entry vs
|
|
498
|
+
// (1-entry vs 3-entry) is per-entry, not per-frame. URP / HDRP
|
|
482
499
|
// entries keep using `meshGroup2` (1-entry mesh-array or HDRP
|
|
483
500
|
// unified). The skin-variant cache key includes both buffer
|
|
484
501
|
// identities so a future allocator-driven palette buffer rotation
|
|
@@ -489,7 +506,7 @@ export function recordGeometryDraws(
|
|
|
489
506
|
// BGL-build failure), AND (b) the skin PSO cache returns a non-null
|
|
490
507
|
// pipeline for this entry. Without (b), the per-submesh selector
|
|
491
508
|
// below falls back to URP `standardPipeline` (`pbr-pl` layout,
|
|
492
|
-
// 1-entry mesh-array BGL); binding the
|
|
509
|
+
// 1-entry mesh-array BGL); binding the 3-entry skin BG against
|
|
493
510
|
// that pipeline reproduces the exact `pbr-mesh-array-bgl ... does
|
|
494
511
|
// not match layout pbr-skin-mesh-array-bgl` device error R1
|
|
495
512
|
// captured. Mirrors the uniform null skip-draw pattern (M6-T1).
|
|
@@ -517,28 +534,40 @@ export function recordGeometryDraws(
|
|
|
517
534
|
// and walks 0, 1536, 3072, ... on the storage path.
|
|
518
535
|
const skinAllocator = pipelineState.skinPaletteAllocator;
|
|
519
536
|
const skinSlice = entry.source.skin;
|
|
537
|
+
const clusteredSkin = clusteredLighting;
|
|
538
|
+
const skinMeshBindGroupLayout = clusteredSkin
|
|
539
|
+
? pipelineState.hdrpSkinMeshBindGroupLayout
|
|
540
|
+
: pipelineState.pbrSkinMeshBindGroupLayout;
|
|
541
|
+
const hdrpSkinBuffers =
|
|
542
|
+
isSkinEntry && clusteredSkin
|
|
543
|
+
? getOrCreateHdrpBuffers(runtime, frameState.installedPipelineConfig?.clusterGrid)
|
|
544
|
+
: null;
|
|
520
545
|
const skinResources =
|
|
521
546
|
isSkinEntry &&
|
|
522
|
-
|
|
547
|
+
skinMeshBindGroupLayout !== null &&
|
|
523
548
|
skinAllocator !== null &&
|
|
524
|
-
skinSlice !== undefined
|
|
549
|
+
skinSlice !== undefined &&
|
|
550
|
+
(!clusteredSkin || hdrpSkinBuffers !== null)
|
|
525
551
|
? {
|
|
526
|
-
meshArrayBgl:
|
|
552
|
+
meshArrayBgl: skinMeshBindGroupLayout,
|
|
527
553
|
paletteBuffer: skinSlice.buffer,
|
|
528
554
|
paletteBindingWindowBytes: skinAllocator.bindingWindowBytes,
|
|
555
|
+
hdrpBuffers: hdrpSkinBuffers,
|
|
529
556
|
}
|
|
530
557
|
: null;
|
|
531
558
|
// Probe the skin PSO cache up front so we can decide whether to swap
|
|
532
|
-
// to the
|
|
559
|
+
// to the skin BG. The same probe + selector is repeated in
|
|
533
560
|
// the per-submesh loop below (the loop's variantSet derivation is
|
|
534
561
|
// identical -- skin shader registers a single all-true variant so
|
|
535
562
|
// the canonical empty-key rule applies on HDRP and the URP key is
|
|
536
563
|
// the explicit expanded form, mirroring the standard PBR path).
|
|
537
564
|
const skinVariantSetResult = variantSetFromVertexLayoutProjection(
|
|
538
565
|
entry.mesh.layoutProjection,
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
566
|
+
standardTopologyVariantSet(
|
|
567
|
+
c.standardLighting,
|
|
568
|
+
runtime.device.caps.storageBuffer,
|
|
569
|
+
entry.mesh.layoutProjection.attributes.some((attribute) => attribute.key === 'color'),
|
|
570
|
+
),
|
|
542
571
|
);
|
|
543
572
|
if (!skinVariantSetResult.ok) runtime.errorRegistry.fire(skinVariantSetResult.error);
|
|
544
573
|
const skinVariantSet = skinVariantSetResult.ok ? skinVariantSetResult.value : undefined;
|
|
@@ -579,45 +608,47 @@ export function recordGeometryDraws(
|
|
|
579
608
|
const skinMissesBefore = bindGroupCounts.createBindGroup;
|
|
580
609
|
const skinBindGroup: BindGroup = getOrCreateFromChain(
|
|
581
610
|
frameState.meshBindGroupCache,
|
|
582
|
-
[
|
|
611
|
+
[
|
|
612
|
+
pipelineState.meshStorageBuffer.buffer,
|
|
613
|
+
skinResources.paletteBuffer,
|
|
614
|
+
...(skinResources.hdrpBuffers === null
|
|
615
|
+
? []
|
|
616
|
+
: [
|
|
617
|
+
skinResources.hdrpBuffers.lightDataBuffer,
|
|
618
|
+
skinResources.hdrpBuffers.clusterGridBuffer,
|
|
619
|
+
skinResources.hdrpBuffers.lightIndexListBuffer,
|
|
620
|
+
skinResources.hdrpBuffers.clusterUniformBuffer,
|
|
621
|
+
]),
|
|
622
|
+
],
|
|
583
623
|
'pbr-skin-mesh',
|
|
584
624
|
() => {
|
|
625
|
+
if (skinResources.hdrpBuffers !== null) {
|
|
626
|
+
const result = createHdrpSkinUnifiedBindGroup(
|
|
627
|
+
runtime,
|
|
628
|
+
skinResources.hdrpBuffers,
|
|
629
|
+
skinResources.meshArrayBgl,
|
|
630
|
+
pipelineState.meshStorageBuffer.buffer,
|
|
631
|
+
skinResources.paletteBuffer,
|
|
632
|
+
skinResources.paletteBindingWindowBytes,
|
|
633
|
+
);
|
|
634
|
+
if (result === null) {
|
|
635
|
+
throw new RhiError({
|
|
636
|
+
code: 'webgpu-runtime-error',
|
|
637
|
+
expected: 'HDRP clustered skin BindGroup creation succeeds',
|
|
638
|
+
hint: 'inspect prior errorRegistry events for createBindGroup failure detail',
|
|
639
|
+
});
|
|
640
|
+
}
|
|
641
|
+
return result;
|
|
642
|
+
}
|
|
585
643
|
const result = runtime.device.createBindGroup({
|
|
586
644
|
label: 'pbr-skin-mesh-bg',
|
|
587
645
|
layout: skinResources.meshArrayBgl,
|
|
588
|
-
entries:
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
buffer: pipelineState.meshStorageBuffer.buffer,
|
|
595
|
-
offset: 0,
|
|
596
|
-
size: meshBindSize,
|
|
597
|
-
},
|
|
598
|
-
},
|
|
599
|
-
},
|
|
600
|
-
{
|
|
601
|
-
binding: 1,
|
|
602
|
-
resource: {
|
|
603
|
-
kind: 'buffer',
|
|
604
|
-
value: {
|
|
605
|
-
buffer: skinResources.paletteBuffer,
|
|
606
|
-
offset: 0,
|
|
607
|
-
// M6 SSOT: static BG entry size (= MAX_JOINTS * 64 =
|
|
608
|
-
// 16320 B) sourced from the allocator. The per-draw
|
|
609
|
-
// window slides via `group2DynamicOffsets[1]`
|
|
610
|
-
// (= entry.source.skin.byteOffset) so this size
|
|
611
|
-
// stays at the worst case across all skin entries
|
|
612
|
-
// -- one BG covers every skinned draw in the frame
|
|
613
|
-
// (m3-1b miss=1 + hit=N-1 contract). The allocator
|
|
614
|
-
// guarantees `buffer.size >= byteOffset + this size`
|
|
615
|
-
// so dynOffset[1] passes WebGPU validation.
|
|
616
|
-
size: skinResources.paletteBindingWindowBytes,
|
|
617
|
-
},
|
|
618
|
-
},
|
|
619
|
-
},
|
|
620
|
-
],
|
|
646
|
+
entries: createPbrSkinMeshBindGroupEntries(
|
|
647
|
+
pipelineState.meshStorageBuffer.buffer,
|
|
648
|
+
meshBindSize,
|
|
649
|
+
skinResources.paletteBuffer,
|
|
650
|
+
skinResources.paletteBindingWindowBytes,
|
|
651
|
+
),
|
|
621
652
|
});
|
|
622
653
|
if (!result.ok) throw result.error;
|
|
623
654
|
return result.value;
|
|
@@ -634,9 +665,10 @@ export function recordGeometryDraws(
|
|
|
634
665
|
// Replaces the prior PR #353 hard-coded `0` second slot -- every
|
|
635
666
|
// skin entry now points the palette window at its own slice while
|
|
636
667
|
// sharing the worst-case BG entry size above.
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
668
|
+
group2DynamicOffsets = pbrSkinMeshDynamicOffsets(
|
|
669
|
+
i * MESH_PER_ENTITY_STRIDE,
|
|
670
|
+
entry.source.skin?.byteOffset ?? 0,
|
|
671
|
+
);
|
|
640
672
|
} else if (isSkinEntry) {
|
|
641
673
|
// Skin entry but skin PSO not ready (cache miss / async build pending,
|
|
642
674
|
// or skin pipeline layout failed at boot). Skip the draw rather than
|
|
@@ -778,6 +810,8 @@ export function recordGeometryDraws(
|
|
|
778
810
|
: geometryRenderStateForTopology(smTopology, submeshMaterial.renderState);
|
|
779
811
|
const pipelineRenderState = geometryRenderStateForPass(basePipelineRenderState, passKind);
|
|
780
812
|
let smPipelineHandle: typeof pipelineState.unlitPipeline;
|
|
813
|
+
let materialGroup2Contract: 'mesh' | 'skin' | 'cluster' | 'skin-cluster' | undefined;
|
|
814
|
+
let materialPipelineEntry: MaterialShaderPipelineEntry | null = null;
|
|
781
815
|
if (smMaterialShaderId === undefined || smMaterialShaderId === 'forgeax::default-unlit') {
|
|
782
816
|
const unlitShaderId = smMaterialShaderId ?? 'forgeax::default-unlit';
|
|
783
817
|
const unlitProjectionVariantResult = variantSetFromVertexLayoutProjection(
|
|
@@ -789,9 +823,10 @@ export function recordGeometryDraws(
|
|
|
789
823
|
continue;
|
|
790
824
|
}
|
|
791
825
|
const unlitHasColor = unlitProjectionVariantResult.value === 'VERTEX_COLOR_AVAILABLE=true';
|
|
792
|
-
const unlitVariantSet =
|
|
793
|
-
|
|
794
|
-
|
|
826
|
+
const unlitVariantSet = standardStorageVariantSet(
|
|
827
|
+
runtime.device.caps.storageBuffer,
|
|
828
|
+
unlitHasColor,
|
|
829
|
+
);
|
|
795
830
|
const unlitRsp = resolveMaterialPipeline(
|
|
796
831
|
unlitShaderId,
|
|
797
832
|
pipelineRenderState,
|
|
@@ -801,8 +836,9 @@ export function recordGeometryDraws(
|
|
|
801
836
|
colorFormatOverride,
|
|
802
837
|
entry.mesh.layoutProjection,
|
|
803
838
|
);
|
|
839
|
+
materialPipelineEntry = unlitRsp;
|
|
804
840
|
smPipelineHandle =
|
|
805
|
-
unlitRsp ??
|
|
841
|
+
unlitRsp?.pipeline ??
|
|
806
842
|
(colorFormatOverride === undefined
|
|
807
843
|
? selectGeometryPipeline(pipelineState, isHdrTarget, msaaActive)
|
|
808
844
|
: null);
|
|
@@ -829,11 +865,11 @@ export function recordGeometryDraws(
|
|
|
829
865
|
// VERTEX_COLOR_AVAILABLE=false axis, so retain the two capability
|
|
830
866
|
// axes explicitly or the selector would silently choose the URP
|
|
831
867
|
// group(2) layout for an HDRP cluster bind group.
|
|
832
|
-
const capabilityVariantSet =
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
868
|
+
const capabilityVariantSet = standardTopologyVariantSet(
|
|
869
|
+
c.standardLighting,
|
|
870
|
+
runtime.device.caps.storageBuffer,
|
|
871
|
+
hasVertexColor,
|
|
872
|
+
);
|
|
837
873
|
// Sprite's base request must retain the boot-selected artifact. Only
|
|
838
874
|
// SpriteInstances uses the explicit empty key for the
|
|
839
875
|
// PER_INSTANCE_REGION=true variant; synthesizing the generic PBR
|
|
@@ -877,7 +913,8 @@ export function recordGeometryDraws(
|
|
|
877
913
|
// build resolves. The pre-loop skin-PSO probe still skips the
|
|
878
914
|
// entire entry on first-submesh probe miss; this site only
|
|
879
915
|
// fires on per-submesh topology variance miss.
|
|
880
|
-
|
|
916
|
+
materialPipelineEntry = cachedPipeline;
|
|
917
|
+
smPipelineHandle = cachedPipeline?.pipeline ?? null;
|
|
881
918
|
} else {
|
|
882
919
|
smPipelineHandle = selectGeometryPipeline(pipelineState, isHdrTarget, msaaActive);
|
|
883
920
|
}
|
|
@@ -890,16 +927,16 @@ export function recordGeometryDraws(
|
|
|
890
927
|
// ordinary mesh group instead; choosing one group for the whole pass
|
|
891
928
|
// makes Dawn reject an otherwise valid unlit pipeline and invalidates
|
|
892
929
|
// the command buffer before it reaches the surface.
|
|
893
|
-
const usesStandardClusterBindings = smMaterialShaderId === 'forgeax::default-standard-pbr';
|
|
894
930
|
if (!isSkinEntry) {
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
931
|
+
materialGroup2Contract = materialPipelineEntry?.group2Contract;
|
|
932
|
+
if (materialGroup2Contract === undefined) continue;
|
|
933
|
+
const selectedGroup = selectMaterialGroup2(
|
|
934
|
+
meshGroup2,
|
|
935
|
+
meshBindGroup,
|
|
936
|
+
materialGroup2Contract,
|
|
937
|
+
);
|
|
938
|
+
if (selectedGroup === null) continue;
|
|
939
|
+
group2BindGroup = selectedGroup;
|
|
903
940
|
}
|
|
904
941
|
pass.setBindGroup(2, group2BindGroup, group2DynamicOffsets);
|
|
905
942
|
|
|
@@ -945,6 +982,9 @@ function resolveGeometryInstanceBuffer(
|
|
|
945
982
|
const { runtime, pipelineState, frameState } = c;
|
|
946
983
|
const inst = entry.source.instances;
|
|
947
984
|
if (inst === undefined) return identityInstanceDraws;
|
|
985
|
+
// A present, empty Instances array means zero draws. Do not fall back to
|
|
986
|
+
// the shared identity buffer, which would silently render one instance.
|
|
987
|
+
if (inst.instanceCount === 0) return [];
|
|
948
988
|
let instanceBuffer: Buffer = pipelineState.identityInstanceBuffer;
|
|
949
989
|
let instanceCount = 1;
|
|
950
990
|
{
|