@forgeax/engine-render 0.1.33 → 0.1.34
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 +1010 -124
- package/dist/assembly/backend-contract.d.ts +2 -0
- package/dist/assembly/backend-contract.d.ts.map +1 -1
- package/dist/assembly/barrel-distortion-inspection.d.ts +3 -0
- package/dist/assembly/barrel-distortion-inspection.d.ts.map +1 -0
- package/dist/assembly/canvas-draw-guard.d.ts +3 -0
- package/dist/assembly/canvas-draw-guard.d.ts.map +1 -0
- package/dist/assembly/cloud-shadow-entry.d.ts +4 -0
- package/dist/assembly/cloud-shadow-entry.d.ts.map +1 -0
- package/dist/assembly/dynamic-geometry-host.d.ts +4 -1
- package/dist/assembly/dynamic-geometry-host.d.ts.map +1 -1
- package/dist/assembly/dynamic-geometry-runtime.d.ts +1 -1
- package/dist/assembly/dynamic-geometry-runtime.d.ts.map +1 -1
- package/dist/assembly/factory.d.ts +1 -1
- package/dist/assembly/factory.d.ts.map +1 -1
- package/dist/assembly/host-contract.d.ts +3 -3
- package/dist/assembly/host-contract.d.ts.map +1 -1
- package/dist/assembly/material/assembly.d.ts.map +1 -1
- package/dist/assembly/material/pipeline-helpers.d.ts +5 -0
- package/dist/assembly/material/pipeline-helpers.d.ts.map +1 -1
- package/dist/assembly/material-shader-policy.d.ts +16 -2
- package/dist/assembly/material-shader-policy.d.ts.map +1 -1
- package/dist/assembly/material-shader-prewarm.d.ts.map +1 -1
- package/dist/assembly/recovery/device-loss-fanout.d.ts.map +1 -1
- package/dist/assembly/recovery/renderer-recover.d.ts +2 -0
- package/dist/assembly/recovery/renderer-recover.d.ts.map +1 -1
- package/dist/assembly/render-feature-post-processes.d.ts +6 -0
- package/dist/assembly/render-feature-post-processes.d.ts.map +1 -0
- package/dist/assembly/renderer-facade.d.ts.map +1 -1
- package/dist/assembly/renderer-feature-inspection.d.ts +1 -1
- package/dist/assembly/renderer-feature-inspection.d.ts.map +1 -1
- package/dist/assembly/renderer-frame-transaction.d.ts +12 -0
- package/dist/assembly/renderer-frame-transaction.d.ts.map +1 -1
- package/dist/assembly/renderer-inspection.d.ts +11 -0
- package/dist/assembly/renderer-inspection.d.ts.map +1 -1
- package/dist/assembly/webgpu-pbr-ready.d.ts +1 -0
- package/dist/assembly/webgpu-pbr-ready.d.ts.map +1 -1
- package/dist/assembly/webgpu-ready-per-pass.d.ts +39 -0
- package/dist/assembly/webgpu-ready-per-pass.d.ts.map +1 -0
- package/dist/assembly/webgpu-ready.d.ts +1 -1
- package/dist/assembly/webgpu-ready.d.ts.map +1 -1
- package/dist/assembly/webgpu-renderer-bootstrap.d.ts.map +1 -1
- package/dist/assembly/webgpu-renderer-observation-owner.d.ts +35 -0
- package/dist/assembly/webgpu-renderer-observation-owner.d.ts.map +1 -0
- package/dist/assembly/webgpu-renderer.d.ts +1 -1
- package/dist/assembly/webgpu-renderer.d.ts.map +1 -1
- package/dist/authoring.mjs +1 -1
- package/dist/barrel-distortion.d.ts +47 -0
- package/dist/barrel-distortion.d.ts.map +1 -0
- package/dist/{chunk-PA5DRJNI.mjs → chunk-ELJFJ2BU.mjs} +2 -2
- package/dist/chunk-ELJFJ2BU.mjs.map +1 -0
- package/dist/{chunk-ZDQWGQW7.mjs → chunk-HEB564WF.mjs} +4 -4
- package/dist/{chunk-ZDQWGQW7.mjs.map → chunk-HEB564WF.mjs.map} +1 -1
- package/dist/{chunk-VOZWDM3L.mjs → chunk-MKDIT2EM.mjs} +1307 -188
- package/dist/chunk-MKDIT2EM.mjs.map +1 -0
- package/dist/{chunk-LEAXOMYJ.mjs → chunk-OCDLEI6I.mjs} +3 -3
- package/dist/{chunk-LEAXOMYJ.mjs.map → chunk-OCDLEI6I.mjs.map} +1 -1
- package/dist/chunk-ODZWR6JQ.mjs +4927 -0
- package/dist/chunk-ODZWR6JQ.mjs.map +1 -0
- package/dist/{chunk-3RTCJTH4.mjs → chunk-SHFUFJ5N.mjs} +184 -13
- package/dist/chunk-SHFUFJ5N.mjs.map +1 -0
- package/dist/{chunk-OO3DRYK7.mjs → chunk-UI5SFODX.mjs} +176 -96
- package/dist/chunk-UI5SFODX.mjs.map +1 -0
- package/dist/{chunk-PLAXOOX5.mjs → chunk-UINHLCZA.mjs} +561 -79
- package/dist/chunk-UINHLCZA.mjs.map +1 -0
- package/dist/{chunk-NB2S7ZRX.mjs → chunk-WEX45HKH.mjs} +127 -386
- package/dist/chunk-WEX45HKH.mjs.map +1 -0
- package/dist/cloud/density.d.ts +55 -0
- package/dist/cloud/density.d.ts.map +1 -0
- package/dist/cloud/extract.d.ts +25 -0
- package/dist/cloud/extract.d.ts.map +1 -0
- package/dist/cloud/feature.d.ts +57 -0
- package/dist/cloud/feature.d.ts.map +1 -0
- package/dist/cloud/frame-context.d.ts +8 -0
- package/dist/cloud/frame-context.d.ts.map +1 -0
- package/dist/cloud/inspection.d.ts +59 -0
- package/dist/cloud/inspection.d.ts.map +1 -0
- package/dist/cloud/optics.d.ts +56 -0
- package/dist/cloud/optics.d.ts.map +1 -0
- package/dist/cloud/parameters.d.ts +73 -0
- package/dist/cloud/parameters.d.ts.map +1 -0
- package/dist/cloud/resources.d.ts +60 -0
- package/dist/cloud/resources.d.ts.map +1 -0
- package/dist/cloud/shadow.d.ts +42 -0
- package/dist/cloud/shadow.d.ts.map +1 -0
- package/dist/cloud/temporal.d.ts +74 -0
- package/dist/cloud/temporal.d.ts.map +1 -0
- package/dist/components/barrel-distortion.d.ts +13 -0
- package/dist/components/barrel-distortion.d.ts.map +1 -0
- package/dist/components/cloud-layer.d.ts +29 -0
- package/dist/components/cloud-layer.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/instances.d.ts +20 -6
- package/dist/components/instances.d.ts.map +1 -1
- package/dist/construct-renderer.d.ts +1 -1
- package/dist/construct-renderer.d.ts.map +1 -1
- package/dist/construct-renderer.mjs +6759 -2875
- package/dist/construct-renderer.mjs.map +1 -1
- package/dist/dynamic-geometry.d.ts +5 -1
- package/dist/dynamic-geometry.d.ts.map +1 -1
- package/dist/errors/cloud.d.ts +59 -0
- package/dist/errors/cloud.d.ts.map +1 -0
- package/dist/errors/render.d.ts +18 -4
- package/dist/errors/render.d.ts.map +1 -1
- package/dist/examples/single-layer-medium-surface.d.ts +47 -0
- package/dist/examples/single-layer-medium-surface.d.ts.map +1 -0
- package/dist/extract/camera.d.ts.map +1 -1
- package/dist/extract/contracts.d.ts +5 -1
- package/dist/extract/contracts.d.ts.map +1 -1
- package/dist/features/barrel-distortion.d.ts +29 -0
- package/dist/features/barrel-distortion.d.ts.map +1 -0
- package/dist/features/error-reporting.d.ts +6 -2
- package/dist/features/error-reporting.d.ts.map +1 -1
- package/dist/features/host.d.ts +10 -0
- package/dist/features/host.d.ts.map +1 -1
- package/dist/features/plan.d.ts +8 -0
- package/dist/features/plan.d.ts.map +1 -1
- package/dist/features/render-graph-contribution.d.ts +5 -0
- package/dist/features/render-graph-contribution.d.ts.map +1 -1
- package/dist/features/render-graph-raster.d.ts +1 -0
- package/dist/features/render-graph-raster.d.ts.map +1 -1
- package/dist/features/targets.d.ts +2 -0
- package/dist/features/targets.d.ts.map +1 -1
- package/dist/features/types.d.ts +44 -0
- package/dist/features/types.d.ts.map +1 -1
- package/dist/fullscreen-post-process-pass.d.ts +15 -7
- package/dist/fullscreen-post-process-pass.d.ts.map +1 -1
- package/dist/gpu-dirty-ranges.d.ts +11 -0
- package/dist/gpu-dirty-ranges.d.ts.map +1 -0
- package/dist/gpu-driven/batch-topology.d.ts +17 -0
- package/dist/gpu-driven/batch-topology.d.ts.map +1 -1
- package/dist/gpu-driven/material-artifacts.d.ts +6 -0
- package/dist/gpu-driven/material-artifacts.d.ts.map +1 -1
- package/dist/gpu-driven/prepared-draw.d.ts.map +1 -1
- package/dist/gpu-driven/production-raster-material.d.ts +178 -0
- package/dist/gpu-driven/production-raster-material.d.ts.map +1 -0
- package/dist/gpu-driven/production-raster.d.ts +47 -3
- package/dist/gpu-driven/production-raster.d.ts.map +1 -1
- package/dist/gpu-driven/resource-allocation.d.ts +31 -0
- package/dist/gpu-driven/resource-allocation.d.ts.map +1 -0
- package/dist/gpu-driven/shadow-ownership.d.ts +14 -0
- package/dist/gpu-driven/shadow-ownership.d.ts.map +1 -0
- package/dist/gpu-driven/view-gpu.d.ts +26 -2
- package/dist/gpu-driven/view-gpu.d.ts.map +1 -1
- package/dist/gpu-scene.d.ts +5 -0
- package/dist/gpu-scene.d.ts.map +1 -1
- package/dist/hdrp-buffers.d.ts +2 -2
- package/dist/hdrp-buffers.d.ts.map +1 -1
- package/dist/ibl/skylight-bind-group.d.ts +10 -1
- package/dist/ibl/skylight-bind-group.d.ts.map +1 -1
- package/dist/index.d.ts +27 -7
- package/dist/index.d.ts.map +1 -1
- package/dist/index.mjs +258 -8
- package/dist/index.mjs.map +1 -1
- package/dist/inspection-types.d.ts +135 -1
- package/dist/inspection-types.d.ts.map +1 -1
- package/dist/instance-buffer-cache.d.ts +4 -4
- package/dist/instance-buffer-cache.d.ts.map +1 -1
- package/dist/instances.d.ts +48 -100
- package/dist/instances.d.ts.map +1 -1
- package/dist/internal.mjs +7 -7
- package/dist/pbr-pipeline.d.ts +19 -1
- package/dist/pbr-pipeline.d.ts.map +1 -1
- package/dist/pipeline/single-layer-medium-passes.d.ts +73 -0
- package/dist/pipeline/single-layer-medium-passes.d.ts.map +1 -0
- package/dist/pipeline/standard-forward-lane.d.ts.map +1 -1
- package/dist/pipeline/standard-output/graph.d.ts.map +1 -1
- package/dist/pipeline/standard-output/types.d.ts +4 -2
- package/dist/pipeline/standard-output/types.d.ts.map +1 -1
- package/dist/pipeline/standard-pipeline.d.ts.map +1 -1
- package/dist/pipeline/standard-post.d.ts.map +1 -1
- package/dist/pipeline-builder.d.ts +1 -1
- package/dist/pipeline-builder.d.ts.map +1 -1
- package/dist/plugin.d.ts.map +1 -1
- package/dist/prepare/prepared-graphics-resolver.d.ts +2 -0
- package/dist/prepare/prepared-graphics-resolver.d.ts.map +1 -1
- package/dist/record/barrel-distortion-frame.d.ts +15 -0
- package/dist/record/barrel-distortion-frame.d.ts.map +1 -0
- package/dist/record/dynamic-geometry-consumption.d.ts +10 -2
- package/dist/record/dynamic-geometry-consumption.d.ts.map +1 -1
- package/dist/record/fold-buckets.d.ts +95 -0
- package/dist/record/fold-buckets.d.ts.map +1 -0
- package/dist/record/fold-instance-buffer.d.ts +6 -0
- package/dist/record/fold-instance-buffer.d.ts.map +1 -0
- package/dist/record/frame-lighting.d.ts +1 -0
- package/dist/record/frame-lighting.d.ts.map +1 -1
- package/dist/record/frame-snapshot.d.ts +37 -3
- package/dist/record/frame-snapshot.d.ts.map +1 -1
- package/dist/record/frame.d.ts +10 -61
- package/dist/record/frame.d.ts.map +1 -1
- package/dist/record/gpu-draw-receipts.d.ts +11 -0
- package/dist/record/gpu-draw-receipts.d.ts.map +1 -0
- package/dist/record/gpu-timing.d.ts +8 -0
- package/dist/record/gpu-timing.d.ts.map +1 -1
- package/dist/record/main-pass-geometry.d.ts +21 -5
- package/dist/record/main-pass-geometry.d.ts.map +1 -1
- package/dist/record/main-pass-material.d.ts +7 -1
- package/dist/record/main-pass-material.d.ts.map +1 -1
- package/dist/record/main-pass-sprite-draws.d.ts.map +1 -1
- package/dist/record/main-pass.d.ts +13 -2
- package/dist/record/main-pass.d.ts.map +1 -1
- package/dist/record/motion-blur-receipt.d.ts +11 -0
- package/dist/record/motion-blur-receipt.d.ts.map +1 -0
- package/dist/record/probe-blend-buffer.d.ts +16 -0
- package/dist/record/probe-blend-buffer.d.ts.map +1 -0
- package/dist/record/recovery-pipeline.d.ts.map +1 -1
- package/dist/record/render-context.d.ts +22 -3
- package/dist/record/render-context.d.ts.map +1 -1
- package/dist/record/shadow-pass.d.ts +2 -0
- 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 +22 -2
- package/dist/record/typed-frame-graph.d.ts.map +1 -1
- package/dist/record/view-ubo.d.ts +11 -3
- package/dist/record/view-ubo.d.ts.map +1 -1
- package/dist/record/volume-params.d.ts +9 -0
- package/dist/record/volume-params.d.ts.map +1 -0
- package/dist/recovery/render-system-candidate.d.ts +10 -0
- package/dist/recovery/render-system-candidate.d.ts.map +1 -1
- package/dist/reflection/record-owner.d.ts.map +1 -1
- package/dist/render-contract.d.ts +42 -4
- package/dist/render-contract.d.ts.map +1 -1
- package/dist/render-graph-primitives.d.ts.map +1 -1
- package/dist/render-pipeline.d.ts +103 -2
- package/dist/render-pipeline.d.ts.map +1 -1
- package/dist/render-system-extract-tail.d.ts +3 -2
- package/dist/render-system-extract-tail.d.ts.map +1 -1
- package/dist/render-system-extract.d.ts +16 -9
- package/dist/render-system-extract.d.ts.map +1 -1
- package/dist/render-system-presentation.d.ts +23 -0
- package/dist/render-system-presentation.d.ts.map +1 -0
- package/dist/render-system-producer-roots.d.ts +10 -0
- package/dist/render-system-producer-roots.d.ts.map +1 -0
- package/dist/render-system-residency.d.ts +12 -0
- package/dist/render-system-residency.d.ts.map +1 -0
- package/dist/render-system.d.ts +19 -14
- package/dist/render-system.d.ts.map +1 -1
- package/dist/scene/probe-blend.d.ts +27 -0
- package/dist/scene/probe-blend.d.ts.map +1 -1
- package/dist/scene/render-scene.d.ts +12 -5
- package/dist/scene/render-scene.d.ts.map +1 -1
- package/dist/ssao-buffers.d.ts +9 -0
- package/dist/ssao-buffers.d.ts.map +1 -1
- package/dist/surface/dynamic-input.d.ts +133 -0
- package/dist/surface/dynamic-input.d.ts.map +1 -0
- package/dist/surface/gpu-driven.d.ts +41 -0
- package/dist/surface/gpu-driven.d.ts.map +1 -0
- package/dist/surface/submission-observation.d.ts +136 -0
- package/dist/surface/submission-observation.d.ts.map +1 -0
- package/dist/systems/skin-palette-allocator.d.ts.map +1 -1
- package/dist/temporal/gpu.d.ts +13 -1
- package/dist/temporal/gpu.d.ts.map +1 -1
- package/dist/temporal/index.mjs +5 -5
- package/dist/temporal/inspection.d.ts.map +1 -1
- package/dist/temporal/standard-scene-data.d.ts.map +1 -1
- package/dist/temporal/target-coverage-attachment.d.ts.map +1 -1
- package/dist/transmission/single-layer-medium.d.ts +89 -0
- package/dist/transmission/single-layer-medium.d.ts.map +1 -0
- package/dist/typed-render-graph-primitives.d.ts +14 -2
- package/dist/typed-render-graph-primitives.d.ts.map +1 -1
- package/dist/volume/component.d.ts +9 -4
- package/dist/volume/component.d.ts.map +1 -1
- package/dist/volume/extract.d.ts +1 -1
- package/dist/volume/extract.d.ts.map +1 -1
- package/dist/volume/inspection.d.ts +2 -0
- package/dist/volume/inspection.d.ts.map +1 -1
- package/dist/volume/passes.d.ts +4 -1
- package/dist/volume/passes.d.ts.map +1 -1
- package/dist/volume/resources.d.ts.map +1 -1
- package/package.json +22 -21
- package/src/__tests__/atmosphere-daylight.dawn.test.ts +72 -0
- package/src/__tests__/barrel-distortion-lkg.integration.test.ts +353 -0
- package/src/__tests__/barrel-distortion.dawn.test.ts +41 -0
- package/src/__tests__/barrel-distortion.unit.test.ts +364 -0
- package/src/__tests__/construct-renderer-identity.unit.test.ts +49 -0
- package/src/__tests__/detached-recovery-graph.unit.test.ts +277 -0
- package/src/__tests__/device-loss-fanout.unit.test.ts +36 -1
- package/src/__tests__/docs-gate-green.unit.test.ts +112 -1
- package/src/__tests__/factory-contract.integration.test.ts +295 -45
- package/src/__tests__/feature-depth-input.dawn.test.ts +129 -2
- package/src/__tests__/fullscreen-feature-plan.unit.test.ts +14 -3
- package/src/__tests__/gpu-dirty-ranges.unit.test.ts +22 -0
- package/src/__tests__/gpu-driven-baseline.characterization.test.ts +16 -3
- package/src/__tests__/gpu-driven-batch-topology-pbr.unit.test.ts +12 -0
- package/src/__tests__/gpu-driven-material-artifacts.unit.test.ts +143 -0
- package/src/__tests__/gpu-driven-pbr.dawn.test.ts +2 -2
- package/src/__tests__/gpu-driven-production.integration.test.ts +482 -3
- package/src/__tests__/gpu-driven-shadow-views.dawn.test.ts +6 -5
- package/src/__tests__/gpu-driven-view-gpu-evidence.ts +94 -6
- package/src/__tests__/gpu-driven-view-graph.integration.test.ts +18 -2
- package/src/__tests__/gpu-driven-view.browser.test.ts +5 -8
- package/src/__tests__/gpu-driven-view.dawn.test.ts +6 -2
- package/src/__tests__/gpu-driven-view.unit.test.ts +1 -1
- package/src/__tests__/gpu-pass-timing-lifecycle.integration.test.ts +1 -0
- package/src/__tests__/gpu-pass-timing.browser.test.ts +6 -4
- package/src/__tests__/gpu-pass-timing.rhi-null.unit.test.ts +1 -0
- package/src/__tests__/gpu-scene.unit.test.ts +119 -9
- package/src/__tests__/instance-allocation-failure.unit.test.ts +57 -0
- package/src/__tests__/instances-culling.integration.test.ts +10 -36
- package/src/__tests__/instances-store.unit.test.ts +97 -305
- package/src/__tests__/instances-world-ownership.integration.test.ts +62 -0
- package/src/__tests__/main-pass-material-medium-selection.unit.test.ts +146 -0
- package/src/__tests__/material-shader-prewarm.unit.test.ts +59 -0
- package/src/__tests__/material-snapshot-mutation.integration.test.ts +39 -1
- package/src/__tests__/morph-culling-reentry.dawn.test.ts +5 -5
- package/src/__tests__/morph-visual-evidence.integration.test.ts +8 -7
- package/src/__tests__/motion-blur-compute.dawn.test.ts +13 -7
- package/src/__tests__/motion-blur.pixel.integration.test.ts +2 -2
- package/src/__tests__/nineslice-handle-surface.unit.test.ts +4 -4
- package/src/__tests__/pbr-view-layout.unit.test.ts +9 -0
- package/src/__tests__/physical-clearcoat.integration.test.ts +58 -0
- package/src/__tests__/prepared-graphics-capability.unit.test.ts +66 -2
- package/src/__tests__/probe-bindings.unit.test.ts +582 -1
- package/src/__tests__/probe-scene-dirty.integration.test.ts +28 -1
- package/src/__tests__/receipt-observation-retirement.unit.test.ts +65 -0
- package/src/__tests__/recovery-candidate-prepare.contract.test.ts +69 -0
- package/src/__tests__/render-error-code-owner.test-d.ts +7 -0
- package/src/__tests__/render-feature-diagnostics.unit.test.ts +15 -2
- package/src/__tests__/render-feature-error-reporting.unit.test.ts +21 -1
- package/src/__tests__/render-feature-prepared-diagnostics.unit.test.ts +10 -1
- package/src/__tests__/render-feature-retry.unit.test.ts +12 -1
- package/src/__tests__/render-scene-mixed-updates.integration.test.ts +145 -19
- package/src/__tests__/render-scene-projection.unit.test.ts +36 -11
- package/src/__tests__/render-scene-temporal-retry.unit.test.ts +20 -20
- package/src/__tests__/render-target-probe-soak.perf.test.ts +2 -2
- package/src/__tests__/render-temporal-environment-consumer.browser.test.ts +3 -3
- package/src/__tests__/render-temporal-environment-consumer.dawn.test.ts +5 -2
- package/src/__tests__/renderer-factory-material-contract.unit.test.ts +41 -7
- package/src/__tests__/renderer-frame-generation-fence.integration.test.ts +16 -0
- package/src/__tests__/renderer-frame-transaction.integration.test.ts +26 -10
- package/src/__tests__/resource-allocation.unit.test.ts +123 -0
- package/src/__tests__/single-layer-medium-passes.unit.test.ts +275 -0
- package/src/__tests__/skin-motion-regression.unit.test.ts +70 -1
- package/src/__tests__/skin-palette-recycling.dawn.test.ts +97 -0
- package/src/__tests__/skinned-shadow-caster.test.ts +15 -0
- package/src/__tests__/ssr-carrier-public-contract.unit.test.ts +21 -0
- package/src/__tests__/ssr-gpu-dispatch.browser.test.ts +4 -4
- package/src/__tests__/ssr-gpu-dispatch.dawn.test.ts +2 -2
- package/src/__tests__/ssr-gpu-dispatch.ts +1 -1
- package/src/__tests__/ssr-receiver-coverage.dawn.test.ts +6 -2
- package/src/__tests__/standard-output-chain-contract.unit.test.ts +28 -0
- package/src/__tests__/standard-pbr-artifact-assembly.unit.test.ts +46 -1
- package/src/__tests__/standard-pipeline.integration.test.ts +182 -1
- package/src/__tests__/surface-dynamic-buffer-lifecycle.unit.test.ts +506 -0
- package/src/__tests__/surface-submission-observation.unit.test.ts +812 -0
- package/src/__tests__/temporal-history-lifecycle.unit.test.ts +32 -0
- package/src/__tests__/temporal-performance.integration.test.ts +3 -3
- package/src/__tests__/visibility-instances.integration.test.ts +7 -19
- package/src/__tests__/visibility-producer-matrix.integration.test.ts +9 -20
- package/src/__tests__/volume-optics-oracle.unit.test.ts +4 -2
- package/src/__tests__/volumetric-fog-budget-recovery.integration.test.ts +30 -20
- package/src/__tests__/volumetric-fog-errors.unit.test.ts +4 -3
- package/src/__tests__/volumetric-fog-multiple.unit.test.ts +55 -0
- package/src/__tests__/volumetric-fog-spot-frame-optics.integration.test.ts +1 -1
- package/src/__tests__/volumetric-fog-stage-readback.dawn.test.ts +113 -9
- package/src/__tests__/volumetric-fog-topology.unit.test.ts +5 -3
- package/src/assembly/backend-contract.ts +30 -0
- package/src/assembly/barrel-distortion-inspection.ts +22 -0
- package/src/assembly/canvas-draw-guard.ts +11 -0
- package/src/assembly/cloud-shadow-entry.ts +22 -0
- package/src/assembly/dynamic-geometry-host.ts +65 -37
- package/src/assembly/dynamic-geometry-runtime.ts +7 -1
- package/src/assembly/factory.ts +2 -30
- package/src/assembly/host-contract.ts +3 -3
- package/src/assembly/material/assembly.ts +25 -13
- package/src/assembly/material/pipeline-helpers.ts +53 -12
- package/src/assembly/material-shader-policy.ts +55 -0
- package/src/assembly/material-shader-prewarm.ts +21 -10
- package/src/assembly/recovery/device-loss-fanout.ts +13 -0
- package/src/assembly/recovery/renderer-recover.ts +41 -18
- package/src/assembly/render-feature-post-processes.ts +54 -0
- package/src/assembly/renderer-facade.ts +4 -1
- package/src/assembly/renderer-feature-inspection.ts +8 -2
- package/src/assembly/renderer-frame-transaction.ts +23 -0
- package/src/assembly/renderer-inspection.ts +28 -0
- package/src/assembly/skin-palette-owner.ts +1 -1
- package/src/assembly/temporal-post-process-prewarm.ts +3 -3
- package/src/assembly/webgpu-pbr-ready.ts +9 -1
- package/src/assembly/webgpu-ready-per-pass.ts +104 -0
- package/src/assembly/webgpu-ready.ts +115 -61
- package/src/assembly/webgpu-renderer-bootstrap.ts +0 -12
- package/src/assembly/webgpu-renderer-observation-owner.ts +222 -0
- package/src/assembly/webgpu-renderer.ts +214 -252
- package/src/assembly/webgpu-vertex-layouts.ts +1 -1
- package/src/barrel-distortion.ts +247 -0
- package/src/cloud/__tests__/cloud-density-parity.dawn.test.ts +173 -0
- package/src/cloud/__tests__/cloud-layer-framebuffer-y.dawn.test.ts +265 -0
- package/src/cloud/__tests__/cloud-layer.browser.test.ts +432 -0
- package/src/cloud/__tests__/cloud-layer.unit.test.ts +634 -0
- package/src/cloud/density.ts +600 -0
- package/src/cloud/extract.ts +110 -0
- package/src/cloud/feature.ts +1810 -0
- package/src/cloud/frame-context.ts +42 -0
- package/src/cloud/inspection.ts +130 -0
- package/src/cloud/optics.ts +285 -0
- package/src/cloud/parameters.ts +255 -0
- package/src/cloud/resources.ts +122 -0
- package/src/cloud/shadow.ts +167 -0
- package/src/cloud/temporal.ts +226 -0
- package/src/components/barrel-distortion.ts +46 -0
- package/src/components/cloud-layer.ts +47 -0
- package/src/components/index.ts +2 -0
- package/src/components/instances.ts +18 -45
- package/src/components/sprite-instances.ts +1 -1
- package/src/construct-renderer.ts +1 -1
- package/src/dynamic-geometry.ts +12 -1
- package/src/errors/cloud.ts +103 -0
- package/src/errors/render.ts +44 -7
- package/src/examples/single-layer-medium-surface.ts +59 -0
- package/src/extract/camera.ts +15 -1
- package/src/extract/contracts.ts +5 -0
- package/src/features/barrel-distortion.ts +172 -0
- package/src/features/error-reporting.ts +26 -6
- package/src/features/host.ts +115 -14
- package/src/features/plan.ts +8 -0
- package/src/features/render-graph-contribution.ts +9 -0
- package/src/features/render-graph-raster.ts +45 -3
- package/src/features/targets.ts +66 -0
- package/src/features/types.ts +47 -0
- package/src/fullscreen-post-process-pass.ts +41 -9
- package/src/gpu-dirty-ranges.ts +48 -0
- package/src/gpu-driven/batch-topology.ts +53 -0
- package/src/gpu-driven/material-artifacts.ts +33 -25
- package/src/gpu-driven/prepared-draw.ts +12 -4
- package/src/gpu-driven/production-raster-material.ts +1894 -0
- package/src/gpu-driven/production-raster.ts +825 -784
- package/src/gpu-driven/resource-allocation.ts +142 -0
- package/src/gpu-driven/shadow-ownership.ts +71 -0
- package/src/gpu-driven/view-gpu.ts +164 -10
- package/src/gpu-scene.ts +75 -84
- package/src/hdrp-buffers.ts +4 -3
- package/src/ibl/skylight-bind-group.ts +49 -7
- package/src/index.ts +196 -9
- package/src/inspection-types.ts +162 -0
- package/src/instance-buffer-cache.ts +4 -4
- package/src/instances.ts +149 -569
- package/src/pbr-pipeline.ts +219 -13
- package/src/pipeline/single-layer-medium-passes.ts +267 -0
- package/src/pipeline/standard-forward-lane.ts +313 -57
- package/src/pipeline/standard-output/graph.ts +8 -2
- package/src/pipeline/standard-output/types.ts +12 -1
- package/src/pipeline/standard-pipeline.ts +291 -18
- package/src/pipeline/standard-post.ts +90 -24
- package/src/pipeline-builder.ts +1 -1
- package/src/plugin.ts +4 -0
- package/src/points-lines/__tests__/points-lines.bench.ts +17 -8
- package/src/prepare/prepared-graphics-resolver.ts +2 -0
- package/src/record/__tests__/main-pass-geometry.unit.test.ts +30 -0
- package/src/record/__tests__/sprite-material-abi.unit.test.ts +1 -1
- package/src/record/__tests__/temporal-payload.unit.test.ts +1 -1
- package/src/record/__tests__/transparent-group2-selection.unit.test.ts +11 -0
- package/src/record/__tests__/typed-frame-graph-plan.unit.test.ts +1 -0
- package/src/record/__tests__/view-ubo-layout.unit.test.ts +4 -3
- package/src/record/barrel-distortion-frame.ts +110 -0
- package/src/record/dynamic-geometry-consumption.ts +39 -9
- package/src/record/fold-buckets.ts +852 -0
- package/src/record/fold-instance-buffer.ts +51 -0
- package/src/record/frame-lighting.ts +36 -2
- package/src/record/frame-snapshot.ts +39 -3
- package/src/record/frame.ts +217 -1084
- package/src/record/gpu-draw-receipts.ts +38 -0
- package/src/record/gpu-timing.ts +48 -5
- package/src/record/main-pass-geometry.ts +251 -82
- package/src/record/main-pass-material.ts +66 -4
- package/src/record/main-pass-sprite-draws.ts +7 -65
- package/src/record/main-pass.ts +156 -20
- package/src/record/motion-blur-receipt.ts +91 -0
- package/src/record/probe-blend-buffer.ts +180 -0
- package/src/record/recovery-pipeline.ts +35 -3
- package/src/record/render-context.ts +39 -3
- package/src/record/shadow-pass.ts +30 -1
- package/src/record/skybox-post-pass.ts +28 -4
- package/src/record/typed-frame-graph.ts +770 -134
- package/src/record/view-ubo.ts +26 -3
- package/src/record/volume-params.ts +225 -0
- package/src/recovery/render-system-candidate.ts +235 -42
- package/src/reflection/record-owner.ts +7 -3
- package/src/render-contract.ts +48 -4
- package/src/render-graph-primitives.ts +7 -1
- package/src/render-pipeline.ts +130 -0
- package/src/render-system-extract-tail.ts +57 -61
- package/src/render-system-extract.ts +74 -76
- package/src/render-system-presentation.ts +56 -0
- package/src/render-system-producer-roots.ts +96 -0
- package/src/render-system-residency.ts +159 -0
- package/src/render-system.ts +347 -363
- package/src/scene/probe-blend.ts +96 -4
- package/src/scene/render-scene.ts +349 -280
- package/src/ssao-buffers.ts +95 -2
- package/src/surface/__tests__/dynamic-input.unit.test.ts +374 -0
- package/src/surface/__tests__/gpu-driven.unit.test.ts +87 -0
- package/src/surface/dynamic-input.ts +658 -0
- package/src/surface/gpu-driven.ts +147 -0
- package/src/surface/submission-observation.ts +517 -0
- package/src/systems/skin-palette-allocator.ts +4 -1
- package/src/temporal/gpu.ts +101 -17
- package/src/temporal/inspection.ts +7 -1
- package/src/temporal/standard-scene-data.ts +5 -0
- package/src/temporal/target-coverage-attachment.ts +4 -0
- package/src/transmission/__tests__/single-layer-medium.unit.test.ts +149 -0
- package/src/transmission/__tests__/standard-transmission.dawn.test.ts +12 -11
- package/src/transmission/single-layer-medium.ts +322 -0
- package/src/typed-render-graph-primitives.ts +70 -2
- package/src/volume/component.ts +10 -9
- package/src/volume/extract.ts +11 -5
- package/src/volume/inspection.ts +3 -0
- package/src/volume/passes.ts +87 -4
- package/src/volume/resources.ts +2 -1
- package/dist/chunk-3RTCJTH4.mjs.map +0 -1
- package/dist/chunk-NB2S7ZRX.mjs.map +0 -1
- package/dist/chunk-NNQL7CB3.mjs +0 -1713
- package/dist/chunk-NNQL7CB3.mjs.map +0 -1
- package/dist/chunk-OO3DRYK7.mjs.map +0 -1
- package/dist/chunk-PA5DRJNI.mjs.map +0 -1
- package/dist/chunk-PLAXOOX5.mjs.map +0 -1
- package/dist/chunk-VOZWDM3L.mjs.map +0 -1
|
@@ -0,0 +1,658 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
MaterialDynamicFieldType,
|
|
3
|
+
MaterialDynamicInputLayout,
|
|
4
|
+
MaterialDynamicInputSchema,
|
|
5
|
+
} from '@forgeax/engine-types';
|
|
6
|
+
import { deriveMaterialDynamicInputLayout, err, ok, type Result } from '@forgeax/engine-types';
|
|
7
|
+
|
|
8
|
+
export type DynamicInputValue = number | readonly number[];
|
|
9
|
+
|
|
10
|
+
/** Stable public address of one admitted Surface draw member. */
|
|
11
|
+
export interface SurfaceDynamicInputMemberIdentity {
|
|
12
|
+
/** `World.identity`; stable across renderer-local World reordering. */
|
|
13
|
+
readonly worldIdentity: string;
|
|
14
|
+
readonly entityKey: number;
|
|
15
|
+
readonly drawItemIndex: number;
|
|
16
|
+
readonly instanceOrdinal: number;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface DynamicInputRange {
|
|
20
|
+
readonly pageId: number;
|
|
21
|
+
readonly sourceId: string;
|
|
22
|
+
/** Producer-owned domain identity retained across device regeneration. */
|
|
23
|
+
readonly domain: string;
|
|
24
|
+
readonly byteOffset: number;
|
|
25
|
+
readonly recordStart: number;
|
|
26
|
+
readonly recordCount: number;
|
|
27
|
+
readonly instanceIndex: number;
|
|
28
|
+
readonly member: SurfaceDynamicInputMemberIdentity;
|
|
29
|
+
readonly contentRevision: number;
|
|
30
|
+
readonly bufferGeneration: number;
|
|
31
|
+
readonly deviceGeneration: number;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export interface DynamicInputDirtyRange {
|
|
35
|
+
readonly byteStart: number;
|
|
36
|
+
readonly byteEnd: number;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export interface DynamicInputUploadReceipt {
|
|
40
|
+
readonly sourceId: string;
|
|
41
|
+
readonly pageId: number;
|
|
42
|
+
readonly contentRevision: number;
|
|
43
|
+
readonly bufferGeneration: number;
|
|
44
|
+
readonly deviceGeneration: number;
|
|
45
|
+
readonly ranges: readonly DynamicInputDirtyRange[];
|
|
46
|
+
readonly bytes: number;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export interface DynamicInputConsumptionReceipt extends DynamicInputRange {
|
|
50
|
+
readonly frameNumber: number;
|
|
51
|
+
readonly uploadedRevision: number;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Renderer input for one frame of a published Surface dynamic page.
|
|
56
|
+
*
|
|
57
|
+
* `ranges` join by their stable World/entity/draw/instance member identity.
|
|
58
|
+
* Producer order is irrelevant and cannot redirect one member's dynamic
|
|
59
|
+
* records to another member after culling or World reordering.
|
|
60
|
+
*/
|
|
61
|
+
export interface SurfaceDynamicInputFrame {
|
|
62
|
+
readonly page: ReadonlyDynamicInputPage;
|
|
63
|
+
readonly ranges?: readonly DynamicInputRange[];
|
|
64
|
+
/** Producer-owned membership/address revision; time and record values do not advance it. */
|
|
65
|
+
readonly projectionRevision: number;
|
|
66
|
+
readonly frameTime: number;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export type DynamicInputErrorCode =
|
|
70
|
+
| 'invalid-schema'
|
|
71
|
+
| 'invalid-record'
|
|
72
|
+
| 'range-overflow'
|
|
73
|
+
| 'domain-overflow'
|
|
74
|
+
| 'not-uploaded'
|
|
75
|
+
| 'stale-generation'
|
|
76
|
+
| 'released';
|
|
77
|
+
|
|
78
|
+
export interface DynamicInputErrorDetail {
|
|
79
|
+
readonly operation:
|
|
80
|
+
| 'create'
|
|
81
|
+
| 'write'
|
|
82
|
+
| 'reserve'
|
|
83
|
+
| 'upload'
|
|
84
|
+
| 'consume'
|
|
85
|
+
| 'reconfigure'
|
|
86
|
+
| 'release';
|
|
87
|
+
readonly field?: string;
|
|
88
|
+
readonly expected: string;
|
|
89
|
+
readonly actual?: unknown;
|
|
90
|
+
readonly sourceId?: string;
|
|
91
|
+
readonly pageId?: number;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const ERROR_POLICY: Readonly<
|
|
95
|
+
Record<DynamicInputErrorCode, { readonly expected: string; readonly hint: string }>
|
|
96
|
+
> = {
|
|
97
|
+
'invalid-schema': {
|
|
98
|
+
expected: 'the dynamic input schema has one derived bounded record layout',
|
|
99
|
+
hint: 'repair the root MaterialSurface dynamicInput declaration and recook it',
|
|
100
|
+
},
|
|
101
|
+
'invalid-record': {
|
|
102
|
+
expected: 'each dynamic record matches the derived scalar/vector fields',
|
|
103
|
+
hint: 'write finite values using the field names and types declared by the material',
|
|
104
|
+
},
|
|
105
|
+
'range-overflow': {
|
|
106
|
+
expected: 'the instance range stays within the declared read-only page',
|
|
107
|
+
hint: 'reduce the range or increase the producer page budget before publication',
|
|
108
|
+
},
|
|
109
|
+
'domain-overflow': {
|
|
110
|
+
expected: 'the page stays within its declared number of producer domains',
|
|
111
|
+
hint: 'reuse an existing domain or publish a larger bounded declaration',
|
|
112
|
+
},
|
|
113
|
+
'not-uploaded': {
|
|
114
|
+
expected: 'the current page revision was uploaded before frame consumption',
|
|
115
|
+
hint: 'submit the page upload receipt and retry the same frame',
|
|
116
|
+
},
|
|
117
|
+
'stale-generation': {
|
|
118
|
+
expected: 'the range, upload, and device use one current page generation',
|
|
119
|
+
hint: 'discard stale addresses and rebuild the producer projection for the current device',
|
|
120
|
+
},
|
|
121
|
+
released: {
|
|
122
|
+
expected: 'the read-only page is still attached to its owning Render lifecycle',
|
|
123
|
+
hint: 'create a new page after releasing the old owner',
|
|
124
|
+
},
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
export class DynamicInputError extends Error {
|
|
128
|
+
readonly code: DynamicInputErrorCode;
|
|
129
|
+
readonly expected: string;
|
|
130
|
+
readonly hint: string;
|
|
131
|
+
readonly detail: DynamicInputErrorDetail;
|
|
132
|
+
|
|
133
|
+
constructor(code: DynamicInputErrorCode, detail: DynamicInputErrorDetail) {
|
|
134
|
+
super(`${code}: ${ERROR_POLICY[code].expected}`);
|
|
135
|
+
this.name = 'DynamicInputError';
|
|
136
|
+
this.code = code;
|
|
137
|
+
this.expected = ERROR_POLICY[code].expected;
|
|
138
|
+
this.hint = ERROR_POLICY[code].hint;
|
|
139
|
+
this.detail = Object.freeze({ ...detail });
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
export type DynamicInputResult<T> = Result<T, DynamicInputError>;
|
|
144
|
+
|
|
145
|
+
interface DomainRecord {
|
|
146
|
+
readonly name: string;
|
|
147
|
+
readonly start: number;
|
|
148
|
+
readonly end: number;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
function alignRange(ranges: DynamicInputDirtyRange[], start: number, end: number): void {
|
|
152
|
+
if (start >= end) return;
|
|
153
|
+
let index = 0;
|
|
154
|
+
while (index < ranges.length && (ranges[index]?.byteEnd ?? 0) < start) index += 1;
|
|
155
|
+
while (index < ranges.length) {
|
|
156
|
+
const existing = ranges[index];
|
|
157
|
+
if (existing === undefined || existing.byteStart > end) break;
|
|
158
|
+
start = Math.min(start, existing.byteStart);
|
|
159
|
+
end = Math.max(end, existing.byteEnd);
|
|
160
|
+
ranges.splice(index, 1);
|
|
161
|
+
}
|
|
162
|
+
ranges.splice(index, 0, { byteStart: start, byteEnd: end });
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
function fieldWidth(type: MaterialDynamicFieldType): number {
|
|
166
|
+
switch (type) {
|
|
167
|
+
case 'f32':
|
|
168
|
+
case 'u32':
|
|
169
|
+
return 1;
|
|
170
|
+
case 'vec2<f32>':
|
|
171
|
+
return 2;
|
|
172
|
+
case 'vec3<f32>':
|
|
173
|
+
return 3;
|
|
174
|
+
case 'vec4<f32>':
|
|
175
|
+
return 4;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
function finiteNumber(value: unknown): value is number {
|
|
180
|
+
return typeof value === 'number' && Number.isFinite(value);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
function invalid(
|
|
184
|
+
code: DynamicInputErrorCode,
|
|
185
|
+
operation: DynamicInputErrorDetail['operation'],
|
|
186
|
+
expected: string,
|
|
187
|
+
actual?: unknown,
|
|
188
|
+
field?: string,
|
|
189
|
+
page?: Readonly<{ sourceId: string; pageId: number }>,
|
|
190
|
+
): DynamicInputError {
|
|
191
|
+
return new DynamicInputError(code, {
|
|
192
|
+
operation,
|
|
193
|
+
expected,
|
|
194
|
+
...(actual === undefined ? {} : { actual }),
|
|
195
|
+
...(field === undefined ? {} : { field }),
|
|
196
|
+
...(page === undefined ? {} : page),
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Generic Render-owned CPU side of a read-only dynamic input page. The page
|
|
202
|
+
* has no GPU handle: the renderer's existing resource owner can upload the
|
|
203
|
+
* detached bytes and attach the receipt to a prepared pass.
|
|
204
|
+
*/
|
|
205
|
+
export class ReadonlyDynamicInputPage {
|
|
206
|
+
readonly sourceId: string;
|
|
207
|
+
readonly pageId: number;
|
|
208
|
+
readonly schema: MaterialDynamicInputSchema;
|
|
209
|
+
readonly layout: MaterialDynamicInputLayout;
|
|
210
|
+
readonly bytes: Uint8Array;
|
|
211
|
+
private contentRevisionValue = 1;
|
|
212
|
+
private bufferGenerationValue = 1;
|
|
213
|
+
private deviceGenerationValue = 1;
|
|
214
|
+
private uploadedRevisionValue = 0;
|
|
215
|
+
private lastUploadedBytesValue = 0;
|
|
216
|
+
private released = false;
|
|
217
|
+
private readonly ownedRanges = new WeakSet<object>();
|
|
218
|
+
private readonly ownedUploads = new WeakSet<object>();
|
|
219
|
+
private readonly dirty = [
|
|
220
|
+
{
|
|
221
|
+
byteStart: 0,
|
|
222
|
+
byteEnd: 0,
|
|
223
|
+
} as DynamicInputDirtyRange,
|
|
224
|
+
];
|
|
225
|
+
private readonly domains = new Map<string, DomainRecord>();
|
|
226
|
+
|
|
227
|
+
private constructor(
|
|
228
|
+
sourceId: string,
|
|
229
|
+
pageId: number,
|
|
230
|
+
schema: MaterialDynamicInputSchema,
|
|
231
|
+
layout: MaterialDynamicInputLayout,
|
|
232
|
+
) {
|
|
233
|
+
this.sourceId = sourceId;
|
|
234
|
+
this.pageId = pageId;
|
|
235
|
+
this.schema = schema;
|
|
236
|
+
this.layout = layout;
|
|
237
|
+
this.bytes = new Uint8Array(schema.maxPageBytes);
|
|
238
|
+
this.dirty.length = 0;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
static create(input: {
|
|
242
|
+
readonly sourceId: string;
|
|
243
|
+
readonly pageId: number;
|
|
244
|
+
readonly schema: MaterialDynamicInputSchema;
|
|
245
|
+
}): DynamicInputResult<ReadonlyDynamicInputPage> {
|
|
246
|
+
if (input.sourceId.length === 0 || !Number.isSafeInteger(input.pageId) || input.pageId < 0) {
|
|
247
|
+
return err(
|
|
248
|
+
invalid(
|
|
249
|
+
'invalid-schema',
|
|
250
|
+
'create',
|
|
251
|
+
'sourceId is non-empty and pageId is non-negative',
|
|
252
|
+
input.pageId,
|
|
253
|
+
),
|
|
254
|
+
);
|
|
255
|
+
}
|
|
256
|
+
const layout = deriveMaterialDynamicInputLayout(input.schema);
|
|
257
|
+
if (!layout.ok) {
|
|
258
|
+
return err(
|
|
259
|
+
invalid(
|
|
260
|
+
'invalid-schema',
|
|
261
|
+
'create',
|
|
262
|
+
layout.error.expected,
|
|
263
|
+
layout.error.actual,
|
|
264
|
+
layout.error.field,
|
|
265
|
+
),
|
|
266
|
+
);
|
|
267
|
+
}
|
|
268
|
+
return ok(
|
|
269
|
+
new ReadonlyDynamicInputPage(input.sourceId, input.pageId, input.schema, layout.value),
|
|
270
|
+
);
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
get contentRevision(): number {
|
|
274
|
+
return this.contentRevisionValue;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
get bufferGeneration(): number {
|
|
278
|
+
return this.bufferGenerationValue;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
get deviceGeneration(): number {
|
|
282
|
+
return this.deviceGenerationValue;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
get uploadedRevision(): number {
|
|
286
|
+
return this.uploadedRevisionValue;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
get lastUploadedBytes(): number {
|
|
290
|
+
return this.lastUploadedBytesValue;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
/** Write one complete record and mark only its byte interval dirty. */
|
|
294
|
+
writeRecord(
|
|
295
|
+
index: number,
|
|
296
|
+
values: Readonly<Record<string, DynamicInputValue>>,
|
|
297
|
+
): DynamicInputResult<number> {
|
|
298
|
+
const live = this.assertLive('write');
|
|
299
|
+
if (!live.ok) return live;
|
|
300
|
+
if (!Number.isSafeInteger(index) || index < 0 || index >= this.schema.maxRecords) {
|
|
301
|
+
return err(
|
|
302
|
+
invalid(
|
|
303
|
+
'range-overflow',
|
|
304
|
+
'write',
|
|
305
|
+
`record index is within [0, ${this.schema.maxRecords})`,
|
|
306
|
+
index,
|
|
307
|
+
'index',
|
|
308
|
+
this,
|
|
309
|
+
),
|
|
310
|
+
);
|
|
311
|
+
}
|
|
312
|
+
const recordOffset = index * this.layout.stride;
|
|
313
|
+
// Encode into detached bytes first. A malformed later field must leave the
|
|
314
|
+
// previously published record and its dirty/revision state untouched.
|
|
315
|
+
const encoded = new Uint8Array(this.layout.stride);
|
|
316
|
+
const view = new DataView(encoded.buffer, encoded.byteOffset, encoded.byteLength);
|
|
317
|
+
for (const field of this.layout.fields) {
|
|
318
|
+
const value = values[field.name];
|
|
319
|
+
if (value === undefined) {
|
|
320
|
+
return err(
|
|
321
|
+
invalid(
|
|
322
|
+
'invalid-record',
|
|
323
|
+
'write',
|
|
324
|
+
`record contains field ${field.name}`,
|
|
325
|
+
value,
|
|
326
|
+
field.name,
|
|
327
|
+
this,
|
|
328
|
+
),
|
|
329
|
+
);
|
|
330
|
+
}
|
|
331
|
+
const width = fieldWidth(field.type);
|
|
332
|
+
const numbers = typeof value === 'number' ? [value] : value;
|
|
333
|
+
if (numbers.length !== width || numbers.some((candidate) => !finiteNumber(candidate))) {
|
|
334
|
+
return err(
|
|
335
|
+
invalid(
|
|
336
|
+
'invalid-record',
|
|
337
|
+
'write',
|
|
338
|
+
`${field.name} is a finite ${field.type}`,
|
|
339
|
+
value,
|
|
340
|
+
field.name,
|
|
341
|
+
this,
|
|
342
|
+
),
|
|
343
|
+
);
|
|
344
|
+
}
|
|
345
|
+
if (
|
|
346
|
+
field.type === 'u32' &&
|
|
347
|
+
(!Number.isInteger(numbers[0]) ||
|
|
348
|
+
(numbers[0] as number) < 0 ||
|
|
349
|
+
(numbers[0] as number) > 0xffffffff)
|
|
350
|
+
) {
|
|
351
|
+
return err(
|
|
352
|
+
invalid(
|
|
353
|
+
'invalid-record',
|
|
354
|
+
'write',
|
|
355
|
+
`${field.name} is an unsigned 32-bit integer`,
|
|
356
|
+
value,
|
|
357
|
+
field.name,
|
|
358
|
+
this,
|
|
359
|
+
),
|
|
360
|
+
);
|
|
361
|
+
}
|
|
362
|
+
for (const [component, number] of numbers.entries()) {
|
|
363
|
+
const offset = field.offset + component * 4;
|
|
364
|
+
if (field.type === 'u32') view.setUint32(offset, number as number, true);
|
|
365
|
+
else view.setFloat32(offset, number as number, true);
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
this.bytes.set(encoded, recordOffset);
|
|
369
|
+
this.contentRevisionValue += 1;
|
|
370
|
+
alignRange(this.dirty, recordOffset, recordOffset + this.layout.stride);
|
|
371
|
+
return ok(this.contentRevisionValue);
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
/** Reserve one explicit instance range; no skin address field is involved. */
|
|
375
|
+
reserveRange(input: {
|
|
376
|
+
readonly domain: string;
|
|
377
|
+
readonly recordStart: number;
|
|
378
|
+
readonly recordCount: number;
|
|
379
|
+
readonly instanceIndex: number;
|
|
380
|
+
readonly member: SurfaceDynamicInputMemberIdentity;
|
|
381
|
+
}): DynamicInputResult<DynamicInputRange> {
|
|
382
|
+
const live = this.assertLive('reserve');
|
|
383
|
+
if (!live.ok) return live;
|
|
384
|
+
if (input.domain.length === 0) {
|
|
385
|
+
return err(
|
|
386
|
+
invalid(
|
|
387
|
+
'domain-overflow',
|
|
388
|
+
'reserve',
|
|
389
|
+
'domain is a non-empty identity',
|
|
390
|
+
input.domain,
|
|
391
|
+
'domain',
|
|
392
|
+
this,
|
|
393
|
+
),
|
|
394
|
+
);
|
|
395
|
+
}
|
|
396
|
+
if (!this.domains.has(input.domain) && this.domains.size >= this.schema.maxDomains) {
|
|
397
|
+
return err(
|
|
398
|
+
invalid(
|
|
399
|
+
'domain-overflow',
|
|
400
|
+
'reserve',
|
|
401
|
+
`at most ${this.schema.maxDomains} domains are active`,
|
|
402
|
+
this.domains.size + 1,
|
|
403
|
+
'domain',
|
|
404
|
+
this,
|
|
405
|
+
),
|
|
406
|
+
);
|
|
407
|
+
}
|
|
408
|
+
if (
|
|
409
|
+
!Number.isSafeInteger(input.instanceIndex) ||
|
|
410
|
+
input.instanceIndex < 0 ||
|
|
411
|
+
input.instanceIndex > 0xffffffff
|
|
412
|
+
) {
|
|
413
|
+
return err(
|
|
414
|
+
invalid(
|
|
415
|
+
'range-overflow',
|
|
416
|
+
'reserve',
|
|
417
|
+
'instance index is an exact unsigned 32-bit integer',
|
|
418
|
+
input.instanceIndex,
|
|
419
|
+
'instanceIndex',
|
|
420
|
+
this,
|
|
421
|
+
),
|
|
422
|
+
);
|
|
423
|
+
}
|
|
424
|
+
if (
|
|
425
|
+
input.member.worldIdentity.length === 0 ||
|
|
426
|
+
!Number.isSafeInteger(input.member.entityKey) ||
|
|
427
|
+
input.member.entityKey < 0 ||
|
|
428
|
+
input.member.entityKey > 0xffffffff ||
|
|
429
|
+
!Number.isSafeInteger(input.member.drawItemIndex) ||
|
|
430
|
+
input.member.drawItemIndex < 0 ||
|
|
431
|
+
input.member.drawItemIndex > 0xffffffff ||
|
|
432
|
+
!Number.isSafeInteger(input.member.instanceOrdinal) ||
|
|
433
|
+
input.member.instanceOrdinal < 0 ||
|
|
434
|
+
input.member.instanceOrdinal > 0xffffffff
|
|
435
|
+
) {
|
|
436
|
+
return err(
|
|
437
|
+
invalid(
|
|
438
|
+
'range-overflow',
|
|
439
|
+
'reserve',
|
|
440
|
+
'member is a stable World identity plus exact unsigned 32-bit entity, draw-item, and instance identities',
|
|
441
|
+
input.member,
|
|
442
|
+
'member',
|
|
443
|
+
this,
|
|
444
|
+
),
|
|
445
|
+
);
|
|
446
|
+
}
|
|
447
|
+
if (
|
|
448
|
+
!Number.isSafeInteger(input.recordStart) ||
|
|
449
|
+
!Number.isSafeInteger(input.recordCount) ||
|
|
450
|
+
input.recordStart < 0 ||
|
|
451
|
+
input.recordCount <= 0 ||
|
|
452
|
+
input.recordStart + input.recordCount > this.schema.maxRecords
|
|
453
|
+
) {
|
|
454
|
+
return err(
|
|
455
|
+
invalid(
|
|
456
|
+
'range-overflow',
|
|
457
|
+
'reserve',
|
|
458
|
+
'record range and instance index fit the declared page',
|
|
459
|
+
input,
|
|
460
|
+
'recordStart',
|
|
461
|
+
this,
|
|
462
|
+
),
|
|
463
|
+
);
|
|
464
|
+
}
|
|
465
|
+
const range: DynamicInputRange = {
|
|
466
|
+
pageId: this.pageId,
|
|
467
|
+
sourceId: this.sourceId,
|
|
468
|
+
domain: input.domain,
|
|
469
|
+
byteOffset: input.recordStart * this.layout.stride,
|
|
470
|
+
recordStart: input.recordStart,
|
|
471
|
+
recordCount: input.recordCount,
|
|
472
|
+
instanceIndex: input.instanceIndex,
|
|
473
|
+
member: Object.freeze({ ...input.member }),
|
|
474
|
+
contentRevision: this.contentRevisionValue,
|
|
475
|
+
bufferGeneration: this.bufferGenerationValue,
|
|
476
|
+
deviceGeneration: this.deviceGenerationValue,
|
|
477
|
+
};
|
|
478
|
+
this.ownedRanges.add(range);
|
|
479
|
+
this.domains.set(input.domain, {
|
|
480
|
+
name: input.domain,
|
|
481
|
+
start: input.recordStart,
|
|
482
|
+
end: input.recordStart + input.recordCount,
|
|
483
|
+
});
|
|
484
|
+
return ok(range);
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
/** Return detached dirty bytes for the existing resource owner to upload. */
|
|
488
|
+
beginUpload(): DynamicInputResult<DynamicInputUploadReceipt> {
|
|
489
|
+
const live = this.assertLive('upload');
|
|
490
|
+
if (!live.ok) return live;
|
|
491
|
+
const ranges = this.dirty.map((range) => ({ ...range }));
|
|
492
|
+
const bytes = ranges.reduce((sum, range) => sum + range.byteEnd - range.byteStart, 0);
|
|
493
|
+
const receipt: DynamicInputUploadReceipt = {
|
|
494
|
+
sourceId: this.sourceId,
|
|
495
|
+
pageId: this.pageId,
|
|
496
|
+
contentRevision: this.contentRevisionValue,
|
|
497
|
+
bufferGeneration: this.bufferGenerationValue,
|
|
498
|
+
deviceGeneration: this.deviceGenerationValue,
|
|
499
|
+
ranges,
|
|
500
|
+
bytes,
|
|
501
|
+
};
|
|
502
|
+
this.ownedUploads.add(receipt);
|
|
503
|
+
return ok(receipt);
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
/**
|
|
507
|
+
* Commit an upload only after the owning queue write has succeeded. A
|
|
508
|
+
* producer that changed the page while a write was in flight leaves the
|
|
509
|
+
* dirty bytes pending and must retry the new revision.
|
|
510
|
+
*/
|
|
511
|
+
commitUpload(receipt: DynamicInputUploadReceipt): DynamicInputResult<true> {
|
|
512
|
+
const live = this.assertLive('upload');
|
|
513
|
+
if (!live.ok) return live;
|
|
514
|
+
if (
|
|
515
|
+
!this.ownedUploads.has(receipt) ||
|
|
516
|
+
receipt.sourceId !== this.sourceId ||
|
|
517
|
+
receipt.pageId !== this.pageId ||
|
|
518
|
+
receipt.bufferGeneration !== this.bufferGenerationValue ||
|
|
519
|
+
receipt.deviceGeneration !== this.deviceGenerationValue ||
|
|
520
|
+
receipt.contentRevision !== this.contentRevisionValue
|
|
521
|
+
) {
|
|
522
|
+
return err(
|
|
523
|
+
invalid(
|
|
524
|
+
'stale-generation',
|
|
525
|
+
'upload',
|
|
526
|
+
'the upload receipt still describes the current page revision and generation',
|
|
527
|
+
receipt,
|
|
528
|
+
'receipt',
|
|
529
|
+
this,
|
|
530
|
+
),
|
|
531
|
+
);
|
|
532
|
+
}
|
|
533
|
+
this.uploadedRevisionValue = receipt.contentRevision;
|
|
534
|
+
this.lastUploadedBytesValue = receipt.bytes;
|
|
535
|
+
for (const range of receipt.ranges) {
|
|
536
|
+
const index = this.dirty.findIndex(
|
|
537
|
+
(candidate) =>
|
|
538
|
+
candidate.byteStart === range.byteStart && candidate.byteEnd === range.byteEnd,
|
|
539
|
+
);
|
|
540
|
+
if (index >= 0) this.dirty.splice(index, 1);
|
|
541
|
+
}
|
|
542
|
+
return ok(true);
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
/** CPU-only convenience: begin and commit are still explicit in production. */
|
|
546
|
+
upload(): DynamicInputResult<DynamicInputUploadReceipt> {
|
|
547
|
+
const receipt = this.beginUpload();
|
|
548
|
+
if (!receipt.ok) return receipt;
|
|
549
|
+
const committed = this.commitUpload(receipt.value);
|
|
550
|
+
if (!committed.ok) return committed;
|
|
551
|
+
return receipt;
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
/** Consume an uploaded range after graph submission has completed. */
|
|
555
|
+
consume(
|
|
556
|
+
range: DynamicInputRange,
|
|
557
|
+
frameNumber: number,
|
|
558
|
+
): DynamicInputResult<DynamicInputConsumptionReceipt> {
|
|
559
|
+
const live = this.assertLive('consume');
|
|
560
|
+
if (!live.ok) return live;
|
|
561
|
+
if (
|
|
562
|
+
!this.ownedRanges.has(range) ||
|
|
563
|
+
range.sourceId !== this.sourceId ||
|
|
564
|
+
range.pageId !== this.pageId ||
|
|
565
|
+
range.bufferGeneration !== this.bufferGenerationValue ||
|
|
566
|
+
range.deviceGeneration !== this.deviceGenerationValue ||
|
|
567
|
+
range.recordStart < 0 ||
|
|
568
|
+
range.recordCount <= 0 ||
|
|
569
|
+
range.recordStart + range.recordCount > this.schema.maxRecords
|
|
570
|
+
) {
|
|
571
|
+
return err(
|
|
572
|
+
invalid(
|
|
573
|
+
'stale-generation',
|
|
574
|
+
'consume',
|
|
575
|
+
'range belongs to this current page generation',
|
|
576
|
+
range,
|
|
577
|
+
'generation',
|
|
578
|
+
this,
|
|
579
|
+
),
|
|
580
|
+
);
|
|
581
|
+
}
|
|
582
|
+
if (this.uploadedRevisionValue < range.contentRevision) {
|
|
583
|
+
return err(
|
|
584
|
+
invalid(
|
|
585
|
+
'not-uploaded',
|
|
586
|
+
'consume',
|
|
587
|
+
'range content revision was uploaded before consumption',
|
|
588
|
+
this.uploadedRevisionValue,
|
|
589
|
+
'contentRevision',
|
|
590
|
+
this,
|
|
591
|
+
),
|
|
592
|
+
);
|
|
593
|
+
}
|
|
594
|
+
return ok({ ...range, frameNumber, uploadedRevision: this.uploadedRevisionValue });
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
/** Device loss/rebuild changes physical generations while source identity stays stable. */
|
|
598
|
+
reconfigureDevice(deviceGeneration: number): DynamicInputResult<number> {
|
|
599
|
+
const live = this.assertLive('reconfigure');
|
|
600
|
+
if (!live.ok) return live;
|
|
601
|
+
if (!Number.isSafeInteger(deviceGeneration) || deviceGeneration < 0) {
|
|
602
|
+
return err(
|
|
603
|
+
invalid(
|
|
604
|
+
'stale-generation',
|
|
605
|
+
'reconfigure',
|
|
606
|
+
'deviceGeneration is a non-negative safe integer',
|
|
607
|
+
deviceGeneration,
|
|
608
|
+
'deviceGeneration',
|
|
609
|
+
this,
|
|
610
|
+
),
|
|
611
|
+
);
|
|
612
|
+
}
|
|
613
|
+
const rendererInitialGeneration =
|
|
614
|
+
this.bufferGenerationValue === 1 &&
|
|
615
|
+
this.deviceGenerationValue === 1 &&
|
|
616
|
+
deviceGeneration === 0;
|
|
617
|
+
if (deviceGeneration < this.deviceGenerationValue && !rendererInitialGeneration) {
|
|
618
|
+
return err(
|
|
619
|
+
invalid(
|
|
620
|
+
'stale-generation',
|
|
621
|
+
'reconfigure',
|
|
622
|
+
'deviceGeneration does not precede the current device generation',
|
|
623
|
+
deviceGeneration,
|
|
624
|
+
'deviceGeneration',
|
|
625
|
+
this,
|
|
626
|
+
),
|
|
627
|
+
);
|
|
628
|
+
}
|
|
629
|
+
this.deviceGenerationValue = deviceGeneration;
|
|
630
|
+
this.bufferGenerationValue += 1;
|
|
631
|
+
this.uploadedRevisionValue = 0;
|
|
632
|
+
alignRange(this.dirty, 0, this.schema.maxRecords * this.layout.stride);
|
|
633
|
+
return ok(this.bufferGenerationValue);
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
release(): DynamicInputResult<true> {
|
|
637
|
+
if (this.released) return ok(true);
|
|
638
|
+
this.released = true;
|
|
639
|
+
this.domains.clear();
|
|
640
|
+
this.dirty.length = 0;
|
|
641
|
+
return ok(true);
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
private assertLive(operation: DynamicInputErrorDetail['operation']): DynamicInputResult<true> {
|
|
645
|
+
return this.released
|
|
646
|
+
? err(
|
|
647
|
+
invalid(
|
|
648
|
+
'released',
|
|
649
|
+
operation,
|
|
650
|
+
ERROR_POLICY.released.expected,
|
|
651
|
+
undefined,
|
|
652
|
+
undefined,
|
|
653
|
+
this,
|
|
654
|
+
),
|
|
655
|
+
)
|
|
656
|
+
: ok(true);
|
|
657
|
+
}
|
|
658
|
+
}
|