@forgeax/engine-render 0.1.19 → 0.1.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +215 -0
- package/dist/.tsbuildinfo +1 -1
- package/dist/assembly/device-feature-admission.d.ts +18 -0
- package/dist/assembly/device-feature-admission.d.ts.map +1 -0
- package/dist/assembly/directional-shadow-inspection.d.ts +38 -0
- package/dist/assembly/directional-shadow-inspection.d.ts.map +1 -0
- package/dist/assembly/factory.d.ts +34 -20
- package/dist/assembly/factory.d.ts.map +1 -1
- package/dist/assembly/host-contract.d.ts +9 -0
- package/dist/assembly/host-contract.d.ts.map +1 -1
- package/dist/assembly/render-target-host.d.ts +46 -0
- package/dist/assembly/render-target-host.d.ts.map +1 -0
- package/dist/assets/render-asset-port.d.ts.map +1 -1
- package/dist/authoring.mjs +3 -0
- package/dist/authoring.mjs.map +1 -1
- package/dist/capture/cube-views.d.ts +21 -0
- package/dist/capture/cube-views.d.ts.map +1 -0
- package/dist/capture/scheduler.d.ts +54 -0
- package/dist/capture/scheduler.d.ts.map +1 -0
- package/dist/{chunk-RJRUS55L.mjs → chunk-5YADUCA7.mjs} +1896 -1624
- package/dist/chunk-5YADUCA7.mjs.map +1 -0
- package/dist/{chunk-LOSO4CTV.mjs → chunk-6OPXDQ2E.mjs} +423 -46
- package/dist/chunk-6OPXDQ2E.mjs.map +1 -0
- package/dist/{chunk-IPXCABEP.mjs → chunk-BXBQQKFQ.mjs} +3 -9
- package/dist/chunk-BXBQQKFQ.mjs.map +1 -0
- package/dist/chunk-FS2KNUQH.mjs +1294 -0
- package/dist/chunk-FS2KNUQH.mjs.map +1 -0
- package/dist/components/camera.d.ts +1 -0
- package/dist/components/camera.d.ts.map +1 -1
- package/dist/components/cube-camera.d.ts +20 -0
- package/dist/components/cube-camera.d.ts.map +1 -0
- package/dist/components/directional-light.d.ts +11 -2
- package/dist/components/directional-light.d.ts.map +1 -1
- package/dist/components/directional-shadow-filter.d.ts +25 -0
- package/dist/components/directional-shadow-filter.d.ts.map +1 -0
- package/dist/components/index.d.ts +2 -0
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/light-helpers.d.ts.map +1 -1
- package/dist/components/reflection-probe.d.ts +17 -0
- package/dist/components/reflection-probe.d.ts.map +1 -0
- package/dist/components/spot-light.d.ts +12 -0
- package/dist/components/spot-light.d.ts.map +1 -1
- package/dist/construct-renderer.mjs +8552 -1612
- package/dist/construct-renderer.mjs.map +1 -1
- package/dist/device/gpu-residency.d.ts +19 -2
- package/dist/device/gpu-residency.d.ts.map +1 -1
- package/dist/environment/frame.d.ts.map +1 -1
- package/dist/environment/lifecycle.d.ts +5 -0
- package/dist/environment/lifecycle.d.ts.map +1 -1
- package/dist/errors/render.d.ts +209 -93
- package/dist/errors/render.d.ts.map +1 -1
- package/dist/extract/directional-shadow-projection.d.ts +23 -0
- package/dist/extract/directional-shadow-projection.d.ts.map +1 -0
- package/dist/extract/environment.d.ts +14 -0
- package/dist/extract/environment.d.ts.map +1 -1
- package/dist/extract/visibility.d.ts.map +1 -1
- package/dist/features/fullscreen.d.ts.map +1 -1
- package/dist/features/targets.d.ts.map +1 -1
- package/dist/features/types.d.ts +10 -0
- package/dist/features/types.d.ts.map +1 -1
- package/dist/fullscreen-post-process-pass.d.ts +13 -2
- package/dist/fullscreen-post-process-pass.d.ts.map +1 -1
- package/dist/gpu-driven/batch-topology.d.ts.map +1 -1
- package/dist/gpu-driven/production-raster.d.ts +0 -1
- package/dist/gpu-driven/production-raster.d.ts.map +1 -1
- package/dist/gpu-scene.d.ts.map +1 -1
- package/dist/gpu-usage.d.ts +2 -0
- package/dist/gpu-usage.d.ts.map +1 -1
- package/dist/hdrp-buffers.d.ts +19 -17
- package/dist/hdrp-buffers.d.ts.map +1 -1
- package/dist/ibl/IblPipelineCache.d.ts +4 -0
- package/dist/ibl/IblPipelineCache.d.ts.map +1 -1
- package/dist/ibl/kernel-cache.d.ts +36 -0
- package/dist/ibl/kernel-cache.d.ts.map +1 -0
- package/dist/index.d.ts +35 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.mjs +4 -4
- package/dist/index.mjs.map +1 -1
- package/dist/inspection-types.d.ts +51 -0
- package/dist/inspection-types.d.ts.map +1 -1
- package/dist/instances-derived-bounds.d.ts +50 -0
- package/dist/instances-derived-bounds.d.ts.map +1 -0
- package/dist/internal.mjs +1 -1
- package/dist/light-buffer-layout.d.ts +30 -13
- package/dist/light-buffer-layout.d.ts.map +1 -1
- package/dist/mesh-material-bindings.d.ts +54 -0
- package/dist/mesh-material-bindings.d.ts.map +1 -1
- package/dist/pbr-pipeline.d.ts +20 -7
- package/dist/pbr-pipeline.d.ts.map +1 -1
- package/dist/pipeline/standard-forward-lane.d.ts +2 -1
- package/dist/pipeline/standard-forward-lane.d.ts.map +1 -1
- package/dist/pipeline/standard-lighting/errors.d.ts +4 -0
- package/dist/pipeline/standard-lighting/errors.d.ts.map +1 -0
- package/dist/pipeline/standard-lighting/graph.d.ts +24 -0
- package/dist/pipeline/standard-lighting/graph.d.ts.map +1 -0
- package/dist/pipeline/standard-lighting/inspection.d.ts +38 -0
- package/dist/pipeline/standard-lighting/inspection.d.ts.map +1 -0
- package/dist/pipeline/standard-lighting/layout.d.ts +28 -0
- package/dist/pipeline/standard-lighting/layout.d.ts.map +1 -0
- package/dist/pipeline/standard-lighting/light-frame.d.ts +33 -0
- package/dist/pipeline/standard-lighting/light-frame.d.ts.map +1 -0
- package/dist/pipeline/standard-lighting/membership.d.ts +14 -0
- package/dist/pipeline/standard-lighting/membership.d.ts.map +1 -0
- package/dist/pipeline/standard-lighting/prepare.d.ts +16 -0
- package/dist/pipeline/standard-lighting/prepare.d.ts.map +1 -0
- package/dist/pipeline/standard-lighting/topology.d.ts +45 -0
- package/dist/pipeline/standard-lighting/topology.d.ts.map +1 -0
- package/dist/pipeline/standard-lighting/transport.d.ts +36 -0
- package/dist/pipeline/standard-lighting/transport.d.ts.map +1 -0
- package/dist/pipeline/standard-pipeline.d.ts +4 -13
- package/dist/pipeline/standard-pipeline.d.ts.map +1 -1
- package/dist/pipeline/standard-post.d.ts.map +1 -1
- package/dist/pipeline/standard-profile.d.ts +12 -20
- package/dist/pipeline/standard-profile.d.ts.map +1 -1
- package/dist/pipeline-spec.d.ts +40 -7
- package/dist/pipeline-spec.d.ts.map +1 -1
- package/dist/point-shadow-inspection.d.ts +21 -0
- package/dist/point-shadow-inspection.d.ts.map +1 -0
- package/dist/record/frame-lighting.d.ts +29 -32
- package/dist/record/frame-lighting.d.ts.map +1 -1
- package/dist/record/frame-snapshot.d.ts +65 -15
- package/dist/record/frame-snapshot.d.ts.map +1 -1
- package/dist/record/frame-targets.d.ts +5 -0
- package/dist/record/frame-targets.d.ts.map +1 -1
- package/dist/record/frame.d.ts +12 -5
- package/dist/record/frame.d.ts.map +1 -1
- package/dist/record/gpu-pass-timing/contract.d.ts +96 -0
- package/dist/record/gpu-pass-timing/contract.d.ts.map +1 -0
- package/dist/record/gpu-pass-timing/errors.d.ts +18 -0
- package/dist/record/gpu-pass-timing/errors.d.ts.map +1 -0
- package/dist/record/gpu-pass-timing/index.d.ts +8 -0
- package/dist/record/gpu-pass-timing/index.d.ts.map +1 -0
- package/dist/record/gpu-pass-timing/parser.d.ts +11 -0
- package/dist/record/gpu-pass-timing/parser.d.ts.map +1 -0
- package/dist/record/gpu-pass-timing/session.d.ts +43 -0
- package/dist/record/gpu-pass-timing/session.d.ts.map +1 -0
- package/dist/record/gpu-timing.d.ts +37 -0
- package/dist/record/gpu-timing.d.ts.map +1 -0
- package/dist/record/main-pass-geometry.d.ts.map +1 -1
- package/dist/record/main-pass-material.d.ts +23 -2
- package/dist/record/main-pass-material.d.ts.map +1 -1
- package/dist/record/main-pass-sprite-draws.d.ts.map +1 -1
- package/dist/record/main-pass.d.ts +2 -0
- package/dist/record/main-pass.d.ts.map +1 -1
- package/dist/record/render-context.d.ts +48 -3
- package/dist/record/render-context.d.ts.map +1 -1
- package/dist/record/shadow-pass.d.ts.map +1 -1
- package/dist/record/skybox-post-pass.d.ts.map +1 -1
- package/dist/record/typed-frame-graph.d.ts +81 -5
- package/dist/record/typed-frame-graph.d.ts.map +1 -1
- package/dist/record/view-ubo.d.ts +7 -4
- package/dist/record/view-ubo.d.ts.map +1 -1
- package/dist/reflection/filter.d.ts +22 -0
- package/dist/reflection/filter.d.ts.map +1 -0
- package/dist/reflection/gpu-table.d.ts +25 -0
- package/dist/reflection/gpu-table.d.ts.map +1 -0
- package/dist/reflection/projection.d.ts +91 -0
- package/dist/reflection/projection.d.ts.map +1 -0
- package/dist/render-contract.d.ts +114 -7
- package/dist/render-contract.d.ts.map +1 -1
- package/dist/render-data.d.ts +10 -6
- package/dist/render-data.d.ts.map +1 -1
- package/dist/render-graph-primitives.d.ts +1 -0
- package/dist/render-graph-primitives.d.ts.map +1 -1
- package/dist/render-pipeline.d.ts +78 -2
- package/dist/render-pipeline.d.ts.map +1 -1
- package/dist/render-system-extract.d.ts +113 -20
- package/dist/render-system-extract.d.ts.map +1 -1
- package/dist/render-system.d.ts +24 -3
- package/dist/render-system.d.ts.map +1 -1
- package/dist/renderer-inspect.d.ts +29 -0
- package/dist/renderer-inspect.d.ts.map +1 -0
- package/dist/renderer.d.ts +43 -0
- package/dist/renderer.d.ts.map +1 -0
- package/dist/scene/render-scene.d.ts +14 -0
- package/dist/scene/render-scene.d.ts.map +1 -1
- package/dist/shadow-atlas.d.ts +3 -3
- package/dist/shadow-atlas.d.ts.map +1 -1
- package/dist/ssao-buffers.d.ts +3 -0
- package/dist/ssao-buffers.d.ts.map +1 -1
- package/dist/targets/contracts.d.ts +66 -0
- package/dist/targets/contracts.d.ts.map +1 -0
- package/dist/targets/graph-projection.d.ts +29 -0
- package/dist/targets/graph-projection.d.ts.map +1 -0
- package/dist/targets/material-source.d.ts +34 -0
- package/dist/targets/material-source.d.ts.map +1 -0
- package/dist/targets/owner.d.ts +32 -0
- package/dist/targets/owner.d.ts.map +1 -0
- package/dist/targets/physical.d.ts +18 -0
- package/dist/targets/physical.d.ts.map +1 -0
- package/dist/targets/readback.d.ts +39 -0
- package/dist/targets/readback.d.ts.map +1 -0
- package/dist/temporal/frame.d.ts +44 -0
- package/dist/temporal/frame.d.ts.map +1 -0
- package/dist/temporal/index.mjs +3 -3
- package/dist/typed-render-graph-primitives.d.ts +6 -1
- package/dist/typed-render-graph-primitives.d.ts.map +1 -1
- package/dist/typed-shadow-atlas.d.ts +10 -0
- package/dist/typed-shadow-atlas.d.ts.map +1 -0
- package/dist/typed-shadow-passes.d.ts +1 -1
- package/dist/typed-shadow-passes.d.ts.map +1 -1
- package/dist/volume/capability.d.ts +57 -0
- package/dist/volume/capability.d.ts.map +1 -0
- package/dist/volume/component.d.ts +61 -0
- package/dist/volume/component.d.ts.map +1 -0
- package/dist/volume/extract.d.ts +11 -0
- package/dist/volume/extract.d.ts.map +1 -0
- package/dist/volume/inspection.d.ts +38 -0
- package/dist/volume/inspection.d.ts.map +1 -0
- package/dist/volume/passes.d.ts +38 -0
- package/dist/volume/passes.d.ts.map +1 -0
- package/dist/volume/recovery.d.ts +38 -0
- package/dist/volume/recovery.d.ts.map +1 -0
- package/dist/volume/resources.d.ts +57 -0
- package/dist/volume/resources.d.ts.map +1 -0
- package/dist/volume/temporal.d.ts +35 -0
- package/dist/volume/temporal.d.ts.map +1 -0
- package/package.json +20 -20
- package/src/__tests__/bloom-exact-zero.unit.test.ts +48 -19
- package/src/__tests__/bloom-lifecycle.integration.test.ts +41 -13
- package/src/__tests__/camera-target-consumption.unit.test.ts +53 -0
- package/src/__tests__/cluster-binner.unit.test.ts +35 -0
- package/src/__tests__/cluster-grid-default-surface.unit.test.ts +7 -2
- package/src/__tests__/cube-camera-scheduler.unit.test.ts +70 -0
- package/src/__tests__/cube-camera-single-submit.perf.test.ts +75 -0
- package/src/__tests__/cube-camera-view-matrices.unit.test.ts +41 -0
- package/src/__tests__/cube-camera-vocabulary.unit.test.ts +47 -0
- package/src/__tests__/cube-camera.integration.test.ts +42 -0
- package/src/__tests__/device-feature-admission.unit.test.ts +73 -0
- package/src/__tests__/direct-light-snapshot.unit.test.ts +3 -3
- package/src/__tests__/docs-gate-green.unit.test.ts +38 -0
- package/src/__tests__/factory-contract.integration.test.ts +255 -29
- package/src/__tests__/fog-component.unit.test.ts +67 -0
- package/src/__tests__/fog.integration.test.ts +86 -0
- package/src/__tests__/fullscreen-feature-plan.unit.test.ts +37 -0
- package/src/__tests__/gpu-driven-indirect-raster-evidence.ts +10 -9
- package/src/__tests__/gpu-driven-indirect-raster.dawn.test.ts +17 -1
- package/src/__tests__/gpu-driven-production.integration.test.ts +16 -17
- package/src/__tests__/gpu-driven-view-graph.integration.test.ts +12 -4
- package/src/__tests__/gpu-pass-timing-browser-runner.ts +281 -0
- package/src/__tests__/gpu-pass-timing-coexistence.integration.test.ts +80 -0
- package/src/__tests__/gpu-pass-timing-contract.unit.test.ts +243 -0
- package/src/__tests__/gpu-pass-timing-exact-zero.unit.test.ts +131 -0
- package/src/__tests__/gpu-pass-timing-lifecycle.integration.test.ts +230 -0
- package/src/__tests__/gpu-pass-timing-observation.unit.test.ts +233 -0
- package/src/__tests__/gpu-pass-timing-session.unit.test.ts +438 -0
- package/src/__tests__/gpu-pass-timing.browser.test.ts +26 -0
- package/src/__tests__/gpu-pass-timing.rhi-null.unit.test.ts +125 -0
- package/src/__tests__/hdrp-group2-visibility.unit.test.ts +24 -0
- package/src/__tests__/instances-culling.integration.test.ts +94 -0
- package/src/__tests__/instances-derived-bounds.unit.test.ts +118 -0
- package/src/__tests__/ktx2-basis-gpu-consumer.dawn.test.ts +14 -14
- package/src/__tests__/material-observation.integration.test.ts +101 -0
- package/src/__tests__/mesh-buffer-usage-surface.unit.test.ts +1 -1
- package/src/__tests__/pbr-view-layout.unit.test.ts +16 -0
- package/src/__tests__/point-shadow-inspection.unit.test.ts +60 -0
- package/src/__tests__/public-surface.test-d.ts +10 -0
- package/src/__tests__/reflection-probe-authoring.unit.test.ts +71 -0
- package/src/__tests__/reflection-probe-filter.unit.test.ts +54 -0
- package/src/__tests__/reflection-probe-ibl-topology.unit.test.ts +45 -0
- package/src/__tests__/reflection-probe-pass-encode.integration.test.ts +101 -0
- package/src/__tests__/reflection-probe-performance.perf.test.ts +60 -0
- package/src/__tests__/reflection-probe-recovery.integration.test.ts +55 -0
- package/src/__tests__/reflection-probe-selection.unit.test.ts +46 -0
- package/src/__tests__/render-error-code-owner.test-d.ts +23 -3
- package/src/__tests__/render-feature-docs.unit.test.ts +1 -1
- package/src/__tests__/render-target-admission.unit.test.ts +80 -0
- package/src/__tests__/render-target-graph-projection.unit.test.ts +102 -0
- package/src/__tests__/render-target-inspection.unit.test.ts +52 -0
- package/src/__tests__/render-target-material-source.test-d.ts +30 -0
- package/src/__tests__/render-target-material-source.unit.test.ts +97 -0
- package/src/__tests__/render-target-owner-placement.unit.test.ts +203 -0
- package/src/__tests__/render-target-owner.unit.test.ts +122 -0
- package/src/__tests__/render-target-probe-soak.perf.test.ts +94 -0
- package/src/__tests__/render-target-public-schema.json +107 -0
- package/src/__tests__/render-target-public-schema.unit.test.ts +91 -0
- package/src/__tests__/render-target-public-surface.test-d.ts +83 -0
- package/src/__tests__/render-target-readback.integration.test.ts +90 -0
- package/src/__tests__/render-target-recovery.integration.test.ts +85 -0
- package/src/__tests__/renderer-factory-material-contract.unit.test.ts +76 -0
- package/src/__tests__/renderer-frame-transaction.integration.test.ts +1 -1
- package/src/__tests__/renderer-lifecycle.integration.test.ts +14 -0
- package/src/__tests__/shader-stage-surface.unit.test.ts +19 -4
- package/src/__tests__/skin-motion-regression.unit.test.ts +132 -0
- package/src/__tests__/skinned-shadow-caster.test.ts +32 -2
- package/src/__tests__/standard-cluster-capability.integration.test.ts +63 -0
- package/src/__tests__/standard-cluster-transport.unit.test.ts +121 -0
- package/src/__tests__/standard-cluster-variant-resolution.unit.test.ts +232 -0
- package/src/__tests__/standard-clustered-pipeline.unit.test.ts +8 -5
- package/src/__tests__/standard-lighting-inspection.integration.test.ts +138 -0
- package/src/__tests__/standard-lighting-ssot.unit.test.ts +18 -0
- package/src/__tests__/standard-lighting-write.unit.test.ts +377 -0
- package/src/__tests__/standard-lighting.integration.test.ts +67 -0
- package/src/__tests__/standard-pipeline.dawn.test.ts +206 -5
- package/src/__tests__/standard-pipeline.integration.test.ts +181 -150
- package/src/__tests__/standard-probe-binding.unit.test.ts +25 -0
- package/src/__tests__/standard-profile-oracle.unit.test.ts +23 -36
- package/src/__tests__/typed-pipeline-topology.unit.test.ts +395 -14
- package/src/__tests__/urp-pipeline-targets.unit.test.ts +2 -2
- package/src/__tests__/visibility-resolver.unit.test.ts +15 -0
- package/src/__tests__/volume-optics-oracle.unit.test.ts +85 -0
- package/src/__tests__/volumetric-fog-budget-recovery.integration.test.ts +655 -0
- package/src/__tests__/volumetric-fog-component.unit.test.ts +71 -0
- package/src/__tests__/volumetric-fog-composite-stage-readback.dawn.test.ts +376 -0
- package/src/__tests__/volumetric-fog-errors.unit.test.ts +51 -0
- package/src/__tests__/volumetric-fog-inspection.unit.test.ts +77 -0
- package/src/__tests__/volumetric-fog-light-capability.unit.test.ts +19 -0
- package/src/__tests__/volumetric-fog-light-consumers.integration.test.ts +18 -0
- package/src/__tests__/volumetric-fog-light-errors.unit.test.ts +17 -0
- package/src/__tests__/volumetric-fog-light-topology.unit.test.ts +21 -0
- package/src/__tests__/volumetric-fog-light-transaction.integration.test.ts +53 -0
- package/src/__tests__/volumetric-fog-m9-watcher.integration.test.ts +27 -0
- package/src/__tests__/volumetric-fog-point-light-owner.integration.test.ts +44 -0
- package/src/__tests__/volumetric-fog-point-spot-accumulation.integration.test.ts +49 -0
- package/src/__tests__/volumetric-fog-point-spot-contract.unit.test.ts +28 -0
- package/src/__tests__/volumetric-fog-point-spot-lkg.integration.test.ts +65 -0
- package/src/__tests__/volumetric-fog-point-spot-selection.integration.test.ts +49 -0
- package/src/__tests__/volumetric-fog-point-spot-temporal.unit.test.ts +55 -0
- package/src/__tests__/volumetric-fog-projector-contract.unit.test.ts +22 -0
- package/src/__tests__/volumetric-fog-projector-inspection.unit.test.ts +12 -0
- package/src/__tests__/volumetric-fog-projector-surface-volume.integration.test.ts +11 -0
- package/src/__tests__/volumetric-fog-projector-transaction.integration.test.ts +26 -0
- package/src/__tests__/volumetric-fog-recovery.integration.test.ts +47 -0
- package/src/__tests__/volumetric-fog-selected-light-resolution.integration.test.ts +63 -0
- package/src/__tests__/volumetric-fog-spot-closure.integration.test.ts +26 -0
- package/src/__tests__/volumetric-fog-spot-contract.test-d.ts +21 -0
- package/src/__tests__/volumetric-fog-spot-contract.unit.test.ts +27 -0
- package/src/__tests__/volumetric-fog-spot-frame-optics.integration.test.ts +14 -0
- package/src/__tests__/volumetric-fog-spot-optics.integration.test.ts +29 -0
- package/src/__tests__/volumetric-fog-stage-readback.dawn.test.ts +550 -0
- package/src/__tests__/volumetric-fog-temporal-selected-light.unit.test.ts +33 -0
- package/src/__tests__/volumetric-fog-temporal.unit.test.ts +45 -0
- package/src/__tests__/volumetric-fog-topology.unit.test.ts +237 -0
- package/src/__tests__/volumetric-fog-transparent.integration.test.ts +27 -0
- package/src/assembly/device-feature-admission.ts +73 -0
- package/src/assembly/directional-shadow-inspection.ts +122 -0
- package/src/assembly/factory.ts +1093 -246
- package/src/assembly/host-contract.ts +25 -0
- package/src/assembly/render-target-host.ts +847 -0
- package/src/assets/asset-decoders.ts +1 -1
- package/src/assets/render-asset-port.ts +7 -1
- package/src/capture/cube-views.ts +69 -0
- package/src/capture/scheduler.ts +265 -0
- package/src/components/__tests__/schema-contract.unit.test.ts +12 -0
- package/src/components/__tests__/schema-parity.unit.test.ts +9 -0
- package/src/components/camera.ts +4 -0
- package/src/components/cube-camera.ts +52 -0
- package/src/components/directional-light.ts +22 -2
- package/src/components/directional-shadow-filter.ts +57 -0
- package/src/components/index.ts +2 -0
- package/src/components/light-helpers.ts +85 -7
- package/src/components/reflection-probe.ts +49 -0
- package/src/components/spot-light.ts +22 -3
- package/src/device/gpu-residency.ts +168 -58
- package/src/environment/frame.ts +6 -24
- package/src/environment/lifecycle.ts +12 -0
- package/src/errors/render.ts +405 -143
- package/src/extract/directional-shadow-projection.ts +61 -0
- package/src/extract/environment.ts +57 -0
- package/src/extract/visibility.ts +25 -1
- package/src/features/fullscreen.ts +3 -0
- package/src/features/targets.ts +4 -1
- package/src/features/types.ts +10 -0
- package/src/fullscreen-post-process-pass.ts +43 -2
- package/src/gpu-driven/batch-topology.ts +1 -0
- package/src/gpu-driven/production-raster.ts +1 -3
- package/src/gpu-scene.ts +8 -1
- package/src/gpu-usage.ts +2 -0
- package/src/hdrp-buffers.ts +165 -59
- package/src/ibl/IblPipelineCache.ts +11 -0
- package/src/ibl/kernel-cache.ts +88 -0
- package/src/index.ts +186 -1
- package/src/inspection-types.ts +56 -0
- package/src/instances-derived-bounds.ts +171 -0
- package/src/light-buffer-layout.ts +74 -26
- package/src/mesh-material-bindings.ts +132 -0
- package/src/pbr-pipeline.ts +139 -27
- package/src/pipeline/standard-forward-lane.ts +65 -15
- package/src/pipeline/standard-lighting/errors.ts +6 -0
- package/src/pipeline/standard-lighting/graph.ts +157 -0
- package/src/pipeline/standard-lighting/inspection.ts +88 -0
- package/src/pipeline/standard-lighting/layout.ts +31 -0
- package/src/pipeline/standard-lighting/light-frame.ts +34 -0
- package/src/pipeline/standard-lighting/membership.ts +43 -0
- package/src/pipeline/standard-lighting/prepare.ts +37 -0
- package/src/pipeline/standard-lighting/topology.ts +120 -0
- package/src/pipeline/standard-lighting/transport.ts +77 -0
- package/src/pipeline/standard-pipeline.ts +141 -192
- package/src/pipeline/standard-post.ts +26 -7
- package/src/pipeline/standard-profile.ts +23 -30
- package/src/pipeline-spec.ts +84 -21
- package/src/point-shadow-inspection.ts +55 -0
- package/src/record/__tests__/temporal-payload.unit.test.ts +42 -1
- package/src/record/__tests__/transparent-group2-selection.unit.test.ts +73 -0
- package/src/record/__tests__/view-ubo-layout.unit.test.ts +40 -0
- package/src/record/frame-lighting.ts +470 -516
- package/src/record/frame-snapshot.ts +76 -28
- package/src/record/frame-targets.ts +23 -2
- package/src/record/frame.ts +1169 -79
- package/src/record/gpu-pass-timing/contract.ts +180 -0
- package/src/record/gpu-pass-timing/errors.ts +34 -0
- package/src/record/gpu-pass-timing/index.ts +37 -0
- package/src/record/gpu-pass-timing/parser.ts +97 -0
- package/src/record/gpu-pass-timing/session.ts +938 -0
- package/src/record/gpu-timing.ts +233 -0
- package/src/record/main-pass-geometry.ts +120 -80
- package/src/record/main-pass-material.ts +101 -11
- package/src/record/main-pass-sprite-draws.ts +54 -25
- package/src/record/main-pass.ts +71 -15
- package/src/record/render-context.ts +77 -0
- package/src/record/shadow-pass.ts +104 -66
- package/src/record/skybox-post-pass.ts +20 -4
- package/src/record/typed-frame-graph.ts +1016 -32
- package/src/record/view-ubo.ts +63 -28
- package/src/reflection/filter.ts +81 -0
- package/src/reflection/gpu-table.ts +44 -0
- package/src/reflection/projection.ts +281 -0
- package/src/render-contract.ts +147 -4
- package/src/render-data.ts +50 -22
- package/src/render-graph-primitives.ts +9 -4
- package/src/render-pipeline.ts +161 -2
- package/src/render-system-extract.ts +886 -103
- package/src/render-system.ts +1174 -66
- package/src/renderer-inspect.ts +66 -0
- package/src/renderer.ts +222 -0
- package/src/scene/render-scene.ts +117 -9
- package/src/shadow-atlas.ts +5 -5
- package/src/ssao-buffers.ts +9 -2
- package/src/targets/contracts.ts +182 -0
- package/src/targets/graph-projection.ts +169 -0
- package/src/targets/material-source.ts +143 -0
- package/src/targets/owner.ts +214 -0
- package/src/targets/physical.ts +18 -0
- package/src/targets/readback.ts +153 -0
- package/src/temporal/frame.ts +128 -0
- package/src/transmission/__tests__/standard-transmission.dawn.test.ts +61 -23
- package/src/typed-render-graph-primitives.ts +34 -2
- package/src/typed-shadow-atlas.ts +17 -0
- package/src/typed-shadow-passes.ts +47 -40
- package/src/volume/capability.ts +173 -0
- package/src/volume/component.ts +110 -0
- package/src/volume/extract.ts +21 -0
- package/src/volume/inspection.ts +78 -0
- package/src/volume/passes.ts +686 -0
- package/src/volume/recovery.ts +86 -0
- package/src/volume/resources.ts +236 -0
- package/src/volume/temporal.ts +89 -0
- package/dist/chunk-IPXCABEP.mjs.map +0 -1
- package/dist/chunk-LOSO4CTV.mjs.map +0 -1
- package/dist/chunk-RJRUS55L.mjs.map +0 -1
- package/dist/chunk-YTQ5C7YQ.mjs +0 -584
- package/dist/chunk-YTQ5C7YQ.mjs.map +0 -1
|
@@ -0,0 +1,847 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
Buffer,
|
|
3
|
+
RhiCommandEncoder,
|
|
4
|
+
RhiDevice,
|
|
5
|
+
Texture,
|
|
6
|
+
TextureView,
|
|
7
|
+
} from '@forgeax/engine-rhi';
|
|
8
|
+
import type { RenderError } from '../errors/render';
|
|
9
|
+
import {
|
|
10
|
+
RenderTargetCapabilityMissingError,
|
|
11
|
+
RenderTargetDescriptorInvalidError,
|
|
12
|
+
RenderTargetOperationFailedError,
|
|
13
|
+
RenderTargetStateInvalidError,
|
|
14
|
+
} from '../errors/render';
|
|
15
|
+
import {
|
|
16
|
+
GPU_TEXTURE_USAGE_COPY_SRC,
|
|
17
|
+
GPU_TEXTURE_USAGE_RENDER_ATTACHMENT,
|
|
18
|
+
GPU_TEXTURE_USAGE_TEXTURE_BINDING,
|
|
19
|
+
} from '../gpu-texture-usage';
|
|
20
|
+
import { GPU_BUFFER_USAGE_COPY_DST, GPU_BUFFER_USAGE_MAP_READ } from '../gpu-usage';
|
|
21
|
+
import { resolveRenderTargetMipExtent } from '../record/frame-targets';
|
|
22
|
+
import type { RenderResult } from '../render-contract';
|
|
23
|
+
import {
|
|
24
|
+
admitRenderTargetDescriptor,
|
|
25
|
+
type RenderTarget,
|
|
26
|
+
type RenderTargetAdmissionLimits,
|
|
27
|
+
type RenderTargetDescriptor,
|
|
28
|
+
type RenderTargetReadbackData,
|
|
29
|
+
type RenderTargetReadbackRequest,
|
|
30
|
+
type RenderTargetReadbackTicket,
|
|
31
|
+
type RenderTargetTextureSource,
|
|
32
|
+
type RenderTargetTextureSourceOptions,
|
|
33
|
+
} from '../targets/contracts';
|
|
34
|
+
import {
|
|
35
|
+
createRenderTargetMaterialSource,
|
|
36
|
+
type RenderTargetMaterialSourceBinding,
|
|
37
|
+
resolveRenderTargetMaterialSource,
|
|
38
|
+
} from '../targets/material-source';
|
|
39
|
+
import { createRenderTargetOwner, type RenderTargetOwner } from '../targets/owner';
|
|
40
|
+
import type { RenderTargetPhysical } from '../targets/physical';
|
|
41
|
+
import {
|
|
42
|
+
bindRenderTargetReadbackTicket,
|
|
43
|
+
completeRenderTargetReadback,
|
|
44
|
+
createRenderTargetReadbackTicket,
|
|
45
|
+
type RenderTargetReadbackTicket as InternalReadbackTicket,
|
|
46
|
+
type RenderTargetReadbackReceipt,
|
|
47
|
+
} from '../targets/readback';
|
|
48
|
+
|
|
49
|
+
export interface RenderTargetHostOptions {
|
|
50
|
+
readonly rendererId?: symbol;
|
|
51
|
+
readonly initialGeneration?: number;
|
|
52
|
+
readonly getGeneration?: () => number;
|
|
53
|
+
readonly limits?: RenderTargetAdmissionLimits;
|
|
54
|
+
readonly getDevice?: () => RhiDevice;
|
|
55
|
+
/**
|
|
56
|
+
* Renderer-owned candidate publication gate. Progressive cube capture keeps
|
|
57
|
+
* a target candidate across face submissions and returns true only after the
|
|
58
|
+
* capture scheduler has committed all faces for the matching fence.
|
|
59
|
+
*/
|
|
60
|
+
readonly canPromoteTarget?: (target: RenderTarget) => boolean;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const DEFAULT_LIMITS: RenderTargetAdmissionLimits = {
|
|
64
|
+
maxTextureDimension2D: 8192,
|
|
65
|
+
maxBytesPerTarget: 256 * 1024 * 1024,
|
|
66
|
+
renderableFormats: ['rgba16float', 'rgba8unorm', 'rgba8unorm-srgb'],
|
|
67
|
+
sampleCounts: [1, 4],
|
|
68
|
+
depthFormats: ['depth24plus-stencil8', 'depth32float'],
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
interface ReadbackRecord {
|
|
72
|
+
readonly target: RenderTarget;
|
|
73
|
+
readonly request: RenderTargetReadbackRequest;
|
|
74
|
+
readonly ticket: InternalReadbackTicket;
|
|
75
|
+
readonly buffer?: Buffer;
|
|
76
|
+
encoded: boolean;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export interface RenderTargetHost {
|
|
80
|
+
/** The logical owner for every target lifecycle operation. */
|
|
81
|
+
readonly owner: 'renderer';
|
|
82
|
+
createRenderTarget(descriptor: RenderTargetDescriptor): RenderResult<RenderTarget, RenderError>;
|
|
83
|
+
resizeRenderTarget(
|
|
84
|
+
target: RenderTarget,
|
|
85
|
+
descriptor: RenderTargetDescriptor,
|
|
86
|
+
): RenderResult<void, RenderError>;
|
|
87
|
+
createRenderTargetTextureSource(
|
|
88
|
+
target: RenderTarget,
|
|
89
|
+
options: RenderTargetTextureSourceOptions,
|
|
90
|
+
): RenderResult<RenderTargetTextureSource, RenderError>;
|
|
91
|
+
/** @internal Resolve a source for the existing material projection path. */
|
|
92
|
+
resolveRenderTargetTextureSource(
|
|
93
|
+
source: RenderTargetTextureSource,
|
|
94
|
+
): RenderTargetMaterialSourceBinding | undefined;
|
|
95
|
+
requestTargetReadback(
|
|
96
|
+
target: RenderTarget,
|
|
97
|
+
request: RenderTargetReadbackRequest,
|
|
98
|
+
): RenderResult<RenderTargetReadbackTicket, RenderError>;
|
|
99
|
+
observeTargetReadbacks(
|
|
100
|
+
receipt: RenderTargetReadbackReceipt,
|
|
101
|
+
tickets: readonly RenderTargetReadbackTicket[],
|
|
102
|
+
): Promise<RenderResult<readonly RenderTargetReadbackData[], RenderError>>;
|
|
103
|
+
/** @internal Physical target used by the active Standard frame. */
|
|
104
|
+
getPhysicalTarget(target: RenderTarget): RenderTargetPhysical | undefined;
|
|
105
|
+
/** @internal Add pending target copies to the frame's sole encoder. */
|
|
106
|
+
encodePendingReadbacks(encoder: RhiCommandEncoder, faces?: readonly number[]): void;
|
|
107
|
+
destroyRenderTarget(target: RenderTarget): RenderResult<void, RenderError>;
|
|
108
|
+
/** Called immediately before the existing Standard frame is interpreted. */
|
|
109
|
+
beginFrame(): void;
|
|
110
|
+
/** Called only after the existing Renderer frame submission is accepted. */
|
|
111
|
+
onFrameSubmitted(completed?: Promise<RenderResult<void, RenderError>>): void;
|
|
112
|
+
/** Called after a replacement DeviceScope generation becomes active. */
|
|
113
|
+
recover(): void;
|
|
114
|
+
/** Called before Renderer-owned physical resources are released. */
|
|
115
|
+
dispose(): void;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function opaqueTicket(): RenderTargetReadbackTicket {
|
|
119
|
+
return Object.freeze({}) as RenderTargetReadbackTicket;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function bytesPerPixel(format: RenderTargetDescriptor['format']): number {
|
|
123
|
+
return format === 'rgba16float' ? 8 : 4;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
function mipCount(descriptor: RenderTargetDescriptor): number {
|
|
127
|
+
return descriptor.mipLevels === 1
|
|
128
|
+
? 1
|
|
129
|
+
: Math.floor(Math.log2(Math.max(descriptor.width, descriptor.height))) + 1;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
function makePhysical(
|
|
133
|
+
device: RhiDevice,
|
|
134
|
+
descriptor: RenderTargetDescriptor,
|
|
135
|
+
generation: number,
|
|
136
|
+
): RenderResult<RenderTargetPhysical, RenderError> {
|
|
137
|
+
const layers = descriptor.shape === 'cube' ? 6 : 1;
|
|
138
|
+
const usage =
|
|
139
|
+
GPU_TEXTURE_USAGE_RENDER_ATTACHMENT |
|
|
140
|
+
(descriptor.sampled ? GPU_TEXTURE_USAGE_TEXTURE_BINDING : 0) |
|
|
141
|
+
(descriptor.readback ? GPU_TEXTURE_USAGE_COPY_SRC : 0);
|
|
142
|
+
const created = device.createTexture({
|
|
143
|
+
label: `render-target.${generation}`,
|
|
144
|
+
size: { width: descriptor.width, height: descriptor.height, depthOrArrayLayers: layers },
|
|
145
|
+
format: descriptor.format,
|
|
146
|
+
mipLevelCount: mipCount(descriptor),
|
|
147
|
+
// WebGPU forbids multisampled array textures. The cube is always the
|
|
148
|
+
// single-sample resolve destination; MSAA capture uses one depth=1 color
|
|
149
|
+
// texture per face below.
|
|
150
|
+
sampleCount: 1,
|
|
151
|
+
dimension: '2d',
|
|
152
|
+
usage,
|
|
153
|
+
viewFormats: undefined,
|
|
154
|
+
textureBindingViewDimension: descriptor.shape === 'cube' ? 'cube' : undefined,
|
|
155
|
+
});
|
|
156
|
+
if (!created.ok)
|
|
157
|
+
return {
|
|
158
|
+
ok: false,
|
|
159
|
+
error: new RenderTargetOperationFailedError({
|
|
160
|
+
operation: 'create',
|
|
161
|
+
stage: 'allocation',
|
|
162
|
+
generation,
|
|
163
|
+
cause: created.error,
|
|
164
|
+
recovery: 'retry',
|
|
165
|
+
}),
|
|
166
|
+
};
|
|
167
|
+
const texture = created.value;
|
|
168
|
+
const view = device.createTextureView(texture, {
|
|
169
|
+
dimension: descriptor.shape,
|
|
170
|
+
baseMipLevel: 0,
|
|
171
|
+
mipLevelCount: mipCount(descriptor),
|
|
172
|
+
baseArrayLayer: 0,
|
|
173
|
+
arrayLayerCount: layers,
|
|
174
|
+
});
|
|
175
|
+
if (!view.ok)
|
|
176
|
+
return {
|
|
177
|
+
ok: false,
|
|
178
|
+
error: new RenderTargetOperationFailedError({
|
|
179
|
+
operation: 'create',
|
|
180
|
+
stage: 'allocation',
|
|
181
|
+
generation,
|
|
182
|
+
cause: view.error,
|
|
183
|
+
recovery: 'retry',
|
|
184
|
+
}),
|
|
185
|
+
};
|
|
186
|
+
const mipViews: TextureView[] = [];
|
|
187
|
+
for (let mip = 0; mip < mipCount(descriptor); mip += 1) {
|
|
188
|
+
const mipView = device.createTextureView(texture, {
|
|
189
|
+
dimension: descriptor.shape,
|
|
190
|
+
baseMipLevel: mip,
|
|
191
|
+
mipLevelCount: 1,
|
|
192
|
+
baseArrayLayer: 0,
|
|
193
|
+
arrayLayerCount: layers,
|
|
194
|
+
});
|
|
195
|
+
if (!mipView.ok)
|
|
196
|
+
return {
|
|
197
|
+
ok: false,
|
|
198
|
+
error: new RenderTargetOperationFailedError({
|
|
199
|
+
operation: 'create',
|
|
200
|
+
stage: 'allocation',
|
|
201
|
+
generation,
|
|
202
|
+
cause: mipView.error,
|
|
203
|
+
recovery: 'retry',
|
|
204
|
+
}),
|
|
205
|
+
};
|
|
206
|
+
mipViews.push(mipView.value);
|
|
207
|
+
}
|
|
208
|
+
const resolveFaceViews: TextureView[] = [];
|
|
209
|
+
for (let face = 0; face < layers; face += 1) {
|
|
210
|
+
const faceView = device.createTextureView(texture, {
|
|
211
|
+
dimension: '2d',
|
|
212
|
+
baseMipLevel: 0,
|
|
213
|
+
mipLevelCount: 1,
|
|
214
|
+
baseArrayLayer: face,
|
|
215
|
+
arrayLayerCount: 1,
|
|
216
|
+
});
|
|
217
|
+
if (!faceView.ok)
|
|
218
|
+
return {
|
|
219
|
+
ok: false,
|
|
220
|
+
error: new RenderTargetOperationFailedError({
|
|
221
|
+
operation: 'create',
|
|
222
|
+
stage: 'allocation',
|
|
223
|
+
generation,
|
|
224
|
+
cause: faceView.error,
|
|
225
|
+
recovery: 'retry',
|
|
226
|
+
}),
|
|
227
|
+
};
|
|
228
|
+
resolveFaceViews.push(faceView.value);
|
|
229
|
+
}
|
|
230
|
+
const colorTextures: Texture[] = [];
|
|
231
|
+
const faceViews: TextureView[] = [];
|
|
232
|
+
const depthTextures: Texture[] = [];
|
|
233
|
+
const depthViews: TextureView[] = [];
|
|
234
|
+
if (descriptor.shape === 'cube') {
|
|
235
|
+
for (let face = 0; face < layers; face += 1) {
|
|
236
|
+
const depth = device.createTexture({
|
|
237
|
+
label: `render-target.${generation}.depth.${face}`,
|
|
238
|
+
size: {
|
|
239
|
+
width: descriptor.width,
|
|
240
|
+
height: descriptor.height,
|
|
241
|
+
depthOrArrayLayers: descriptor.sampleCount === 4 ? 1 : layers,
|
|
242
|
+
},
|
|
243
|
+
mipLevelCount: 1,
|
|
244
|
+
sampleCount: descriptor.sampleCount,
|
|
245
|
+
dimension: '2d',
|
|
246
|
+
format: 'depth24plus-stencil8',
|
|
247
|
+
usage: GPU_TEXTURE_USAGE_RENDER_ATTACHMENT,
|
|
248
|
+
viewFormats: undefined,
|
|
249
|
+
textureBindingViewDimension: undefined,
|
|
250
|
+
});
|
|
251
|
+
if (!depth.ok)
|
|
252
|
+
return {
|
|
253
|
+
ok: false,
|
|
254
|
+
error: new RenderTargetOperationFailedError({
|
|
255
|
+
operation: 'create',
|
|
256
|
+
stage: 'allocation',
|
|
257
|
+
generation,
|
|
258
|
+
cause: depth.error,
|
|
259
|
+
recovery: 'retry',
|
|
260
|
+
}),
|
|
261
|
+
};
|
|
262
|
+
const depthView = device.createTextureView(depth.value, {
|
|
263
|
+
dimension: '2d',
|
|
264
|
+
baseArrayLayer: descriptor.sampleCount === 4 ? 0 : face,
|
|
265
|
+
arrayLayerCount: 1,
|
|
266
|
+
});
|
|
267
|
+
if (!depthView.ok)
|
|
268
|
+
return {
|
|
269
|
+
ok: false,
|
|
270
|
+
error: new RenderTargetOperationFailedError({
|
|
271
|
+
operation: 'create',
|
|
272
|
+
stage: 'allocation',
|
|
273
|
+
generation,
|
|
274
|
+
cause: depthView.error,
|
|
275
|
+
recovery: 'retry',
|
|
276
|
+
}),
|
|
277
|
+
};
|
|
278
|
+
depthTextures.push(depth.value);
|
|
279
|
+
depthViews.push(depthView.value);
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
if (descriptor.sampleCount === 4) {
|
|
283
|
+
for (let face = 0; face < layers; face += 1) {
|
|
284
|
+
const msaa = device.createTexture({
|
|
285
|
+
label: `render-target.${generation}.msaa.${face}`,
|
|
286
|
+
size: { width: descriptor.width, height: descriptor.height, depthOrArrayLayers: 1 },
|
|
287
|
+
format: descriptor.format,
|
|
288
|
+
mipLevelCount: 1,
|
|
289
|
+
sampleCount: 4,
|
|
290
|
+
dimension: '2d',
|
|
291
|
+
usage: GPU_TEXTURE_USAGE_RENDER_ATTACHMENT,
|
|
292
|
+
viewFormats: undefined,
|
|
293
|
+
textureBindingViewDimension: undefined,
|
|
294
|
+
});
|
|
295
|
+
if (!msaa.ok)
|
|
296
|
+
return {
|
|
297
|
+
ok: false,
|
|
298
|
+
error: new RenderTargetOperationFailedError({
|
|
299
|
+
operation: 'create',
|
|
300
|
+
stage: 'allocation',
|
|
301
|
+
generation,
|
|
302
|
+
cause: msaa.error,
|
|
303
|
+
recovery: 'retry',
|
|
304
|
+
}),
|
|
305
|
+
};
|
|
306
|
+
const msaaView = device.createTextureView(msaa.value, {
|
|
307
|
+
dimension: '2d',
|
|
308
|
+
baseMipLevel: 0,
|
|
309
|
+
mipLevelCount: 1,
|
|
310
|
+
baseArrayLayer: 0,
|
|
311
|
+
arrayLayerCount: 1,
|
|
312
|
+
});
|
|
313
|
+
if (!msaaView.ok)
|
|
314
|
+
return {
|
|
315
|
+
ok: false,
|
|
316
|
+
error: new RenderTargetOperationFailedError({
|
|
317
|
+
operation: 'create',
|
|
318
|
+
stage: 'allocation',
|
|
319
|
+
generation,
|
|
320
|
+
cause: msaaView.error,
|
|
321
|
+
recovery: 'retry',
|
|
322
|
+
}),
|
|
323
|
+
};
|
|
324
|
+
colorTextures.push(msaa.value);
|
|
325
|
+
faceViews.push(msaaView.value);
|
|
326
|
+
}
|
|
327
|
+
} else {
|
|
328
|
+
for (let face = 0; face < layers; face += 1) {
|
|
329
|
+
colorTextures.push(texture);
|
|
330
|
+
faceViews.push(resolveFaceViews[face] ?? view.value);
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
return {
|
|
334
|
+
ok: true,
|
|
335
|
+
value: {
|
|
336
|
+
generation,
|
|
337
|
+
descriptor,
|
|
338
|
+
texture,
|
|
339
|
+
view: view.value,
|
|
340
|
+
mipViews,
|
|
341
|
+
colorTextures,
|
|
342
|
+
faceViews,
|
|
343
|
+
depthTextures,
|
|
344
|
+
depthViews,
|
|
345
|
+
...(descriptor.sampleCount === 4 ? { resolveTexture: texture } : {}),
|
|
346
|
+
resolveView: view.value,
|
|
347
|
+
resolveFaceViews,
|
|
348
|
+
},
|
|
349
|
+
};
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
function destroyPhysical(
|
|
353
|
+
device: RhiDevice | undefined,
|
|
354
|
+
physical: RenderTargetPhysical | undefined,
|
|
355
|
+
): void {
|
|
356
|
+
if (device === undefined || physical === undefined) return;
|
|
357
|
+
const textures = new Set<Texture>();
|
|
358
|
+
textures.add(physical.texture);
|
|
359
|
+
if (physical.resolveTexture !== undefined) textures.add(physical.resolveTexture);
|
|
360
|
+
for (const texture of physical.colorTextures) textures.add(texture);
|
|
361
|
+
for (const texture of physical.depthTextures) textures.add(texture);
|
|
362
|
+
for (const texture of textures) device.destroyTexture(texture);
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
export function createRenderTargetHost(options: RenderTargetHostOptions = {}): RenderTargetHost {
|
|
366
|
+
let disposed = false;
|
|
367
|
+
const limits = options.limits ?? DEFAULT_LIMITS;
|
|
368
|
+
const owner: RenderTargetOwner = createRenderTargetOwner({
|
|
369
|
+
rendererId: options.rendererId ?? Symbol('renderer'),
|
|
370
|
+
initialGeneration: options.initialGeneration ?? 0,
|
|
371
|
+
});
|
|
372
|
+
const targets = new Set<RenderTarget>();
|
|
373
|
+
const staged = new Set<RenderTarget>();
|
|
374
|
+
const activePhysical = new WeakMap<object, RenderTargetPhysical>();
|
|
375
|
+
const candidatePhysical = new WeakMap<object, RenderTargetPhysical>();
|
|
376
|
+
const sources = new WeakMap<object, RenderTargetMaterialSourceBinding>();
|
|
377
|
+
const readbacks = new WeakMap<object, ReadbackRecord>();
|
|
378
|
+
const readbackRecords = new Set<ReadbackRecord>();
|
|
379
|
+
const currentGeneration = (): number =>
|
|
380
|
+
options.getGeneration?.() ?? options.initialGeneration ?? 0;
|
|
381
|
+
const stagePhysical = (
|
|
382
|
+
target: RenderTarget,
|
|
383
|
+
descriptor?: RenderTargetDescriptor,
|
|
384
|
+
): RenderResult<void, RenderError> => {
|
|
385
|
+
const stagedTarget = owner.stage(target, descriptor);
|
|
386
|
+
if (!stagedTarget.ok) return stagedTarget;
|
|
387
|
+
const device = options.getDevice?.();
|
|
388
|
+
if (device === undefined) {
|
|
389
|
+
staged.add(target);
|
|
390
|
+
return { ok: true, value: undefined };
|
|
391
|
+
}
|
|
392
|
+
const physical = makePhysical(
|
|
393
|
+
device,
|
|
394
|
+
stagedTarget.value.descriptor,
|
|
395
|
+
stagedTarget.value.generation,
|
|
396
|
+
);
|
|
397
|
+
if (!physical.ok) {
|
|
398
|
+
owner.rejectCandidate(target, stagedTarget.value.generation, 'allocation');
|
|
399
|
+
return physical;
|
|
400
|
+
}
|
|
401
|
+
candidatePhysical.set(target as object, physical.value);
|
|
402
|
+
staged.add(target);
|
|
403
|
+
return { ok: true, value: undefined };
|
|
404
|
+
};
|
|
405
|
+
|
|
406
|
+
return Object.freeze({
|
|
407
|
+
owner: 'renderer' as const,
|
|
408
|
+
createRenderTarget(
|
|
409
|
+
descriptor: RenderTargetDescriptor,
|
|
410
|
+
): RenderResult<RenderTarget, RenderError> {
|
|
411
|
+
if (disposed) {
|
|
412
|
+
return {
|
|
413
|
+
ok: false,
|
|
414
|
+
error: new RenderTargetStateInvalidError({
|
|
415
|
+
operation: 'inspect',
|
|
416
|
+
reason: 'destroyed',
|
|
417
|
+
state: 'destroyed',
|
|
418
|
+
generation: currentGeneration(),
|
|
419
|
+
}),
|
|
420
|
+
};
|
|
421
|
+
}
|
|
422
|
+
const admitted = admitRenderTargetDescriptor(descriptor, limits);
|
|
423
|
+
if (!admitted.ok) return admitted;
|
|
424
|
+
const created = owner.create(admitted.value);
|
|
425
|
+
if (created.ok) targets.add(created.value);
|
|
426
|
+
return created;
|
|
427
|
+
},
|
|
428
|
+
resizeRenderTarget(
|
|
429
|
+
target: RenderTarget,
|
|
430
|
+
descriptor: RenderTargetDescriptor,
|
|
431
|
+
): RenderResult<void, RenderError> {
|
|
432
|
+
const admitted = admitRenderTargetDescriptor(descriptor, limits);
|
|
433
|
+
if (!admitted.ok) return admitted;
|
|
434
|
+
return stagePhysical(target, admitted.value);
|
|
435
|
+
},
|
|
436
|
+
createRenderTargetTextureSource(
|
|
437
|
+
target: RenderTarget,
|
|
438
|
+
sourceOptions: RenderTargetTextureSourceOptions,
|
|
439
|
+
): RenderResult<RenderTargetTextureSource, RenderError> {
|
|
440
|
+
const inspected = owner.inspect(target);
|
|
441
|
+
if (!inspected.ok) return inspected;
|
|
442
|
+
if (!inspected.value.descriptor.sampled) {
|
|
443
|
+
return {
|
|
444
|
+
ok: false,
|
|
445
|
+
error: new RenderTargetCapabilityMissingError({
|
|
446
|
+
operation: 'source',
|
|
447
|
+
requested: 'sampled=true',
|
|
448
|
+
capability: 'sampled',
|
|
449
|
+
actual: 'false',
|
|
450
|
+
}),
|
|
451
|
+
};
|
|
452
|
+
}
|
|
453
|
+
if (sourceOptions.dimension !== inspected.value.descriptor.shape) {
|
|
454
|
+
return {
|
|
455
|
+
ok: false,
|
|
456
|
+
error: new RenderTargetDescriptorInvalidError({
|
|
457
|
+
field: 'dimension',
|
|
458
|
+
value: sourceOptions.dimension,
|
|
459
|
+
expected: `dimension matches ${inspected.value.descriptor.shape}`,
|
|
460
|
+
}),
|
|
461
|
+
};
|
|
462
|
+
}
|
|
463
|
+
if (
|
|
464
|
+
!Number.isInteger(sourceOptions.mipLevel) ||
|
|
465
|
+
sourceOptions.mipLevel < 0 ||
|
|
466
|
+
(inspected.value.descriptor.mipLevels === 1 && sourceOptions.mipLevel !== 0)
|
|
467
|
+
) {
|
|
468
|
+
return {
|
|
469
|
+
ok: false,
|
|
470
|
+
error: new RenderTargetDescriptorInvalidError({
|
|
471
|
+
field: 'mipLevel',
|
|
472
|
+
value: sourceOptions.mipLevel,
|
|
473
|
+
expected: 'an admitted mip level for the target',
|
|
474
|
+
}),
|
|
475
|
+
};
|
|
476
|
+
}
|
|
477
|
+
const binding = createRenderTargetMaterialSource(target, inspected.value.descriptor, {
|
|
478
|
+
...sourceOptions,
|
|
479
|
+
generation: inspected.value.generation,
|
|
480
|
+
});
|
|
481
|
+
if (!binding.ok) return binding;
|
|
482
|
+
sources.set(binding.value.source as object, binding.value);
|
|
483
|
+
return { ok: true, value: binding.value.source };
|
|
484
|
+
},
|
|
485
|
+
resolveRenderTargetTextureSource(source: RenderTargetTextureSource) {
|
|
486
|
+
const binding = sources.get(source as object) ?? resolveRenderTargetMaterialSource(source);
|
|
487
|
+
if (binding === undefined) return undefined;
|
|
488
|
+
const physical = activePhysical.get(binding.target as object);
|
|
489
|
+
if (physical === undefined) return binding;
|
|
490
|
+
const view =
|
|
491
|
+
physical.mipViews[binding.view.mipLevel] ??
|
|
492
|
+
(binding.shape === 'cube' ? physical.view : physical.resolveView);
|
|
493
|
+
if (binding.generation !== physical.generation) return binding;
|
|
494
|
+
return { ...binding, textureView: view };
|
|
495
|
+
},
|
|
496
|
+
requestTargetReadback(
|
|
497
|
+
target: RenderTarget,
|
|
498
|
+
request: RenderTargetReadbackRequest,
|
|
499
|
+
): RenderResult<RenderTargetReadbackTicket, RenderError> {
|
|
500
|
+
const inspected = owner.inspect(target);
|
|
501
|
+
if (!inspected.ok) return inspected;
|
|
502
|
+
if (!inspected.value.descriptor.readback) {
|
|
503
|
+
return {
|
|
504
|
+
ok: false,
|
|
505
|
+
error: new RenderTargetCapabilityMissingError({
|
|
506
|
+
operation: 'readback',
|
|
507
|
+
requested: 'readback=true',
|
|
508
|
+
capability: 'readback',
|
|
509
|
+
actual: 'false',
|
|
510
|
+
}),
|
|
511
|
+
};
|
|
512
|
+
}
|
|
513
|
+
if (!Number.isInteger(request.mipLevel) || request.mipLevel < 0) {
|
|
514
|
+
return {
|
|
515
|
+
ok: false,
|
|
516
|
+
error: new RenderTargetDescriptorInvalidError({
|
|
517
|
+
field: 'mipLevel',
|
|
518
|
+
value: request.mipLevel,
|
|
519
|
+
expected: 'a non-negative integer',
|
|
520
|
+
}),
|
|
521
|
+
};
|
|
522
|
+
}
|
|
523
|
+
const mipCount =
|
|
524
|
+
inspected.value.descriptor.mipLevels === 1
|
|
525
|
+
? 1
|
|
526
|
+
: Math.floor(
|
|
527
|
+
Math.log2(
|
|
528
|
+
Math.max(inspected.value.descriptor.width, inspected.value.descriptor.height),
|
|
529
|
+
),
|
|
530
|
+
) + 1;
|
|
531
|
+
if (request.mipLevel >= mipCount) {
|
|
532
|
+
return {
|
|
533
|
+
ok: false,
|
|
534
|
+
error: new RenderTargetDescriptorInvalidError({
|
|
535
|
+
field: 'mipLevel',
|
|
536
|
+
value: request.mipLevel,
|
|
537
|
+
expected: `mipLevel < ${mipCount}`,
|
|
538
|
+
}),
|
|
539
|
+
};
|
|
540
|
+
}
|
|
541
|
+
if (
|
|
542
|
+
request.face !== undefined &&
|
|
543
|
+
(!Number.isInteger(request.face) ||
|
|
544
|
+
request.face < 0 ||
|
|
545
|
+
request.face > 5 ||
|
|
546
|
+
inspected.value.descriptor.shape !== 'cube')
|
|
547
|
+
) {
|
|
548
|
+
return {
|
|
549
|
+
ok: false,
|
|
550
|
+
error: new RenderTargetDescriptorInvalidError({
|
|
551
|
+
field: 'face',
|
|
552
|
+
value: request.face,
|
|
553
|
+
expected:
|
|
554
|
+
inspected.value.descriptor.shape === 'cube'
|
|
555
|
+
? 'an integer in [0, 5]'
|
|
556
|
+
: 'omitted for a 2d target',
|
|
557
|
+
}),
|
|
558
|
+
};
|
|
559
|
+
}
|
|
560
|
+
const ticket = opaqueTicket();
|
|
561
|
+
const extent = resolveRenderTargetMipExtent(inspected.value.descriptor, request.mipLevel);
|
|
562
|
+
const buffer = options.getDevice?.()?.createBuffer({
|
|
563
|
+
label: `render-target-readback.${request.mipLevel}.${request.face ?? 0}`,
|
|
564
|
+
size:
|
|
565
|
+
Math.ceil((extent.width * bytesPerPixel(inspected.value.descriptor.format)) / 256) *
|
|
566
|
+
256 *
|
|
567
|
+
extent.height,
|
|
568
|
+
usage: GPU_BUFFER_USAGE_COPY_DST | GPU_BUFFER_USAGE_MAP_READ,
|
|
569
|
+
mappedAtCreation: false,
|
|
570
|
+
});
|
|
571
|
+
if (buffer !== undefined && !buffer.ok) {
|
|
572
|
+
return {
|
|
573
|
+
ok: false,
|
|
574
|
+
error: new RenderTargetOperationFailedError({
|
|
575
|
+
operation: 'readback',
|
|
576
|
+
stage: 'allocation',
|
|
577
|
+
generation: inspected.value.generation,
|
|
578
|
+
cause: buffer.error,
|
|
579
|
+
recovery: 'retry',
|
|
580
|
+
}),
|
|
581
|
+
};
|
|
582
|
+
}
|
|
583
|
+
const internalTicket = createRenderTargetReadbackTicket(target, {
|
|
584
|
+
deviceGeneration: inspected.value.generation,
|
|
585
|
+
mipLevel: request.mipLevel,
|
|
586
|
+
...(request.face === undefined ? {} : { face: request.face }),
|
|
587
|
+
width: extent.width,
|
|
588
|
+
height: extent.height,
|
|
589
|
+
bytesPerPixel: bytesPerPixel(inspected.value.descriptor.format),
|
|
590
|
+
});
|
|
591
|
+
if (!internalTicket.ok) return internalTicket;
|
|
592
|
+
const record = {
|
|
593
|
+
target,
|
|
594
|
+
request,
|
|
595
|
+
ticket: internalTicket.value,
|
|
596
|
+
...(buffer === undefined ? {} : { buffer: buffer.value }),
|
|
597
|
+
encoded: false,
|
|
598
|
+
} satisfies ReadbackRecord;
|
|
599
|
+
readbacks.set(ticket as object, record);
|
|
600
|
+
readbackRecords.add(record);
|
|
601
|
+
return { ok: true, value: ticket };
|
|
602
|
+
},
|
|
603
|
+
async observeTargetReadbacks(
|
|
604
|
+
receipt: RenderTargetReadbackReceipt,
|
|
605
|
+
tickets: readonly RenderTargetReadbackTicket[],
|
|
606
|
+
): Promise<RenderResult<readonly RenderTargetReadbackData[], RenderError>> {
|
|
607
|
+
const results: RenderTargetReadbackData[] = [];
|
|
608
|
+
for (const publicTicket of tickets) {
|
|
609
|
+
const record = readbacks.get(publicTicket as object);
|
|
610
|
+
if (record === undefined) {
|
|
611
|
+
return {
|
|
612
|
+
ok: false,
|
|
613
|
+
error: new RenderTargetStateInvalidError({
|
|
614
|
+
operation: 'readback',
|
|
615
|
+
reason: 'foreign-renderer',
|
|
616
|
+
state: 'destroyed',
|
|
617
|
+
generation: receipt.deviceGeneration,
|
|
618
|
+
}),
|
|
619
|
+
};
|
|
620
|
+
}
|
|
621
|
+
const inspected = owner.inspect(record.target);
|
|
622
|
+
if (!inspected.ok) return inspected;
|
|
623
|
+
if (inspected.value.state !== 'active') {
|
|
624
|
+
return {
|
|
625
|
+
ok: false,
|
|
626
|
+
error: new RenderTargetStateInvalidError({
|
|
627
|
+
operation: 'readback',
|
|
628
|
+
reason: 'uninitialized',
|
|
629
|
+
state: inspected.value.state,
|
|
630
|
+
generation: inspected.value.generation,
|
|
631
|
+
}),
|
|
632
|
+
};
|
|
633
|
+
}
|
|
634
|
+
if (inspected.value.generation !== receipt.deviceGeneration) {
|
|
635
|
+
return {
|
|
636
|
+
ok: false,
|
|
637
|
+
error: new RenderTargetStateInvalidError({
|
|
638
|
+
operation: 'readback',
|
|
639
|
+
reason: 'generation-mismatch',
|
|
640
|
+
state: inspected.value.state,
|
|
641
|
+
generation: inspected.value.generation,
|
|
642
|
+
}),
|
|
643
|
+
};
|
|
644
|
+
}
|
|
645
|
+
const bound = bindRenderTargetReadbackTicket(record.ticket, receipt);
|
|
646
|
+
if (!bound.ok) return bound;
|
|
647
|
+
let bytes = new Uint8Array(record.ticket.byteLength);
|
|
648
|
+
if (record.buffer !== undefined && typeof record.buffer.mapAsync === 'function') {
|
|
649
|
+
const mapped = await record.buffer.mapAsync(1);
|
|
650
|
+
if (!mapped.ok) {
|
|
651
|
+
return {
|
|
652
|
+
ok: false,
|
|
653
|
+
error: new RenderTargetOperationFailedError({
|
|
654
|
+
operation: 'readback',
|
|
655
|
+
stage: 'copy',
|
|
656
|
+
generation: receipt.deviceGeneration,
|
|
657
|
+
cause: mapped.error,
|
|
658
|
+
recovery: 'retry',
|
|
659
|
+
}),
|
|
660
|
+
};
|
|
661
|
+
}
|
|
662
|
+
const range = mapped.value.getMappedRange();
|
|
663
|
+
if (!range.ok) {
|
|
664
|
+
return {
|
|
665
|
+
ok: false,
|
|
666
|
+
error: new RenderTargetOperationFailedError({
|
|
667
|
+
operation: 'readback',
|
|
668
|
+
stage: 'copy',
|
|
669
|
+
generation: receipt.deviceGeneration,
|
|
670
|
+
cause: range.error,
|
|
671
|
+
recovery: 'retry',
|
|
672
|
+
}),
|
|
673
|
+
};
|
|
674
|
+
}
|
|
675
|
+
bytes = new Uint8Array(range.value.slice(0));
|
|
676
|
+
mapped.value.unmap();
|
|
677
|
+
}
|
|
678
|
+
const completed = completeRenderTargetReadback(record.ticket, receipt, bytes);
|
|
679
|
+
if (!completed.ok) return completed;
|
|
680
|
+
results.push({
|
|
681
|
+
ticket: publicTicket,
|
|
682
|
+
bytes: completed.value.bytes,
|
|
683
|
+
frameId: completed.value.frameId,
|
|
684
|
+
deviceGeneration: completed.value.deviceGeneration,
|
|
685
|
+
mipLevel: completed.value.mipLevel,
|
|
686
|
+
...(completed.value.face === undefined ? {} : { face: completed.value.face }),
|
|
687
|
+
bytesPerRow: record.ticket.bytesPerRow,
|
|
688
|
+
byteLength: record.ticket.byteLength,
|
|
689
|
+
});
|
|
690
|
+
}
|
|
691
|
+
return { ok: true, value: Object.freeze(results) };
|
|
692
|
+
},
|
|
693
|
+
destroyRenderTarget(target: RenderTarget): RenderResult<void, RenderError> {
|
|
694
|
+
const destroyed = owner.destroy(target);
|
|
695
|
+
if (destroyed.ok) {
|
|
696
|
+
destroyPhysical(options.getDevice?.(), activePhysical.get(target as object));
|
|
697
|
+
destroyPhysical(options.getDevice?.(), candidatePhysical.get(target as object));
|
|
698
|
+
activePhysical.delete(target as object);
|
|
699
|
+
candidatePhysical.delete(target as object);
|
|
700
|
+
for (const record of readbackRecords) {
|
|
701
|
+
if (record.target !== target) continue;
|
|
702
|
+
if (record.buffer !== undefined) options.getDevice?.()?.destroyBuffer(record.buffer);
|
|
703
|
+
readbacks.delete(record.ticket as object);
|
|
704
|
+
readbackRecords.delete(record);
|
|
705
|
+
}
|
|
706
|
+
targets.delete(target);
|
|
707
|
+
}
|
|
708
|
+
return destroyed;
|
|
709
|
+
},
|
|
710
|
+
beginFrame(): void {
|
|
711
|
+
if (disposed) return;
|
|
712
|
+
for (const target of targets) {
|
|
713
|
+
const inspected = owner.inspect(target);
|
|
714
|
+
if (
|
|
715
|
+
!inspected.ok ||
|
|
716
|
+
inspected.value.state === 'active' ||
|
|
717
|
+
inspected.value.state === 'candidate'
|
|
718
|
+
) {
|
|
719
|
+
continue;
|
|
720
|
+
}
|
|
721
|
+
stagePhysical(target);
|
|
722
|
+
}
|
|
723
|
+
},
|
|
724
|
+
onFrameSubmitted(completed = Promise.resolve({ ok: true, value: undefined } as const)): void {
|
|
725
|
+
if (disposed) return;
|
|
726
|
+
const submittedTargets = [...staged];
|
|
727
|
+
staged.clear();
|
|
728
|
+
void completed.then((result) => {
|
|
729
|
+
for (const target of submittedTargets) {
|
|
730
|
+
const candidate = owner.inspect(target);
|
|
731
|
+
if (!candidate.ok || candidate.value.candidate === undefined) continue;
|
|
732
|
+
if (!result.ok) {
|
|
733
|
+
owner.rejectCandidate(target, candidate.value.candidate.generation, 'submit');
|
|
734
|
+
destroyPhysical(options.getDevice?.(), candidatePhysical.get(target as object));
|
|
735
|
+
candidatePhysical.delete(target as object);
|
|
736
|
+
continue;
|
|
737
|
+
}
|
|
738
|
+
// A progressive CubeCamera writes several faces into one physical
|
|
739
|
+
// candidate across multiple submissions. Do not publish that
|
|
740
|
+
// partially-written generation as active: the next face would then
|
|
741
|
+
// bind the same texture as both a sampled source and an attachment.
|
|
742
|
+
// Keep the target in the staged queue so the next accepted frame (or
|
|
743
|
+
// this same completion callback after the final face) retries the
|
|
744
|
+
// publication check.
|
|
745
|
+
if (options.canPromoteTarget?.(target) === false) {
|
|
746
|
+
staged.add(target);
|
|
747
|
+
continue;
|
|
748
|
+
}
|
|
749
|
+
const generation = candidate.value.candidate.generation;
|
|
750
|
+
const physical = candidatePhysical.get(target as object);
|
|
751
|
+
if (physical === undefined) {
|
|
752
|
+
owner.rejectCandidate(target, generation, 'submit');
|
|
753
|
+
continue;
|
|
754
|
+
}
|
|
755
|
+
const promoted = owner.promote(target, generation);
|
|
756
|
+
if (!promoted.ok) {
|
|
757
|
+
destroyPhysical(options.getDevice?.(), physical);
|
|
758
|
+
candidatePhysical.delete(target as object);
|
|
759
|
+
continue;
|
|
760
|
+
}
|
|
761
|
+
const previous = activePhysical.get(target as object);
|
|
762
|
+
activePhysical.set(target as object, physical as RenderTargetPhysical);
|
|
763
|
+
candidatePhysical.delete(target as object);
|
|
764
|
+
destroyPhysical(options.getDevice?.(), previous);
|
|
765
|
+
}
|
|
766
|
+
});
|
|
767
|
+
},
|
|
768
|
+
getPhysicalTarget(target: RenderTarget): RenderTargetPhysical | undefined {
|
|
769
|
+
return candidatePhysical.get(target as object) ?? activePhysical.get(target as object);
|
|
770
|
+
},
|
|
771
|
+
encodePendingReadbacks(encoder: RhiCommandEncoder, faces?: readonly number[]): void {
|
|
772
|
+
for (const record of readbackRecords) {
|
|
773
|
+
if (record.encoded || record.buffer === undefined) continue;
|
|
774
|
+
if (
|
|
775
|
+
faces !== undefined &&
|
|
776
|
+
record.ticket.face !== undefined &&
|
|
777
|
+
!faces.includes(record.ticket.face)
|
|
778
|
+
) {
|
|
779
|
+
continue;
|
|
780
|
+
}
|
|
781
|
+
const candidate = candidatePhysical.get(record.target as object);
|
|
782
|
+
const physical =
|
|
783
|
+
faces !== undefined &&
|
|
784
|
+
candidate !== undefined &&
|
|
785
|
+
record.ticket.face !== undefined &&
|
|
786
|
+
faces.includes(record.ticket.face)
|
|
787
|
+
? candidate
|
|
788
|
+
: activePhysical.get(record.target as object);
|
|
789
|
+
if (physical === undefined) continue;
|
|
790
|
+
const source = physical.resolveTexture ?? physical.texture;
|
|
791
|
+
encoder.copyTextureToBuffer(
|
|
792
|
+
{
|
|
793
|
+
texture: source,
|
|
794
|
+
mipLevel: record.ticket.mipLevel,
|
|
795
|
+
origin: { x: 0, y: 0, z: record.ticket.face ?? 0 },
|
|
796
|
+
},
|
|
797
|
+
{
|
|
798
|
+
buffer: record.buffer,
|
|
799
|
+
bytesPerRow: record.ticket.bytesPerRow,
|
|
800
|
+
rowsPerImage: record.ticket.height,
|
|
801
|
+
},
|
|
802
|
+
[record.ticket.width, record.ticket.height, 1],
|
|
803
|
+
);
|
|
804
|
+
record.encoded = true;
|
|
805
|
+
}
|
|
806
|
+
},
|
|
807
|
+
recover(): void {
|
|
808
|
+
if (disposed) return;
|
|
809
|
+
const generation = currentGeneration();
|
|
810
|
+
for (const target of targets) {
|
|
811
|
+
const inspected = owner.inspect(target);
|
|
812
|
+
if (!inspected.ok || inspected.value.state !== 'active') continue;
|
|
813
|
+
destroyPhysical(options.getDevice?.(), activePhysical.get(target as object));
|
|
814
|
+
destroyPhysical(options.getDevice?.(), candidatePhysical.get(target as object));
|
|
815
|
+
activePhysical.delete(target as object);
|
|
816
|
+
candidatePhysical.delete(target as object);
|
|
817
|
+
for (const record of readbackRecords) {
|
|
818
|
+
if (record.target !== target) continue;
|
|
819
|
+
if (record.buffer !== undefined) options.getDevice?.()?.destroyBuffer(record.buffer);
|
|
820
|
+
readbacks.delete(record.ticket as object);
|
|
821
|
+
readbackRecords.delete(record);
|
|
822
|
+
}
|
|
823
|
+
const begun = owner.beginRecovery(target, generation);
|
|
824
|
+
if (begun.ok) owner.finishRecovery(target);
|
|
825
|
+
}
|
|
826
|
+
},
|
|
827
|
+
dispose(): void {
|
|
828
|
+
disposed = true;
|
|
829
|
+
for (const target of [...targets]) {
|
|
830
|
+
destroyPhysical(options.getDevice?.(), activePhysical.get(target as object));
|
|
831
|
+
destroyPhysical(options.getDevice?.(), candidatePhysical.get(target as object));
|
|
832
|
+
for (const record of readbackRecords) {
|
|
833
|
+
if (record.target !== target) continue;
|
|
834
|
+
if (record.buffer !== undefined) options.getDevice?.()?.destroyBuffer(record.buffer);
|
|
835
|
+
readbacks.delete(record.ticket as object);
|
|
836
|
+
readbackRecords.delete(record);
|
|
837
|
+
}
|
|
838
|
+
activePhysical.delete(target as object);
|
|
839
|
+
candidatePhysical.delete(target as object);
|
|
840
|
+
owner.destroy(target);
|
|
841
|
+
}
|
|
842
|
+
targets.clear();
|
|
843
|
+
staged.clear();
|
|
844
|
+
readbackRecords.clear();
|
|
845
|
+
},
|
|
846
|
+
});
|
|
847
|
+
}
|