@forgeax/engine-render 0.1.27 → 0.1.29
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 +842 -124
- package/dist/assembly/atmosphere-shader-prewarm.d.ts +6 -0
- package/dist/assembly/atmosphere-shader-prewarm.d.ts.map +1 -0
- package/dist/assembly/dynamic-geometry-host.d.ts +52 -0
- package/dist/assembly/dynamic-geometry-host.d.ts.map +1 -0
- package/dist/assembly/dynamic-geometry-runtime.d.ts +20 -0
- package/dist/assembly/dynamic-geometry-runtime.d.ts.map +1 -0
- package/dist/assembly/factory.d.ts +3 -1
- package/dist/assembly/factory.d.ts.map +1 -1
- package/dist/assembly/gpu-driven-owner.d.ts +10 -0
- package/dist/assembly/gpu-driven-owner.d.ts.map +1 -0
- package/dist/assembly/host-contract.d.ts +19 -0
- package/dist/assembly/host-contract.d.ts.map +1 -1
- package/dist/assembly/material/assembly.d.ts +7 -0
- package/dist/assembly/material/assembly.d.ts.map +1 -1
- package/dist/assembly/material-shader-policy.d.ts +3 -1
- package/dist/assembly/material-shader-policy.d.ts.map +1 -1
- package/dist/assembly/recovery/failure-location.d.ts +12 -0
- package/dist/assembly/recovery/failure-location.d.ts.map +1 -0
- package/dist/assembly/recovery/renderer-recover.d.ts +6 -4
- package/dist/assembly/recovery/renderer-recover.d.ts.map +1 -1
- package/dist/assembly/renderer-facade.d.ts.map +1 -1
- package/dist/assembly/renderer-feature-inspection.d.ts +5 -0
- package/dist/assembly/renderer-feature-inspection.d.ts.map +1 -0
- package/dist/assembly/renderer-frame-transaction.d.ts +19 -0
- package/dist/assembly/renderer-frame-transaction.d.ts.map +1 -1
- package/dist/assembly/renderer-helpers.d.ts +3 -0
- package/dist/assembly/renderer-helpers.d.ts.map +1 -1
- package/dist/assembly/renderer-inspection.d.ts +4 -0
- package/dist/assembly/renderer-inspection.d.ts.map +1 -1
- package/dist/assembly/shader-prewarm-policy.d.ts +6 -0
- package/dist/assembly/shader-prewarm-policy.d.ts.map +1 -1
- package/dist/assembly/skin-palette-owner.d.ts +8 -0
- package/dist/assembly/skin-palette-owner.d.ts.map +1 -0
- package/dist/assembly/ssr-shader-prewarm.d.ts +6 -0
- package/dist/assembly/ssr-shader-prewarm.d.ts.map +1 -0
- package/dist/assembly/webgpu-device-loss.d.ts +15 -0
- package/dist/assembly/webgpu-device-loss.d.ts.map +1 -0
- package/dist/assembly/webgpu-pbr-ready.d.ts +38 -0
- package/dist/assembly/webgpu-pbr-ready.d.ts.map +1 -0
- package/dist/assembly/webgpu-ready-mipmap.d.ts +11 -0
- package/dist/assembly/webgpu-ready-mipmap.d.ts.map +1 -0
- package/dist/assembly/webgpu-ready.d.ts +7 -3
- package/dist/assembly/webgpu-ready.d.ts.map +1 -1
- package/dist/assembly/webgpu-renderer-bootstrap.d.ts +10 -0
- package/dist/assembly/webgpu-renderer-bootstrap.d.ts.map +1 -0
- package/dist/assembly/webgpu-renderer-contract.d.ts +62 -0
- package/dist/assembly/webgpu-renderer-contract.d.ts.map +1 -0
- package/dist/assembly/webgpu-renderer-guards.d.ts +9 -0
- package/dist/assembly/webgpu-renderer-guards.d.ts.map +1 -0
- package/dist/assembly/webgpu-renderer-observation.d.ts +6 -0
- package/dist/assembly/webgpu-renderer-observation.d.ts.map +1 -0
- package/dist/assembly/webgpu-renderer-recovery-failure.d.ts +12 -0
- package/dist/assembly/webgpu-renderer-recovery-failure.d.ts.map +1 -0
- package/dist/assembly/webgpu-renderer.d.ts +7 -141
- package/dist/assembly/webgpu-renderer.d.ts.map +1 -1
- package/dist/assembly/webgpu-vertex-layouts.d.ts +28 -84
- package/dist/assembly/webgpu-vertex-layouts.d.ts.map +1 -1
- package/dist/authoring.mjs +3 -3
- package/dist/{chunk-ADHHVYLW.mjs → chunk-33XZFTQU.mjs} +245 -39
- package/dist/chunk-33XZFTQU.mjs.map +1 -0
- package/dist/{chunk-GF523LHF.mjs → chunk-BLXGONR2.mjs} +30 -12
- package/dist/chunk-BLXGONR2.mjs.map +1 -0
- package/dist/{chunk-KM2NOX2I.mjs → chunk-BQVQOQJH.mjs} +958 -254
- package/dist/chunk-BQVQOQJH.mjs.map +1 -0
- package/dist/{chunk-HKXTW355.mjs → chunk-BTWH7BP4.mjs} +386 -17
- package/dist/chunk-BTWH7BP4.mjs.map +1 -0
- package/dist/{chunk-TMIASV2N.mjs → chunk-FUODTTIA.mjs} +3934 -676
- package/dist/chunk-FUODTTIA.mjs.map +1 -0
- package/dist/{chunk-FJ6P52EE.mjs → chunk-ILQ5MEZF.mjs} +3 -17
- package/dist/chunk-ILQ5MEZF.mjs.map +1 -0
- package/dist/{chunk-E34VL5VI.mjs → chunk-JQTSEI3Z.mjs} +3 -3
- package/dist/{chunk-E34VL5VI.mjs.map → chunk-JQTSEI3Z.mjs.map} +1 -1
- package/dist/{chunk-GE3SDD72.mjs → chunk-NICXSHAT.mjs} +16 -38
- package/dist/chunk-NICXSHAT.mjs.map +1 -0
- package/dist/{chunk-ZZ4YQ474.mjs → chunk-NRNXBLIJ.mjs} +577 -7
- package/dist/chunk-NRNXBLIJ.mjs.map +1 -0
- package/dist/{chunk-JDWARUOI.mjs → chunk-PA5DRJNI.mjs} +17 -3
- package/dist/chunk-PA5DRJNI.mjs.map +1 -0
- package/dist/{chunk-XDP6XE5V.mjs → chunk-S4DNKQYQ.mjs} +1118 -446
- package/dist/chunk-S4DNKQYQ.mjs.map +1 -0
- package/dist/components/camera.d.ts +62 -2
- package/dist/components/camera.d.ts.map +1 -1
- package/dist/components/index.d.ts +1 -0
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/instances.d.ts +6 -20
- package/dist/components/instances.d.ts.map +1 -1
- package/dist/components/scene-instance.d.ts +2 -1
- package/dist/components/scene-instance.d.ts.map +1 -1
- package/dist/components/screen-space-reflection.d.ts +14 -0
- package/dist/components/screen-space-reflection.d.ts.map +1 -0
- package/dist/construct-renderer.mjs +13805 -7186
- package/dist/construct-renderer.mjs.map +1 -1
- package/dist/device/gpu-residency.d.ts +11 -17
- package/dist/device/gpu-residency.d.ts.map +1 -1
- package/dist/device/mesh-residency-lifetime.d.ts +21 -0
- package/dist/device/mesh-residency-lifetime.d.ts.map +1 -0
- package/dist/dynamic-geometry.d.ts +125 -0
- package/dist/dynamic-geometry.d.ts.map +1 -0
- package/dist/environment/background.d.ts +6 -0
- package/dist/environment/background.d.ts.map +1 -0
- package/dist/errors/gpu-driven.d.ts +6 -3
- package/dist/errors/gpu-driven.d.ts.map +1 -1
- package/dist/errors/render.d.ts +7 -4
- package/dist/errors/render.d.ts.map +1 -1
- package/dist/extract/camera.d.ts.map +1 -1
- package/dist/extract/gpu-driven.d.ts +33 -3
- package/dist/extract/gpu-driven.d.ts.map +1 -1
- package/dist/features/host.d.ts +23 -1
- package/dist/features/host.d.ts.map +1 -1
- package/dist/features/noise-texture.d.ts +17 -0
- package/dist/features/noise-texture.d.ts.map +1 -0
- package/dist/features/plan.d.ts +83 -2
- package/dist/features/plan.d.ts.map +1 -1
- package/dist/features/prepared-gpu-work.d.ts +37 -4
- package/dist/features/prepared-gpu-work.d.ts.map +1 -1
- package/dist/features/prepared-graphics-store.d.ts.map +1 -1
- package/dist/features/prepared-graphics.d.ts +5 -0
- package/dist/features/prepared-graphics.d.ts.map +1 -1
- package/dist/features/render-graph-compute.d.ts +5 -3
- package/dist/features/render-graph-compute.d.ts.map +1 -1
- package/dist/features/render-graph-contribution.d.ts +11 -3
- package/dist/features/render-graph-contribution.d.ts.map +1 -1
- package/dist/features/render-graph-raster.d.ts +19 -3
- package/dist/features/render-graph-raster.d.ts.map +1 -1
- package/dist/features/types.d.ts +11 -0
- package/dist/features/types.d.ts.map +1 -1
- package/dist/fullscreen-post-process-pass.d.ts +2 -0
- package/dist/fullscreen-post-process-pass.d.ts.map +1 -1
- package/dist/gpu-driven/batch-topology.d.ts +34 -1
- package/dist/gpu-driven/batch-topology.d.ts.map +1 -1
- package/dist/gpu-driven/pbr-program.d.ts +10 -0
- package/dist/gpu-driven/pbr-program.d.ts.map +1 -0
- package/dist/gpu-driven/prepared-draw.d.ts.map +1 -1
- package/dist/gpu-driven/production-raster.d.ts +144 -23
- package/dist/gpu-driven/production-raster.d.ts.map +1 -1
- package/dist/gpu-driven/shadow-views.d.ts +126 -0
- package/dist/gpu-driven/shadow-views.d.ts.map +1 -0
- package/dist/gpu-driven/view-gpu.d.ts +18 -2
- package/dist/gpu-driven/view-gpu.d.ts.map +1 -1
- package/dist/gpu-scene-schema.d.ts +2 -8
- package/dist/gpu-scene-schema.d.ts.map +1 -1
- package/dist/gpu-scene.d.ts +14 -0
- package/dist/gpu-scene.d.ts.map +1 -1
- package/dist/gpu-texture-usage.d.ts +1 -0
- package/dist/gpu-texture-usage.d.ts.map +1 -1
- package/dist/hdrp-buffers.d.ts +6 -0
- package/dist/hdrp-buffers.d.ts.map +1 -1
- package/dist/ibl/frame-resources.d.ts +8 -0
- package/dist/ibl/frame-resources.d.ts.map +1 -0
- package/dist/ibl/skylight-bind-group.d.ts.map +1 -1
- package/dist/index.d.ts +21 -8
- package/dist/index.d.ts.map +1 -1
- package/dist/index.mjs +8 -7
- package/dist/index.mjs.map +1 -1
- package/dist/inspection-types.d.ts +164 -0
- package/dist/inspection-types.d.ts.map +1 -1
- package/dist/instances-derived-bounds.d.ts +11 -0
- package/dist/instances-derived-bounds.d.ts.map +1 -1
- package/dist/instances.d.ts +89 -44
- package/dist/instances.d.ts.map +1 -1
- package/dist/internal.d.ts +3 -0
- package/dist/internal.d.ts.map +1 -1
- package/dist/internal.mjs +118 -10
- package/dist/internal.mjs.map +1 -1
- package/dist/lifecycle.d.ts +2 -1
- package/dist/lifecycle.d.ts.map +1 -1
- package/dist/material-row.d.ts +5 -0
- package/dist/material-row.d.ts.map +1 -0
- package/dist/materials.d.ts +15 -0
- package/dist/materials.d.ts.map +1 -1
- package/dist/pbr-pipeline.d.ts +21 -5
- package/dist/pbr-pipeline.d.ts.map +1 -1
- package/dist/pipeline/standard-forward-lane.d.ts.map +1 -1
- package/dist/pipeline/standard-output/auto-exposure/capability.d.ts +12 -0
- package/dist/pipeline/standard-output/auto-exposure/capability.d.ts.map +1 -0
- package/dist/pipeline/standard-output/auto-exposure/gpu.d.ts +70 -0
- package/dist/pipeline/standard-output/auto-exposure/gpu.d.ts.map +1 -0
- package/dist/pipeline/standard-output/auto-exposure/graph.d.ts +75 -0
- package/dist/pipeline/standard-output/auto-exposure/graph.d.ts.map +1 -0
- package/dist/pipeline/standard-output/auto-exposure/inspection.d.ts +111 -0
- package/dist/pipeline/standard-output/auto-exposure/inspection.d.ts.map +1 -0
- package/dist/pipeline/standard-output/auto-exposure/oracle.d.ts +16 -0
- package/dist/pipeline/standard-output/auto-exposure/oracle.d.ts.map +1 -0
- package/dist/pipeline/standard-output/auto-exposure/preset.d.ts +14 -0
- package/dist/pipeline/standard-output/auto-exposure/preset.d.ts.map +1 -0
- package/dist/pipeline/standard-output/auto-exposure/state.d.ts +46 -0
- package/dist/pipeline/standard-output/auto-exposure/state.d.ts.map +1 -0
- package/dist/pipeline/standard-output/color-transform.d.ts +27 -0
- package/dist/pipeline/standard-output/color-transform.d.ts.map +1 -0
- package/dist/pipeline/standard-output/graph.d.ts +15 -0
- package/dist/pipeline/standard-output/graph.d.ts.map +1 -0
- package/dist/pipeline/standard-output/lut-admission.d.ts +29 -0
- package/dist/pipeline/standard-output/lut-admission.d.ts.map +1 -0
- package/dist/pipeline/standard-output/lut-gpu.d.ts +48 -0
- package/dist/pipeline/standard-output/lut-gpu.d.ts.map +1 -0
- package/dist/pipeline/standard-output/lut-state.d.ts +68 -0
- package/dist/pipeline/standard-output/lut-state.d.ts.map +1 -0
- package/dist/pipeline/standard-output/resources.d.ts +10 -0
- package/dist/pipeline/standard-output/resources.d.ts.map +1 -0
- package/dist/pipeline/standard-output/types.d.ts +39 -0
- package/dist/pipeline/standard-output/types.d.ts.map +1 -0
- package/dist/pipeline/standard-pipeline.d.ts.map +1 -1
- package/dist/pipeline/standard-post.d.ts +2 -2
- package/dist/pipeline/standard-post.d.ts.map +1 -1
- package/dist/pipeline-builder.d.ts +2 -1
- package/dist/pipeline-builder.d.ts.map +1 -1
- package/dist/pipeline-spec-types.d.ts +4 -0
- package/dist/pipeline-spec-types.d.ts.map +1 -1
- package/dist/pipeline-spec.d.ts +1 -9
- package/dist/pipeline-spec.d.ts.map +1 -1
- package/dist/points-lines/standard-owner.d.ts +1 -1
- package/dist/points-lines/standard-owner.d.ts.map +1 -1
- package/dist/prepare/prepared-graphics-resolver.d.ts +6 -1
- package/dist/prepare/prepared-graphics-resolver.d.ts.map +1 -1
- package/dist/record/dynamic-geometry-consumption.d.ts +15 -0
- package/dist/record/dynamic-geometry-consumption.d.ts.map +1 -0
- package/dist/record/frame-lighting.d.ts +3 -3
- package/dist/record/frame-lighting.d.ts.map +1 -1
- package/dist/record/frame-snapshot.d.ts +106 -5
- package/dist/record/frame-snapshot.d.ts.map +1 -1
- package/dist/record/frame-targets.d.ts.map +1 -1
- package/dist/record/frame.d.ts +39 -4
- package/dist/record/frame.d.ts.map +1 -1
- package/dist/record/main-pass-geometry.d.ts +7 -8
- package/dist/record/main-pass-geometry.d.ts.map +1 -1
- package/dist/record/main-pass-material.d.ts +38 -1
- package/dist/record/main-pass-material.d.ts.map +1 -1
- package/dist/record/main-pass-sprite-draws.d.ts +2 -10
- package/dist/record/main-pass-sprite-draws.d.ts.map +1 -1
- package/dist/record/main-pass.d.ts +12 -2
- package/dist/record/main-pass.d.ts.map +1 -1
- package/dist/record/mesh-ssbo.d.ts +15 -6
- package/dist/record/mesh-ssbo.d.ts.map +1 -1
- package/dist/record/prepared-material-bindings.d.ts +19 -0
- package/dist/record/prepared-material-bindings.d.ts.map +1 -0
- package/dist/record/recovery-pipeline.d.ts +2 -9
- package/dist/record/recovery-pipeline.d.ts.map +1 -1
- package/dist/record/render-context.d.ts +76 -26
- package/dist/record/render-context.d.ts.map +1 -1
- package/dist/record/shadow-pass.d.ts +62 -7
- package/dist/record/shadow-pass.d.ts.map +1 -1
- package/dist/record/skybox-post-pass.d.ts +1 -1
- package/dist/record/skybox-post-pass.d.ts.map +1 -1
- package/dist/record/typed-frame-graph.d.ts +35 -7
- package/dist/record/typed-frame-graph.d.ts.map +1 -1
- package/dist/record/view-ubo.d.ts +1 -0
- package/dist/record/view-ubo.d.ts.map +1 -1
- package/dist/recovery/render-system-candidate.d.ts +10 -2
- package/dist/recovery/render-system-candidate.d.ts.map +1 -1
- package/dist/recovery/render-system-roots.d.ts +11 -0
- package/dist/recovery/render-system-roots.d.ts.map +1 -0
- package/dist/recovery/types.d.ts +76 -0
- package/dist/recovery/types.d.ts.map +1 -0
- package/dist/reflection/record-owner.d.ts +0 -2
- package/dist/reflection/record-owner.d.ts.map +1 -1
- package/dist/render-contract.d.ts +185 -30
- package/dist/render-contract.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 +64 -5
- package/dist/render-pipeline.d.ts.map +1 -1
- package/dist/render-system-extract-tail.d.ts +7 -5
- package/dist/render-system-extract-tail.d.ts.map +1 -1
- package/dist/render-system-extract.d.ts +101 -41
- package/dist/render-system-extract.d.ts.map +1 -1
- package/dist/render-system-projections.d.ts +22 -0
- package/dist/render-system-projections.d.ts.map +1 -0
- package/dist/render-system.d.ts +34 -77
- package/dist/render-system.d.ts.map +1 -1
- package/dist/scene/render-scene-types.d.ts +14 -7
- package/dist/scene/render-scene-types.d.ts.map +1 -1
- package/dist/scene/render-scene.d.ts +29 -11
- package/dist/scene/render-scene.d.ts.map +1 -1
- package/dist/scene/shadow-visibility.d.ts +5 -0
- package/dist/scene/shadow-visibility.d.ts.map +1 -0
- package/dist/ssr/admission.d.ts +70 -1
- package/dist/ssr/admission.d.ts.map +1 -1
- package/dist/ssr/compose.d.ts +13 -0
- package/dist/ssr/compose.d.ts.map +1 -0
- package/dist/ssr/errors.d.ts +35 -0
- package/dist/ssr/errors.d.ts.map +1 -1
- package/dist/ssr/graph.d.ts +60 -0
- package/dist/ssr/graph.d.ts.map +1 -0
- package/dist/ssr/history.d.ts +97 -0
- package/dist/ssr/history.d.ts.map +1 -0
- package/dist/ssr/hiz.d.ts +37 -0
- package/dist/ssr/hiz.d.ts.map +1 -0
- package/dist/ssr/inspection.d.ts +42 -0
- package/dist/ssr/inspection.d.ts.map +1 -0
- package/dist/ssr/resources.d.ts +58 -0
- package/dist/ssr/resources.d.ts.map +1 -0
- package/dist/ssr/temporal.d.ts +38 -0
- package/dist/ssr/temporal.d.ts.map +1 -0
- package/dist/systems/skin-palette-allocator.d.ts +32 -10
- package/dist/systems/skin-palette-allocator.d.ts.map +1 -1
- package/dist/systems/skin-palette-types.d.ts +15 -0
- package/dist/systems/skin-palette-types.d.ts.map +1 -1
- package/dist/systems/transparent-dispatch.d.ts +9 -0
- package/dist/systems/transparent-dispatch.d.ts.map +1 -0
- package/dist/targets/material-source.d.ts +7 -0
- package/dist/targets/material-source.d.ts.map +1 -1
- package/dist/temporal/frame-coordinator.d.ts +7 -0
- package/dist/temporal/frame-coordinator.d.ts.map +1 -1
- package/dist/temporal/gpu.d.ts +8 -0
- package/dist/temporal/gpu.d.ts.map +1 -1
- package/dist/temporal/history.d.ts.map +1 -1
- package/dist/temporal/index.mjs +6 -6
- package/dist/temporal/inspection.d.ts.map +1 -1
- package/dist/temporal/standard-scene-data.d.ts +2 -1
- package/dist/temporal/standard-scene-data.d.ts.map +1 -1
- package/dist/temporal/temporal-view.d.ts +2 -0
- package/dist/temporal/temporal-view.d.ts.map +1 -1
- package/dist/typed-render-graph-primitives.d.ts +35 -1
- package/dist/typed-render-graph-primitives.d.ts.map +1 -1
- package/dist/typed-shadow-passes.d.ts +3 -1
- package/dist/typed-shadow-passes.d.ts.map +1 -1
- package/dist/volume/temporal.d.ts +6 -0
- package/dist/volume/temporal.d.ts.map +1 -1
- package/package.json +21 -20
- package/src/__tests__/auto-exposure-gpu-evidence.ts +291 -0
- package/src/__tests__/auto-exposure-inspection.unit.test.ts +80 -0
- package/src/__tests__/auto-exposure-transaction.integration.test.ts +99 -0
- package/src/__tests__/auto-exposure.browser.test.ts +33 -0
- package/src/__tests__/auto-exposure.dawn.test.ts +33 -0
- package/src/__tests__/detached-inspection.integration.test.ts +5 -0
- package/src/__tests__/device-scope-lifecycle.unit.test.ts +18 -0
- package/src/__tests__/device-scope-stale-matrix.unit.test.ts +18 -0
- package/src/__tests__/docs-gate-green.unit.test.ts +3 -3
- package/src/__tests__/dynamic-geometry-host.unit.test.ts +1123 -0
- package/src/__tests__/dynamic-geometry.unit.test.ts +233 -0
- package/src/__tests__/factory-contract.integration.test.ts +73 -22
- package/src/__tests__/fallback-row-stride-surface.unit.test.ts +19 -0
- package/src/__tests__/feature-depth-input.dawn.test.ts +121 -0
- package/src/__tests__/feature-noise.unit.test.ts +38 -0
- package/src/__tests__/fixtures/taa-resolve-pinned-baseline.wgsl +301 -0
- package/src/__tests__/frame-camera-selection.unit.test.ts +131 -0
- package/src/__tests__/frame-plan-contract.unit.test.ts +24 -0
- package/src/__tests__/frame-targets.unit.test.ts +24 -0
- package/src/__tests__/fullscreen-feature-plan.unit.test.ts +3 -0
- package/src/__tests__/gpu-driven-baseline.characterization.test.ts +79 -0
- package/src/__tests__/gpu-driven-batch-topology-pbr.unit.test.ts +287 -6
- package/src/__tests__/gpu-driven-indirect-raster-evidence.ts +122 -142
- package/src/__tests__/gpu-driven-indirect-raster.browser.test.ts +10 -1
- package/src/__tests__/gpu-driven-lod-cache.unit.test.ts +264 -0
- package/src/__tests__/gpu-driven-mesh-world-identity.unit.test.ts +349 -0
- package/src/__tests__/gpu-driven-pbr.dawn.test.ts +1417 -0
- package/src/__tests__/gpu-driven-pbr.integration.test.ts +21 -0
- package/src/__tests__/gpu-driven-production-fixture.ts +96 -0
- package/src/__tests__/gpu-driven-production.integration.test.ts +1075 -93
- package/src/__tests__/gpu-driven-scaling.unit.test.ts +1 -3
- package/src/__tests__/gpu-driven-shadow-views.browser.test.ts +63 -0
- package/src/__tests__/gpu-driven-shadow-views.dawn.test.ts +294 -0
- package/src/__tests__/gpu-driven-shadow-views.integration.test.ts +97 -0
- package/src/__tests__/gpu-driven-shadow-views.unit.test.ts +168 -0
- package/src/__tests__/gpu-driven-skin-contract.test-d.ts +11 -0
- package/src/__tests__/gpu-driven-view-gpu-evidence.ts +72 -20
- package/src/__tests__/gpu-driven-view-graph.integration.test.ts +30 -9
- package/src/__tests__/gpu-driven-view.unit.test.ts +159 -52
- package/src/__tests__/gpu-pass-timing.browser.test.ts +6 -1
- package/src/__tests__/gpu-resource-store-stride.unit.test.ts +42 -0
- package/src/__tests__/gpu-scene-render-graph-gpu.ts +19 -5
- package/src/__tests__/gpu-scene.dawn.test.ts +40 -13
- package/src/__tests__/gpu-scene.unit.test.ts +559 -33
- package/src/__tests__/instances-culling.integration.test.ts +36 -10
- package/src/__tests__/instances-derived-bounds.unit.test.ts +54 -0
- package/src/__tests__/instances-store.unit.test.ts +242 -39
- package/src/__tests__/ktx2-basis-gpu-consumer.dawn.test.ts +6 -0
- package/src/__tests__/lighting-scene-roundtrip.integration.test.ts +13 -16
- package/src/__tests__/lut-lkg-transaction.integration.test.ts +122 -0
- package/src/__tests__/material-contract-inventory.unit.test.ts +5 -6
- package/src/__tests__/material-dispatch-shader-id.unit.test.ts +51 -0
- package/src/__tests__/material-lane-selection.unit.test.ts +60 -0
- package/src/__tests__/material-numeric-upload.unit.test.ts +53 -0
- package/src/__tests__/material-texture-handles.unit.test.ts +18 -0
- package/src/__tests__/material-texture-source.unit.test.ts +87 -0
- package/src/__tests__/materials-authoring-validation.unit.test.ts +41 -0
- package/src/__tests__/materials-standard-contract.unit.test.ts +52 -2
- package/src/__tests__/mesh-buffer-usage-surface.unit.test.ts +4 -0
- package/src/__tests__/mesh-submission-lifetime.unit.test.ts +53 -0
- package/src/__tests__/normal-fallback.dawn.test.ts +122 -0
- package/src/__tests__/particle-material-input-layout.unit.test.ts +104 -0
- package/src/__tests__/physical-clearcoat.integration.test.ts +37 -3
- package/src/__tests__/pipeline-texture-specialization.unit.test.ts +138 -0
- package/src/__tests__/point-shadow-inspection.unit.test.ts +2 -0
- package/src/__tests__/prepared-gpu-driven-pbr-contract.test-d.ts +31 -0
- package/src/__tests__/prepared-gpu-driven-pbr-contract.unit.test.ts +39 -0
- package/src/__tests__/prepared-gpu-driven-pbr.integration.test.ts +35 -4
- package/src/__tests__/prepared-graphics-capability.unit.test.ts +21 -0
- package/src/__tests__/prepared-graphics-pipeline-warmup.unit.test.ts +6 -2
- package/src/__tests__/profiler-phase-catalog.test.ts +5 -0
- package/src/__tests__/public-surface.test-d.ts +3 -0
- package/src/__tests__/recovery-candidate-prepare.contract.test.ts +30 -12
- package/src/__tests__/reflection-fallback-async-publication.unit.test.ts +104 -0
- package/src/__tests__/reflection-probe-record-owner.characterization.unit.test.ts +2 -1
- package/src/__tests__/render-error-code-owner.test-d.ts +4 -0
- package/src/__tests__/render-error-detail-ssot.test-d.ts +22 -0
- package/src/__tests__/render-error-exhaustive.test-d.ts +15 -0
- package/src/__tests__/render-feature-gpu-work.integration.test.ts +285 -2
- package/src/__tests__/render-feature-plan.unit.test.ts +245 -0
- package/src/__tests__/render-feature-shadow-order.unit.test.ts +228 -0
- package/src/__tests__/render-feature-zero-work.unit.test.ts +35 -1
- package/src/__tests__/render-graph-fallback.integration.test.ts +2 -2
- package/src/__tests__/render-owner-cohesion.unit.test.ts +55 -0
- package/src/__tests__/render-scene-mixed-updates.integration.test.ts +426 -0
- package/src/__tests__/render-scene-projection.unit.test.ts +914 -23
- package/src/__tests__/render-scene-resource-updates.integration.test.ts +214 -0
- package/src/__tests__/render-scene-skin-lifecycle.integration.test.ts +173 -0
- package/src/__tests__/render-scene-temporal-retry.unit.test.ts +133 -0
- package/src/__tests__/render-target-material-source.test-d.ts +27 -3
- package/src/__tests__/renderer-factory-material-contract.unit.test.ts +61 -1
- package/src/__tests__/renderer-frame-transaction.integration.test.ts +923 -5
- package/src/__tests__/shader-manifest-fixture.ts +39 -0
- package/src/__tests__/skin-motion-regression.unit.test.ts +0 -33
- package/src/__tests__/skin-palette-persistent.integration.test.ts +28 -0
- package/src/__tests__/skin-palette-persistent.unit.test.ts +247 -0
- package/src/__tests__/skinned-shadow-caster.test.ts +118 -14
- package/src/__tests__/specular-environment-scale.dawn.test.ts +156 -0
- package/src/__tests__/ssr-admission-matrix.integration.test.ts +7 -1
- package/src/__tests__/ssr-confidence-compose.unit.test.ts +84 -0
- package/src/__tests__/ssr-coordinate-oracle.unit.test.ts +28 -0
- package/src/__tests__/ssr-format-probe-gating.integration.test.ts +82 -0
- package/src/__tests__/ssr-gpu-dispatch.browser.test.ts +91 -0
- package/src/__tests__/ssr-gpu-dispatch.dawn.test.ts +112 -0
- package/src/__tests__/ssr-gpu-dispatch.ts +946 -0
- package/src/__tests__/ssr-graph-topology.unit.test.ts +104 -0
- package/src/__tests__/ssr-history-filter.dawn.test.ts +198 -0
- package/src/__tests__/ssr-hit-color.dawn.test.ts +273 -0
- package/src/__tests__/ssr-hiz-odd-reduction.dawn.test.ts +569 -0
- package/src/__tests__/ssr-hiz-rescue.dawn.test.ts +279 -0
- package/src/__tests__/ssr-hiz.browser.test.ts +150 -0
- package/src/__tests__/ssr-hiz.dawn.test.ts +150 -0
- package/src/__tests__/ssr-hiz.unit.test.ts +56 -0
- package/src/__tests__/ssr-inspection.unit.test.ts +105 -0
- package/src/__tests__/ssr-memory-budget.unit.test.ts +45 -0
- package/src/__tests__/ssr-performance-sequence-aggregation.unit.test.ts +15 -0
- package/src/__tests__/ssr-public-surface.test-d.ts +37 -0
- package/src/__tests__/ssr-receiver-coverage.dawn.test.ts +387 -0
- package/src/__tests__/ssr-reflection-mip-reducer.dawn.test.ts +309 -0
- package/src/__tests__/ssr-reprojection-probe.ts +90 -0
- package/src/__tests__/ssr-roughness-mip.dawn.test.ts +163 -0
- package/src/__tests__/ssr-shader-prewarm.unit.test.ts +59 -0
- package/src/__tests__/ssr-spatial.integration.test.ts +141 -0
- package/src/__tests__/ssr-stable-lattice.dawn.test.ts +475 -0
- package/src/__tests__/ssr-temporal-history.unit.test.ts +202 -0
- package/src/__tests__/ssr-texel-crossing.dawn.test.ts +448 -0
- package/src/__tests__/ssr-zero-work.integration.test.ts +87 -0
- package/src/__tests__/standard-cluster-variant-resolution.unit.test.ts +44 -12
- package/src/__tests__/standard-clustered-pipeline.unit.test.ts +29 -0
- package/src/__tests__/standard-output-chain-contract.unit.test.ts +99 -0
- package/src/__tests__/standard-output-chain.integration.test.ts +73 -0
- package/src/__tests__/standard-output-gpu-evidence.ts +205 -0
- package/src/__tests__/standard-output.browser.test.ts +15 -0
- package/src/__tests__/standard-output.dawn.test.ts +15 -0
- package/src/__tests__/standard-pbr-artifact-assembly.unit.test.ts +38 -0
- package/src/__tests__/standard-pipeline.integration.test.ts +320 -3
- package/src/__tests__/standard-profile-oracle.unit.test.ts +22 -0
- package/src/__tests__/standard-surface-lighting.unit.test.ts +41 -0
- package/src/__tests__/standard-texture-specialization.dawn.test.ts +141 -0
- package/src/__tests__/surface-adjacent-regressions.integration.test.ts +6 -3
- package/src/__tests__/taa-coverage-edge.dawn.test.ts +193 -0
- package/src/__tests__/taa-history-clipping.dawn.test.ts +328 -0
- package/src/__tests__/taa-neighborhood-equivalence.dawn.test.ts +778 -0
- package/src/__tests__/taa-stability-feedback.browser.test.ts +23 -0
- package/src/__tests__/taa-stability-feedback.dawn.test.ts +68 -0
- package/src/__tests__/taa-stability-feedback.ts +341 -0
- package/src/__tests__/temporal-history-lifecycle.unit.test.ts +49 -7
- package/src/__tests__/temporal-reset-matrix.unit.test.ts +9 -0
- package/src/__tests__/temporal-transaction.integration.test.ts +28 -0
- package/src/__tests__/texture-usage-surface.unit.test.ts +4 -2
- package/src/__tests__/typed-pipeline-topology.unit.test.ts +109 -4
- package/src/__tests__/typed-scene-pass-material-cache.integration.test.ts +126 -0
- package/src/__tests__/vertex-layouts-ssot.unit.test.ts +47 -0
- package/src/__tests__/visibility-extract.perf.test.ts +20 -8
- package/src/__tests__/visibility-instances.integration.test.ts +19 -7
- package/src/__tests__/visibility-producer-matrix.integration.test.ts +20 -9
- package/src/assembly/atmosphere-shader-prewarm.ts +38 -0
- package/src/assembly/dynamic-geometry-host.ts +887 -0
- package/src/assembly/dynamic-geometry-runtime.ts +71 -0
- package/src/assembly/factory.ts +4 -0
- package/src/assembly/gpu-driven-owner.ts +29 -0
- package/src/assembly/host-contract.ts +36 -0
- package/src/assembly/material/assembly.ts +38 -0
- package/src/assembly/material-shader-policy.ts +71 -28
- package/src/assembly/recovery/failure-location.ts +62 -0
- package/src/assembly/recovery/renderer-recover.ts +19 -17
- package/src/assembly/renderer-facade.ts +29 -0
- package/src/assembly/renderer-feature-inspection.ts +13 -0
- package/src/assembly/renderer-frame-transaction.ts +63 -0
- package/src/assembly/renderer-helpers.ts +26 -0
- package/src/assembly/renderer-inspection.ts +6 -0
- package/src/assembly/shader-prewarm-policy.ts +32 -0
- package/src/assembly/skin-palette-owner.ts +21 -0
- package/src/assembly/ssr-shader-prewarm.ts +41 -0
- package/src/assembly/webgpu-device-loss.ts +75 -0
- package/src/assembly/webgpu-pbr-ready.ts +232 -0
- package/src/assembly/webgpu-ready-mipmap.ts +26 -0
- package/src/assembly/webgpu-ready.ts +142 -121
- package/src/assembly/webgpu-renderer-bootstrap.ts +85 -0
- package/src/assembly/webgpu-renderer-contract.ts +69 -0
- package/src/assembly/webgpu-renderer-guards.ts +32 -0
- package/src/assembly/webgpu-renderer-observation.ts +43 -0
- package/src/assembly/webgpu-renderer-recovery-failure.ts +62 -0
- package/src/assembly/webgpu-renderer.ts +675 -614
- package/src/assembly/webgpu-vertex-layouts.ts +233 -87
- package/src/components/__tests__/camera-exposure.contract.unit.test.ts +153 -0
- package/src/components/camera.ts +287 -7
- package/src/components/index.ts +1 -0
- package/src/components/instances.ts +45 -18
- package/src/components/scene-instance.ts +2 -1
- package/src/components/screen-space-reflection.ts +21 -0
- package/src/components/sprite-animation.ts +3 -3
- package/src/components/sprite-instances.ts +1 -1
- package/src/device/gpu-residency.ts +96 -93
- package/src/device/mesh-residency-lifetime.ts +73 -0
- package/src/dynamic-geometry.ts +736 -0
- package/src/environment/background.ts +263 -0
- package/src/errors/gpu-driven.ts +39 -5
- package/src/errors/render.ts +27 -3
- package/src/extract/camera.ts +26 -1
- package/src/extract/gpu-driven.ts +185 -10
- package/src/features/host.ts +237 -19
- package/src/features/noise-texture.ts +91 -0
- package/src/features/plan.ts +553 -24
- package/src/features/prepared-gpu-work.ts +631 -49
- package/src/features/prepared-graphics-store.ts +31 -0
- package/src/features/prepared-graphics.ts +5 -0
- package/src/features/render-graph-compute.ts +41 -8
- package/src/features/render-graph-contribution.ts +141 -3
- package/src/features/render-graph-raster.ts +143 -30
- package/src/features/types.ts +11 -0
- package/src/fullscreen-post-process-pass.ts +3 -0
- package/src/gpu-driven/batch-topology.ts +424 -102
- package/src/gpu-driven/pbr-program.ts +31 -0
- package/src/gpu-driven/prepared-draw.ts +29 -4
- package/src/gpu-driven/production-raster.ts +2267 -694
- package/src/gpu-driven/shadow-views.ts +539 -0
- package/src/gpu-driven/view-gpu.ts +188 -41
- package/src/gpu-scene-schema.ts +52 -11
- package/src/gpu-scene.ts +186 -99
- package/src/gpu-texture-usage.ts +1 -0
- package/src/hdrp-buffers.ts +72 -36
- package/src/ibl/frame-resources.ts +38 -0
- package/src/ibl/skylight-bind-group.ts +5 -4
- package/src/index.ts +125 -1
- package/src/inspection-types.ts +191 -0
- package/src/instances-derived-bounds.ts +258 -34
- package/src/instances.ts +459 -150
- package/src/internal.ts +22 -0
- package/src/lifecycle.ts +2 -0
- package/src/material-row.ts +145 -0
- package/src/materials.ts +44 -8
- package/src/pbr-pipeline.ts +159 -17
- package/src/pipeline/standard-forward-lane.ts +52 -24
- package/src/pipeline/standard-output/__tests__/lut-admission.unit.test.ts +103 -0
- package/src/pipeline/standard-output/auto-exposure/__tests__/capability.unit.test.ts +40 -0
- package/src/pipeline/standard-output/auto-exposure/__tests__/gpu.contract.unit.test.ts +125 -0
- package/src/pipeline/standard-output/auto-exposure/__tests__/graph.contract.unit.test.ts +94 -0
- package/src/pipeline/standard-output/auto-exposure/__tests__/oracle.test.ts +108 -0
- package/src/pipeline/standard-output/auto-exposure/__tests__/preset.test.ts +26 -0
- package/src/pipeline/standard-output/auto-exposure/capability.ts +38 -0
- package/src/pipeline/standard-output/auto-exposure/gpu.ts +567 -0
- package/src/pipeline/standard-output/auto-exposure/graph.ts +221 -0
- package/src/pipeline/standard-output/auto-exposure/inspection.ts +231 -0
- package/src/pipeline/standard-output/auto-exposure/oracle.ts +291 -0
- package/src/pipeline/standard-output/auto-exposure/preset.ts +28 -0
- package/src/pipeline/standard-output/auto-exposure/state.ts +156 -0
- package/src/pipeline/standard-output/color-transform.ts +124 -0
- package/src/pipeline/standard-output/graph.ts +139 -0
- package/src/pipeline/standard-output/lut-admission.ts +121 -0
- package/src/pipeline/standard-output/lut-gpu.ts +399 -0
- package/src/pipeline/standard-output/lut-state.ts +176 -0
- package/src/pipeline/standard-output/resources.ts +121 -0
- package/src/pipeline/standard-output/types.ts +58 -0
- package/src/pipeline/standard-pipeline.ts +192 -59
- package/src/pipeline/standard-post.ts +186 -27
- package/src/pipeline-builder.ts +16 -6
- package/src/pipeline-spec-types.ts +4 -0
- package/src/pipeline-spec.ts +37 -29
- package/src/points-lines/standard-owner.ts +6 -14
- package/src/prepare/prepared-graphics-resolver.ts +9 -2
- package/src/record/__tests__/material-slot-plan.unit.test.ts +48 -0
- package/src/record/__tests__/mesh-ssbo.unit.test.ts +40 -1
- package/src/record/__tests__/recovery-pipeline.unit.test.ts +2 -29
- package/src/record/__tests__/sprite-material-abi.unit.test.ts +36 -5
- package/src/record/__tests__/typed-frame-graph-plan.unit.test.ts +45 -0
- package/src/record/__tests__/view-ubo-layout.unit.test.ts +5 -0
- package/src/record/dynamic-geometry-consumption.ts +59 -0
- package/src/record/frame-lighting.ts +12 -11
- package/src/record/frame-snapshot.ts +133 -23
- package/src/record/frame-targets.ts +9 -0
- package/src/record/frame.ts +727 -133
- package/src/record/main-pass-geometry.ts +162 -98
- package/src/record/main-pass-material.ts +115 -26
- package/src/record/main-pass-sprite-draws.ts +18 -107
- package/src/record/main-pass.ts +78 -8
- package/src/record/material-uniforms.ts +1 -1
- package/src/record/mesh-ssbo.ts +59 -15
- package/src/record/prepared-material-bindings.ts +234 -0
- package/src/record/recovery-pipeline.ts +59 -136
- package/src/record/render-context.ts +92 -22
- package/src/record/shadow-pass.ts +1231 -209
- package/src/record/skybox-post-pass.ts +14 -3
- package/src/record/typed-frame-graph.ts +1006 -53
- package/src/record/view-ubo.ts +11 -0
- package/src/recovery/render-system-candidate.ts +90 -66
- package/src/recovery/render-system-roots.ts +113 -0
- package/src/recovery/types.ts +77 -0
- package/src/reflection/record-owner.ts +26 -54
- package/src/render-contract.ts +219 -25
- package/src/render-graph-primitives.ts +6 -2
- package/src/render-pipeline.ts +70 -1
- package/src/render-system-extract-tail.ts +409 -160
- package/src/render-system-extract.ts +376 -102
- package/src/render-system-projections.ts +241 -0
- package/src/render-system.ts +692 -791
- package/src/scene/render-scene-types.ts +13 -4
- package/src/scene/render-scene.ts +569 -355
- package/src/scene/shadow-visibility.ts +21 -0
- package/src/ssr/admission.ts +380 -14
- package/src/ssr/compose.ts +144 -0
- package/src/ssr/errors.ts +48 -0
- package/src/ssr/graph.ts +777 -0
- package/src/ssr/history.ts +436 -0
- package/src/ssr/hiz.ts +124 -0
- package/src/ssr/inspection.ts +124 -0
- package/src/ssr/resources.ts +202 -0
- package/src/ssr/temporal.ts +164 -0
- package/src/systems/skin-palette-allocator.ts +495 -148
- package/src/systems/skin-palette-types.ts +17 -0
- package/src/systems/transparent-dispatch.ts +90 -0
- package/src/targets/material-source.ts +34 -0
- package/src/temporal/coverage.ts +1 -1
- package/src/temporal/frame-coordinator.ts +23 -2
- package/src/temporal/gpu.ts +74 -12
- package/src/temporal/history.ts +3 -1
- package/src/temporal/inspection.ts +2 -1
- package/src/temporal/standard-scene-data.ts +3 -1
- package/src/temporal/temporal-view.ts +3 -0
- package/src/transmission/__tests__/standard-transmission.dawn.test.ts +204 -139
- package/src/typed-render-graph-primitives.ts +266 -74
- package/src/typed-shadow-passes.ts +122 -12
- package/src/volume/temporal.ts +10 -0
- package/dist/chunk-ADHHVYLW.mjs.map +0 -1
- package/dist/chunk-FJ6P52EE.mjs.map +0 -1
- package/dist/chunk-GE3SDD72.mjs.map +0 -1
- package/dist/chunk-GF523LHF.mjs.map +0 -1
- package/dist/chunk-HKXTW355.mjs.map +0 -1
- package/dist/chunk-JDWARUOI.mjs.map +0 -1
- package/dist/chunk-KM2NOX2I.mjs.map +0 -1
- package/dist/chunk-TMIASV2N.mjs.map +0 -1
- package/dist/chunk-XDP6XE5V.mjs.map +0 -1
- package/dist/chunk-ZZ4YQ474.mjs.map +0 -1
- package/src/__tests__/instances-world-ownership.integration.test.ts +0 -62
- package/src/scene/__tests__/changed-block-summary.candidate.test.ts +0 -36
package/src/instances.ts
CHANGED
|
@@ -1,25 +1,47 @@
|
|
|
1
|
-
import type { World } from '@forgeax/engine-ecs';
|
|
2
1
|
import type { RhiErrorCode } from '@forgeax/engine-rhi';
|
|
2
|
+
import { err, ok, type Result } from '@forgeax/engine-types';
|
|
3
3
|
|
|
4
4
|
const MATRIX_STRIDE = 16;
|
|
5
|
+
const INITIAL_CAPACITY = 1;
|
|
5
6
|
|
|
6
7
|
export type InstanceCollectionId = number & {
|
|
7
8
|
readonly __forgeaxInstanceCollectionId: unique symbol;
|
|
8
9
|
};
|
|
9
10
|
|
|
10
|
-
export interface
|
|
11
|
+
export interface InstanceCollectionData {
|
|
11
12
|
readonly collectionId: InstanceCollectionId;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface InstanceCollectionInfo extends InstanceCollectionData {
|
|
12
16
|
readonly count: number;
|
|
17
|
+
readonly capacity: number;
|
|
13
18
|
readonly revision: number;
|
|
14
19
|
}
|
|
15
20
|
|
|
16
|
-
export interface
|
|
21
|
+
export interface InstanceDirtyRange {
|
|
17
22
|
start: number;
|
|
18
23
|
end: number;
|
|
19
24
|
}
|
|
20
25
|
|
|
26
|
+
/**
|
|
27
|
+
* Choose the ranges that initialize one resident GPU allocation.
|
|
28
|
+
*
|
|
29
|
+
* A cache miss is not a delta upload: recovery, reassociation, and any other
|
|
30
|
+
* new resident has uninitialized device memory. The canonical collection must
|
|
31
|
+
* therefore be copied in full even when the current authoring revision only
|
|
32
|
+
* records a partial dirty range. Existing residents keep the narrower ranges.
|
|
33
|
+
*/
|
|
34
|
+
export function instanceUploadRangesForResident(
|
|
35
|
+
activeIsNew: boolean,
|
|
36
|
+
dirtyRanges: readonly InstanceDirtyRange[],
|
|
37
|
+
fullRange: InstanceDirtyRange,
|
|
38
|
+
): readonly InstanceDirtyRange[] {
|
|
39
|
+
return activeIsNew ? [fullRange] : dirtyRanges;
|
|
40
|
+
}
|
|
41
|
+
|
|
21
42
|
export interface InstanceCollectionSnapshot extends InstanceCollectionInfo {
|
|
22
43
|
readonly transforms: Float32Array;
|
|
44
|
+
readonly dirtyRanges: readonly InstanceDirtyRange[];
|
|
23
45
|
}
|
|
24
46
|
|
|
25
47
|
/** The renderer-owned submission lane selected for one collection. */
|
|
@@ -47,11 +69,29 @@ export interface InstanceCollectionFailureFacts {
|
|
|
47
69
|
readonly recovery: string;
|
|
48
70
|
}
|
|
49
71
|
|
|
72
|
+
function instanceCollectionFailureFacts(
|
|
73
|
+
cause: string,
|
|
74
|
+
recovery: string,
|
|
75
|
+
requestedBytes = 0,
|
|
76
|
+
supportedBytes: number | undefined = undefined,
|
|
77
|
+
backend: InstanceBackendKind = 'unknown',
|
|
78
|
+
): InstanceCollectionFailureFacts {
|
|
79
|
+
return {
|
|
80
|
+
requestedBytes,
|
|
81
|
+
supportedBytes,
|
|
82
|
+
backend,
|
|
83
|
+
owner: 'renderer.instances',
|
|
84
|
+
cause,
|
|
85
|
+
recovery,
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
|
|
50
89
|
/** Detached, bounded collection evidence exposed by Renderer.inspect(). */
|
|
51
90
|
export interface InstanceCollectionInspection extends InstanceCollectionInfo {
|
|
52
91
|
readonly residentGeneration: number | undefined;
|
|
53
92
|
readonly lane: InstanceSubmissionLane;
|
|
54
|
-
readonly
|
|
93
|
+
readonly dirtyRanges: readonly InstanceDirtyRange[];
|
|
94
|
+
readonly uploadRanges: readonly InstanceDirtyRange[];
|
|
55
95
|
readonly uploadedBytes: number;
|
|
56
96
|
readonly requestedBytes: number;
|
|
57
97
|
readonly supportedBytes: number | undefined;
|
|
@@ -67,11 +107,85 @@ export interface InstanceCollectionInspection extends InstanceCollectionInfo {
|
|
|
67
107
|
| undefined;
|
|
68
108
|
}
|
|
69
109
|
|
|
70
|
-
export interface
|
|
110
|
+
export interface InstanceCollectionCreateInput {
|
|
111
|
+
readonly transforms: Float32Array;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
export interface InstanceCollectionUpdateInput {
|
|
115
|
+
/** Matrix ordinal of the first matrix to replace. */
|
|
116
|
+
readonly start: number;
|
|
117
|
+
readonly transforms: Float32Array;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export interface InstanceCollectionInvalidDetail {
|
|
121
|
+
readonly collectionId?: number;
|
|
122
|
+
readonly operation: 'create' | 'replace' | 'update' | 'inspect' | 'release';
|
|
123
|
+
readonly expected: string;
|
|
124
|
+
readonly actual: number | string;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
export type InstanceCollectionErrorCode =
|
|
128
|
+
| 'instance-collection-invalid'
|
|
129
|
+
| 'instance-collection-not-found'
|
|
130
|
+
| 'instance-collection-released';
|
|
131
|
+
|
|
132
|
+
export class InstanceCollectionError extends Error {
|
|
133
|
+
readonly code: InstanceCollectionErrorCode;
|
|
134
|
+
readonly expected: string;
|
|
135
|
+
readonly hint: string;
|
|
136
|
+
readonly detail: InstanceCollectionInvalidDetail | undefined;
|
|
137
|
+
readonly owner = 'renderer.instances' as const;
|
|
138
|
+
readonly recovery: string;
|
|
139
|
+
readonly facts: InstanceCollectionFailureFacts;
|
|
140
|
+
|
|
141
|
+
constructor(
|
|
142
|
+
code: InstanceCollectionErrorCode,
|
|
143
|
+
expected: string,
|
|
144
|
+
hint: string,
|
|
145
|
+
detail?: InstanceCollectionInvalidDetail,
|
|
146
|
+
facts?: InstanceCollectionFailureFacts,
|
|
147
|
+
) {
|
|
148
|
+
super(`${code}: ${expected}`);
|
|
149
|
+
this.name = 'InstanceCollectionError';
|
|
150
|
+
this.code = code;
|
|
151
|
+
this.expected = expected;
|
|
152
|
+
this.hint = hint;
|
|
153
|
+
this.detail = detail;
|
|
154
|
+
this.facts =
|
|
155
|
+
facts ??
|
|
156
|
+
instanceCollectionFailureFacts(
|
|
157
|
+
code,
|
|
158
|
+
hint,
|
|
159
|
+
detail?.operation === 'create' || detail?.operation === 'replace'
|
|
160
|
+
? typeof detail.actual === 'number' && Number.isFinite(detail.actual)
|
|
161
|
+
? detail.actual * Float32Array.BYTES_PER_ELEMENT
|
|
162
|
+
: 0
|
|
163
|
+
: 0,
|
|
164
|
+
);
|
|
165
|
+
this.recovery = this.facts.recovery;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
export type InstanceCollectionResult<T> = Result<T, InstanceCollectionError>;
|
|
170
|
+
|
|
171
|
+
interface CollectionRecord {
|
|
172
|
+
readonly id: InstanceCollectionId;
|
|
173
|
+
transforms: Float32Array;
|
|
174
|
+
count: number;
|
|
175
|
+
capacity: number;
|
|
176
|
+
revision: number;
|
|
177
|
+
dirtyRanges: InstanceDirtyRange[];
|
|
178
|
+
/** Last revision detached for extraction; repeated reads of that revision
|
|
179
|
+
* retain the same ranges for multiple entities sharing one collection. */
|
|
180
|
+
lastSnapshotRevision: number;
|
|
181
|
+
released: boolean;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
interface CollectionResidency {
|
|
71
185
|
readonly frameNumber: number;
|
|
72
186
|
readonly residentGeneration: number | undefined;
|
|
73
187
|
readonly lane: InstanceSubmissionLane;
|
|
74
|
-
readonly uploadRanges: readonly
|
|
188
|
+
readonly uploadRanges: readonly InstanceDirtyRange[];
|
|
75
189
|
readonly uploadedBytes: number;
|
|
76
190
|
readonly requestedBytes: number;
|
|
77
191
|
readonly supportedBytes: number | undefined;
|
|
@@ -79,7 +193,73 @@ export interface InstanceResidency {
|
|
|
79
193
|
readonly error: InstanceCollectionInspection['error'];
|
|
80
194
|
}
|
|
81
195
|
|
|
82
|
-
function
|
|
196
|
+
function nextCapacity(required: number): number {
|
|
197
|
+
let capacity = INITIAL_CAPACITY;
|
|
198
|
+
while (capacity < required) capacity *= 2;
|
|
199
|
+
return capacity;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
function invalid(
|
|
203
|
+
operation: InstanceCollectionInvalidDetail['operation'],
|
|
204
|
+
expected: string,
|
|
205
|
+
actual: number | string,
|
|
206
|
+
collectionId?: number,
|
|
207
|
+
context?: {
|
|
208
|
+
readonly requestedBytes?: number;
|
|
209
|
+
readonly supportedBytes?: number;
|
|
210
|
+
readonly cause?: string;
|
|
211
|
+
readonly recovery?: string;
|
|
212
|
+
},
|
|
213
|
+
): InstanceCollectionError {
|
|
214
|
+
const hint = 'repair the collection payload and retry the same authoring operation';
|
|
215
|
+
return new InstanceCollectionError(
|
|
216
|
+
'instance-collection-invalid',
|
|
217
|
+
expected,
|
|
218
|
+
hint,
|
|
219
|
+
{ operation, expected, actual, ...(collectionId === undefined ? {} : { collectionId }) },
|
|
220
|
+
instanceCollectionFailureFacts(
|
|
221
|
+
context?.cause ?? `invalid-${operation}-authoring`,
|
|
222
|
+
context?.recovery ?? hint,
|
|
223
|
+
context?.requestedBytes ?? 0,
|
|
224
|
+
context?.supportedBytes,
|
|
225
|
+
),
|
|
226
|
+
);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
function validateTransforms(
|
|
230
|
+
operation: InstanceCollectionInvalidDetail['operation'],
|
|
231
|
+
transforms: Float32Array,
|
|
232
|
+
collectionId?: number,
|
|
233
|
+
): InstanceCollectionError | undefined {
|
|
234
|
+
if (!(transforms instanceof Float32Array)) {
|
|
235
|
+
return invalid(operation, 'transforms is a Float32Array', typeof transforms, collectionId, {
|
|
236
|
+
cause: 'invalid-transform-type',
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
if (transforms.length % MATRIX_STRIDE !== 0) {
|
|
240
|
+
return invalid(
|
|
241
|
+
operation,
|
|
242
|
+
`transforms.length is a multiple of ${MATRIX_STRIDE}`,
|
|
243
|
+
transforms.length,
|
|
244
|
+
collectionId,
|
|
245
|
+
{
|
|
246
|
+
requestedBytes: transforms.byteLength,
|
|
247
|
+
cause: 'invalid-transform-stride',
|
|
248
|
+
},
|
|
249
|
+
);
|
|
250
|
+
}
|
|
251
|
+
for (const value of transforms) {
|
|
252
|
+
if (!Number.isFinite(value)) {
|
|
253
|
+
return invalid(operation, 'every transform value is finite', value, collectionId, {
|
|
254
|
+
requestedBytes: transforms.byteLength,
|
|
255
|
+
cause: 'invalid-transform-value',
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
return undefined;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
function appendRange(ranges: InstanceDirtyRange[], start: number, end: number): void {
|
|
83
263
|
if (start >= end) return;
|
|
84
264
|
// Updates are allowed to arrive in any order. Insert at the first range
|
|
85
265
|
// whose end reaches the new interval, then consume every range that starts
|
|
@@ -101,112 +281,312 @@ function appendRange(ranges: InstanceUploadRange[], start: number, end: number):
|
|
|
101
281
|
ranges.splice(index, 0, { start, end });
|
|
102
282
|
}
|
|
103
283
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
284
|
+
function appendDirtyRange(record: CollectionRecord, start: number, end: number): void {
|
|
285
|
+
appendRange(record.dirtyRanges, start, end);
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
function missing(
|
|
289
|
+
operation: InstanceCollectionInvalidDetail['operation'],
|
|
290
|
+
id: InstanceCollectionId,
|
|
291
|
+
): InstanceCollectionError {
|
|
292
|
+
return new InstanceCollectionError(
|
|
293
|
+
'instance-collection-not-found',
|
|
294
|
+
`instance collection ${Number(id)} is live and owned by this Renderer`,
|
|
295
|
+
'create a collection with renderer.instances.create or retain the original collection id',
|
|
296
|
+
{ operation, expected: 'a live instance collection id', actual: Number(id), collectionId: id },
|
|
297
|
+
);
|
|
108
298
|
}
|
|
109
299
|
|
|
110
|
-
/**
|
|
111
|
-
|
|
300
|
+
/**
|
|
301
|
+
* Renderer-owned canonical storage for explicit instance transforms.
|
|
302
|
+
*
|
|
303
|
+
* ECS carries only `Instances.collectionId`; this owner keeps the copied
|
|
304
|
+
* matrices, revision and dirty intervals independent of archetype capacity.
|
|
305
|
+
* Snapshots are detached before they cross into extraction, so callers cannot
|
|
306
|
+
* mutate the canonical source behind the revision protocol.
|
|
307
|
+
*/
|
|
308
|
+
export class InstanceCollectionStore {
|
|
112
309
|
private nextId = 1;
|
|
113
|
-
private
|
|
310
|
+
private epochValue = 0;
|
|
311
|
+
private disposed = false;
|
|
114
312
|
private readonly records = new Map<InstanceCollectionId, CollectionRecord>();
|
|
313
|
+
private readonly residency = new Map<InstanceCollectionId, CollectionResidency>();
|
|
115
314
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
if (entities === undefined) {
|
|
119
|
-
entities = new Map();
|
|
120
|
-
this.identities.set(world, entities);
|
|
121
|
-
}
|
|
122
|
-
let collectionId = entities.get(entity);
|
|
123
|
-
if (collectionId === undefined) {
|
|
124
|
-
collectionId = this.nextId++ as InstanceCollectionId;
|
|
125
|
-
entities.set(entity, collectionId);
|
|
126
|
-
}
|
|
127
|
-
const previous = this.records.get(collectionId);
|
|
128
|
-
const unchanged =
|
|
129
|
-
previous !== undefined &&
|
|
130
|
-
previous.transforms.length === transforms.length &&
|
|
131
|
-
previous.transforms.every((value, index) => Object.is(value, transforms[index]));
|
|
132
|
-
const record: CollectionRecord = unchanged
|
|
133
|
-
? previous
|
|
134
|
-
: {
|
|
135
|
-
collectionId,
|
|
136
|
-
world,
|
|
137
|
-
entity,
|
|
138
|
-
transforms: new Float32Array(transforms),
|
|
139
|
-
count: transforms.length / MATRIX_STRIDE,
|
|
140
|
-
revision: (previous?.revision ?? 0) + 1,
|
|
141
|
-
};
|
|
142
|
-
this.records.set(collectionId, record);
|
|
143
|
-
// Every consumer gets a complete snapshot. Reading never acknowledges an
|
|
144
|
-
// upload; each GPU resident records its own successfully uploaded revision.
|
|
145
|
-
return { ...this.info(record), transforms: record.transforms };
|
|
315
|
+
get epoch(): number {
|
|
316
|
+
return this.epochValue;
|
|
146
317
|
}
|
|
147
318
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
319
|
+
create(input: InstanceCollectionCreateInput): InstanceCollectionResult<InstanceCollectionInfo> {
|
|
320
|
+
if (this.disposed) {
|
|
321
|
+
return err(
|
|
322
|
+
new InstanceCollectionError(
|
|
323
|
+
'instance-collection-released',
|
|
324
|
+
'the Renderer-owned instance collection store is live',
|
|
325
|
+
'create a new Renderer before authoring instance collections',
|
|
326
|
+
),
|
|
327
|
+
);
|
|
153
328
|
}
|
|
329
|
+
const invalidPayload = validateTransforms('create', input.transforms);
|
|
330
|
+
if (invalidPayload !== undefined) return err(invalidPayload);
|
|
331
|
+
const id = this.nextId++ as InstanceCollectionId;
|
|
332
|
+
const count = input.transforms.length / MATRIX_STRIDE;
|
|
333
|
+
const record: CollectionRecord = {
|
|
334
|
+
id,
|
|
335
|
+
transforms: new Float32Array(input.transforms),
|
|
336
|
+
count,
|
|
337
|
+
capacity: nextCapacity(Math.max(INITIAL_CAPACITY, count)),
|
|
338
|
+
revision: 1,
|
|
339
|
+
dirtyRanges: count === 0 ? [] : [{ start: 0, end: count }],
|
|
340
|
+
lastSnapshotRevision: 0,
|
|
341
|
+
released: false,
|
|
342
|
+
};
|
|
343
|
+
this.records.set(id, record);
|
|
344
|
+
this.epochValue += 1;
|
|
345
|
+
return ok(this.info(record));
|
|
154
346
|
}
|
|
155
347
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
348
|
+
replace(
|
|
349
|
+
id: InstanceCollectionId,
|
|
350
|
+
transforms: Float32Array,
|
|
351
|
+
): InstanceCollectionResult<InstanceCollectionInfo> {
|
|
352
|
+
const record = this.live('replace', id);
|
|
353
|
+
if (!record.ok) return record;
|
|
354
|
+
const invalidPayload = validateTransforms('replace', transforms, id);
|
|
355
|
+
if (invalidPayload !== undefined) return err(invalidPayload);
|
|
356
|
+
const count = transforms.length / MATRIX_STRIDE;
|
|
357
|
+
record.value.transforms = new Float32Array(transforms);
|
|
358
|
+
record.value.count = count;
|
|
359
|
+
record.value.capacity = Math.max(record.value.capacity, nextCapacity(Math.max(1, count)));
|
|
360
|
+
record.value.revision += 1;
|
|
361
|
+
record.value.dirtyRanges = count === 0 ? [] : [{ start: 0, end: count }];
|
|
362
|
+
record.value.lastSnapshotRevision = record.value.revision - 1;
|
|
363
|
+
this.epochValue += 1;
|
|
364
|
+
return ok(this.info(record.value));
|
|
163
365
|
}
|
|
164
366
|
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
367
|
+
update(
|
|
368
|
+
id: InstanceCollectionId,
|
|
369
|
+
input: InstanceCollectionUpdateInput,
|
|
370
|
+
): InstanceCollectionResult<InstanceCollectionInfo> {
|
|
371
|
+
const record = this.live('update', id);
|
|
372
|
+
if (!record.ok) return record;
|
|
373
|
+
const invalidPayload = validateTransforms('update', input.transforms, id);
|
|
374
|
+
if (invalidPayload !== undefined) return err(invalidPayload);
|
|
375
|
+
if (!Number.isInteger(input.start) || input.start < 0) {
|
|
376
|
+
return err(
|
|
377
|
+
invalid('update', 'start is a non-negative matrix ordinal', input.start, id, {
|
|
378
|
+
requestedBytes: input.transforms.byteLength,
|
|
379
|
+
supportedBytes: record.value.capacity * MATRIX_STRIDE * Float32Array.BYTES_PER_ELEMENT,
|
|
380
|
+
cause: 'invalid-update-range-start',
|
|
381
|
+
}),
|
|
382
|
+
);
|
|
383
|
+
}
|
|
384
|
+
const span = input.transforms.length / MATRIX_STRIDE;
|
|
385
|
+
const attemptedEnd = input.start + span;
|
|
386
|
+
if (attemptedEnd > record.value.count) {
|
|
387
|
+
return err(
|
|
388
|
+
invalid(
|
|
389
|
+
'update',
|
|
390
|
+
`start + matrix count is <= collection count (${record.value.count})`,
|
|
391
|
+
attemptedEnd,
|
|
392
|
+
id,
|
|
393
|
+
{
|
|
394
|
+
requestedBytes: attemptedEnd * MATRIX_STRIDE * Float32Array.BYTES_PER_ELEMENT,
|
|
395
|
+
supportedBytes: record.value.count * MATRIX_STRIDE * Float32Array.BYTES_PER_ELEMENT,
|
|
396
|
+
cause: 'invalid-update-range-end',
|
|
397
|
+
},
|
|
398
|
+
),
|
|
399
|
+
);
|
|
400
|
+
}
|
|
401
|
+
if (record.value.lastSnapshotRevision === record.value.revision) {
|
|
402
|
+
record.value.dirtyRanges = [];
|
|
403
|
+
}
|
|
404
|
+
record.value.transforms.set(input.transforms, input.start * MATRIX_STRIDE);
|
|
405
|
+
record.value.revision += 1;
|
|
406
|
+
appendDirtyRange(record.value, input.start, input.start + span);
|
|
407
|
+
this.epochValue += 1;
|
|
408
|
+
return ok(this.info(record.value));
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
inspect(id: InstanceCollectionId): InstanceCollectionResult<InstanceCollectionInfo> {
|
|
412
|
+
const record = this.live('inspect', id);
|
|
413
|
+
return record.ok ? ok(this.info(record.value)) : record;
|
|
168
414
|
}
|
|
169
415
|
|
|
170
416
|
/**
|
|
171
417
|
* Return detached residency facts for every live collection.
|
|
172
418
|
*
|
|
173
|
-
* @internal
|
|
419
|
+
* @internal Record-stage evidence is reported through the two methods below;
|
|
174
420
|
* callers only receive immutable PODs and never GPU handles.
|
|
175
421
|
*/
|
|
176
|
-
_inspections(
|
|
177
|
-
residency: ReadonlyMap<InstanceCollectionId, InstanceResidency> | undefined,
|
|
178
|
-
frameNumber: number,
|
|
179
|
-
): readonly InstanceCollectionInspection[] {
|
|
422
|
+
_inspections(): readonly InstanceCollectionInspection[] {
|
|
180
423
|
return Object.freeze(
|
|
181
|
-
[...this.records.values()].map((record) =>
|
|
182
|
-
this.projectInspection(record, residency?.get(record.collectionId), frameNumber),
|
|
183
|
-
),
|
|
424
|
+
[...this.records.values()].map((record) => this.projectInspection(record)),
|
|
184
425
|
);
|
|
185
426
|
}
|
|
186
427
|
|
|
428
|
+
/** @internal Renderer record owner reports the accepted collection lane. */
|
|
429
|
+
_reportResidency(input: {
|
|
430
|
+
readonly collectionId: InstanceCollectionId;
|
|
431
|
+
readonly frameNumber: number;
|
|
432
|
+
readonly residentGeneration: number;
|
|
433
|
+
readonly lane: Exclude<InstanceSubmissionLane, 'unresident' | 'unavailable'>;
|
|
434
|
+
readonly uploadRanges: readonly InstanceDirtyRange[];
|
|
435
|
+
readonly uploadedBytes: number;
|
|
436
|
+
readonly requestedBytes: number;
|
|
437
|
+
readonly supportedBytes: number | undefined;
|
|
438
|
+
readonly backend: InstanceBackendKind;
|
|
439
|
+
}): void {
|
|
440
|
+
if (!this.records.has(input.collectionId)) return;
|
|
441
|
+
const previous = this.residency.get(input.collectionId);
|
|
442
|
+
const sameFrame =
|
|
443
|
+
previous !== undefined &&
|
|
444
|
+
previous.frameNumber === input.frameNumber &&
|
|
445
|
+
previous.error === undefined;
|
|
446
|
+
const uploadRanges = sameFrame
|
|
447
|
+
? [...previous.uploadRanges].reduce(
|
|
448
|
+
(ranges, range) => {
|
|
449
|
+
appendRange(ranges, range.start, range.end);
|
|
450
|
+
return ranges;
|
|
451
|
+
},
|
|
452
|
+
input.uploadRanges.map((range) => ({ ...range })),
|
|
453
|
+
)
|
|
454
|
+
: input.uploadRanges.map((range) => ({ ...range }));
|
|
455
|
+
this.residency.set(input.collectionId, {
|
|
456
|
+
frameNumber: input.frameNumber,
|
|
457
|
+
residentGeneration: input.residentGeneration,
|
|
458
|
+
lane: input.lane,
|
|
459
|
+
uploadRanges,
|
|
460
|
+
uploadedBytes: sameFrame ? previous.uploadedBytes + input.uploadedBytes : input.uploadedBytes,
|
|
461
|
+
requestedBytes: input.requestedBytes,
|
|
462
|
+
supportedBytes: input.supportedBytes,
|
|
463
|
+
backend: input.backend,
|
|
464
|
+
error: undefined,
|
|
465
|
+
});
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
/** @internal Renderer record owner reports a typed admission failure. */
|
|
469
|
+
_reportFailure(input: {
|
|
470
|
+
readonly collectionId: InstanceCollectionId;
|
|
471
|
+
readonly code: InstanceCollectionFailureCode;
|
|
472
|
+
readonly expected: string;
|
|
473
|
+
readonly hint: string;
|
|
474
|
+
readonly facts: InstanceCollectionFailureFacts;
|
|
475
|
+
}): void {
|
|
476
|
+
if (!this.records.has(input.collectionId)) return;
|
|
477
|
+
this.residency.set(input.collectionId, {
|
|
478
|
+
frameNumber: -1,
|
|
479
|
+
residentGeneration: undefined,
|
|
480
|
+
lane: 'unavailable',
|
|
481
|
+
uploadRanges: [],
|
|
482
|
+
uploadedBytes: 0,
|
|
483
|
+
requestedBytes: input.facts.requestedBytes,
|
|
484
|
+
supportedBytes: input.facts.supportedBytes,
|
|
485
|
+
backend: input.facts.backend,
|
|
486
|
+
error: {
|
|
487
|
+
code: input.code,
|
|
488
|
+
expected: input.expected,
|
|
489
|
+
hint: input.hint,
|
|
490
|
+
detail: { ...input.facts },
|
|
491
|
+
},
|
|
492
|
+
});
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
/** @internal A lost device invalidates every renderer-owned GPU resident. */
|
|
496
|
+
_resetResidency(): void {
|
|
497
|
+
this.residency.clear();
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
snapshot(id: InstanceCollectionId): InstanceCollectionResult<InstanceCollectionSnapshot> {
|
|
501
|
+
const record = this.live('inspect', id);
|
|
502
|
+
if (!record.ok) return record;
|
|
503
|
+
const value = record.value;
|
|
504
|
+
value.lastSnapshotRevision = value.revision;
|
|
505
|
+
const result = {
|
|
506
|
+
...this.info(value),
|
|
507
|
+
transforms: new Float32Array(value.transforms),
|
|
508
|
+
dirtyRanges: value.dirtyRanges.map((range) => ({ ...range })),
|
|
509
|
+
};
|
|
510
|
+
// Keep the current ranges stable for repeated reads by entities sharing
|
|
511
|
+
// this collection. The next authoring mutation starts a fresh interval
|
|
512
|
+
// set once this revision has been observed.
|
|
513
|
+
return ok(result);
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
release(id: InstanceCollectionId): InstanceCollectionResult<void> {
|
|
517
|
+
const record = this.records.get(id);
|
|
518
|
+
if (record === undefined) return err(missing('release', id));
|
|
519
|
+
if (record.released) {
|
|
520
|
+
return err(
|
|
521
|
+
new InstanceCollectionError(
|
|
522
|
+
'instance-collection-released',
|
|
523
|
+
`instance collection ${Number(id)} has not already been released`,
|
|
524
|
+
'do not reuse a released collection id; create a new collection',
|
|
525
|
+
{
|
|
526
|
+
operation: 'release',
|
|
527
|
+
expected: 'a live instance collection id',
|
|
528
|
+
actual: Number(id),
|
|
529
|
+
collectionId: id,
|
|
530
|
+
},
|
|
531
|
+
),
|
|
532
|
+
);
|
|
533
|
+
}
|
|
534
|
+
record.released = true;
|
|
535
|
+
this.records.delete(id);
|
|
536
|
+
this.residency.delete(id);
|
|
537
|
+
this.epochValue += 1;
|
|
538
|
+
return ok(undefined);
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
/** Drop all canonical matrices during Renderer disposal. */
|
|
542
|
+
dispose(): void {
|
|
543
|
+
if (this.disposed) return;
|
|
544
|
+
this.disposed = true;
|
|
545
|
+
for (const record of this.records.values()) record.released = true;
|
|
546
|
+
this.records.clear();
|
|
547
|
+
this.residency.clear();
|
|
548
|
+
this.epochValue += 1;
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
private live(
|
|
552
|
+
operation: InstanceCollectionInvalidDetail['operation'],
|
|
553
|
+
id: InstanceCollectionId,
|
|
554
|
+
): InstanceCollectionResult<CollectionRecord> {
|
|
555
|
+
if (!Number.isInteger(id) || id <= 0) {
|
|
556
|
+
return err(invalid(operation, 'collectionId is a positive integer', id, id));
|
|
557
|
+
}
|
|
558
|
+
if (this.disposed) {
|
|
559
|
+
return err(
|
|
560
|
+
new InstanceCollectionError(
|
|
561
|
+
'instance-collection-released',
|
|
562
|
+
'the Renderer-owned instance collection store is live',
|
|
563
|
+
'create a new Renderer before using instance collections',
|
|
564
|
+
{ operation, expected: 'a live collection store', actual: 'disposed', collectionId: id },
|
|
565
|
+
),
|
|
566
|
+
);
|
|
567
|
+
}
|
|
568
|
+
const record = this.records.get(id);
|
|
569
|
+
return record === undefined ? err(missing(operation, id)) : ok(record);
|
|
570
|
+
}
|
|
571
|
+
|
|
187
572
|
private info(record: CollectionRecord): InstanceCollectionInfo {
|
|
188
573
|
return Object.freeze({
|
|
189
|
-
collectionId: record.
|
|
574
|
+
collectionId: record.id,
|
|
190
575
|
count: record.count,
|
|
576
|
+
capacity: record.capacity,
|
|
191
577
|
revision: record.revision,
|
|
192
578
|
});
|
|
193
579
|
}
|
|
194
580
|
|
|
195
|
-
private projectInspection(
|
|
196
|
-
record
|
|
197
|
-
residency: InstanceResidency | undefined,
|
|
198
|
-
frameNumber: number,
|
|
199
|
-
): InstanceCollectionInspection {
|
|
581
|
+
private projectInspection(record: CollectionRecord): InstanceCollectionInspection {
|
|
582
|
+
const residency = this.residency.get(record.id);
|
|
200
583
|
return Object.freeze({
|
|
201
584
|
...this.info(record),
|
|
202
585
|
residentGeneration: residency?.residentGeneration,
|
|
203
586
|
lane: residency?.lane ?? 'unresident',
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
: [],
|
|
208
|
-
),
|
|
209
|
-
uploadedBytes: residency?.frameNumber === frameNumber ? residency.uploadedBytes : 0,
|
|
587
|
+
dirtyRanges: Object.freeze(record.dirtyRanges.map((range) => ({ ...range }))),
|
|
588
|
+
uploadRanges: Object.freeze(residency?.uploadRanges.map((range) => ({ ...range })) ?? []),
|
|
589
|
+
uploadedBytes: residency?.uploadedBytes ?? 0,
|
|
210
590
|
requestedBytes: residency?.requestedBytes ?? record.count * MATRIX_STRIDE * 4,
|
|
211
591
|
supportedBytes: residency?.supportedBytes,
|
|
212
592
|
backend: residency?.backend ?? 'unknown',
|
|
@@ -215,74 +595,3 @@ export class InstanceProjectionStore {
|
|
|
215
595
|
});
|
|
216
596
|
}
|
|
217
597
|
}
|
|
218
|
-
|
|
219
|
-
/** @internal Renderer record owner reports the accepted collection lane. */
|
|
220
|
-
export function recordInstanceResidency(
|
|
221
|
-
residency: Map<InstanceCollectionId, InstanceResidency>,
|
|
222
|
-
input: {
|
|
223
|
-
readonly collectionId: InstanceCollectionId;
|
|
224
|
-
readonly frameNumber: number;
|
|
225
|
-
readonly residentGeneration: number;
|
|
226
|
-
readonly lane: Exclude<InstanceSubmissionLane, 'unresident' | 'unavailable'>;
|
|
227
|
-
readonly uploadRanges: readonly InstanceUploadRange[];
|
|
228
|
-
readonly uploadedBytes: number;
|
|
229
|
-
readonly requestedBytes: number;
|
|
230
|
-
readonly supportedBytes: number | undefined;
|
|
231
|
-
readonly backend: InstanceBackendKind;
|
|
232
|
-
},
|
|
233
|
-
): void {
|
|
234
|
-
const previous = residency.get(input.collectionId);
|
|
235
|
-
const sameFrame =
|
|
236
|
-
previous !== undefined &&
|
|
237
|
-
previous.frameNumber === input.frameNumber &&
|
|
238
|
-
previous.error === undefined;
|
|
239
|
-
const uploadRanges = sameFrame
|
|
240
|
-
? [...previous.uploadRanges].reduce(
|
|
241
|
-
(ranges, range) => {
|
|
242
|
-
appendRange(ranges, range.start, range.end);
|
|
243
|
-
return ranges;
|
|
244
|
-
},
|
|
245
|
-
input.uploadRanges.map((range) => ({ ...range })),
|
|
246
|
-
)
|
|
247
|
-
: input.uploadRanges.map((range) => ({ ...range }));
|
|
248
|
-
residency.set(input.collectionId, {
|
|
249
|
-
frameNumber: input.frameNumber,
|
|
250
|
-
residentGeneration: input.residentGeneration,
|
|
251
|
-
lane: input.lane,
|
|
252
|
-
uploadRanges,
|
|
253
|
-
uploadedBytes: sameFrame ? previous.uploadedBytes + input.uploadedBytes : input.uploadedBytes,
|
|
254
|
-
requestedBytes: input.requestedBytes,
|
|
255
|
-
supportedBytes: input.supportedBytes,
|
|
256
|
-
backend: input.backend,
|
|
257
|
-
error: undefined,
|
|
258
|
-
});
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
/** @internal Renderer record owner reports a typed admission failure. */
|
|
262
|
-
export function recordInstanceFailure(
|
|
263
|
-
residency: Map<InstanceCollectionId, InstanceResidency>,
|
|
264
|
-
input: {
|
|
265
|
-
readonly collectionId: InstanceCollectionId;
|
|
266
|
-
readonly code: InstanceCollectionFailureCode;
|
|
267
|
-
readonly expected: string;
|
|
268
|
-
readonly hint: string;
|
|
269
|
-
readonly facts: InstanceCollectionFailureFacts;
|
|
270
|
-
},
|
|
271
|
-
): void {
|
|
272
|
-
residency.set(input.collectionId, {
|
|
273
|
-
frameNumber: -1,
|
|
274
|
-
residentGeneration: undefined,
|
|
275
|
-
lane: 'unavailable',
|
|
276
|
-
uploadRanges: [],
|
|
277
|
-
uploadedBytes: 0,
|
|
278
|
-
requestedBytes: input.facts.requestedBytes,
|
|
279
|
-
supportedBytes: input.facts.supportedBytes,
|
|
280
|
-
backend: input.facts.backend,
|
|
281
|
-
error: {
|
|
282
|
-
code: input.code,
|
|
283
|
-
expected: input.expected,
|
|
284
|
-
hint: input.hint,
|
|
285
|
-
detail: { ...input.facts },
|
|
286
|
-
},
|
|
287
|
-
});
|
|
288
|
-
}
|