@forgeax/engine-render 0.1.29 → 0.1.31
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 +248 -21
- package/dist/assembly/atmosphere-shader-prewarm.d.ts +1 -1
- package/dist/assembly/atmosphere-shader-prewarm.d.ts.map +1 -1
- package/dist/assembly/device-feature-admission.d.ts +4 -3
- package/dist/assembly/device-feature-admission.d.ts.map +1 -1
- package/dist/assembly/dynamic-geometry-host.d.ts +6 -0
- package/dist/assembly/dynamic-geometry-host.d.ts.map +1 -1
- package/dist/assembly/host-contract.d.ts +6 -0
- package/dist/assembly/host-contract.d.ts.map +1 -1
- package/dist/assembly/material/assembly.d.ts +26 -3
- package/dist/assembly/material/assembly.d.ts.map +1 -1
- package/dist/assembly/material/pipeline-helpers.d.ts +24 -0
- package/dist/assembly/material/pipeline-helpers.d.ts.map +1 -0
- package/dist/assembly/material-shader-policy.d.ts.map +1 -1
- package/dist/assembly/recovery/device-loss-fanout.d.ts.map +1 -1
- package/dist/assembly/recovery/recovery-attempt.d.ts +1 -6
- package/dist/assembly/recovery/recovery-attempt.d.ts.map +1 -1
- package/dist/assembly/recovery/renderer-recover.d.ts +1 -0
- package/dist/assembly/recovery/renderer-recover.d.ts.map +1 -1
- package/dist/assembly/renderer-facade.d.ts.map +1 -1
- package/dist/assembly/shader-prewarm-policy.d.ts +1 -1
- package/dist/assembly/shader-prewarm-policy.d.ts.map +1 -1
- package/dist/assembly/webgpu-ready.d.ts +1 -1
- package/dist/assembly/webgpu-ready.d.ts.map +1 -1
- package/dist/assembly/webgpu-renderer.d.ts.map +1 -1
- package/dist/capture/scene-projection.d.ts +41 -0
- package/dist/capture/scene-projection.d.ts.map +1 -0
- package/dist/{chunk-BQVQOQJH.mjs → chunk-7MQ3XBSP.mjs} +20 -14
- package/dist/chunk-7MQ3XBSP.mjs.map +1 -0
- package/dist/{chunk-S4DNKQYQ.mjs → chunk-C3DDSXYK.mjs} +86 -33
- package/dist/chunk-C3DDSXYK.mjs.map +1 -0
- package/dist/{chunk-BTWH7BP4.mjs → chunk-FUUO4UND.mjs} +73 -29
- package/dist/chunk-FUUO4UND.mjs.map +1 -0
- package/dist/{chunk-NRNXBLIJ.mjs → chunk-JRBDO2KB.mjs} +46 -6
- package/dist/chunk-JRBDO2KB.mjs.map +1 -0
- package/dist/{chunk-NICXSHAT.mjs → chunk-MDQJPY3T.mjs} +8 -6
- package/dist/chunk-MDQJPY3T.mjs.map +1 -0
- package/dist/{chunk-JQTSEI3Z.mjs → chunk-NO4WZCAH.mjs} +3 -3
- package/dist/chunk-NO4WZCAH.mjs.map +1 -0
- package/dist/{chunk-FUODTTIA.mjs → chunk-PSEQ6QPH.mjs} +621 -108
- package/dist/chunk-PSEQ6QPH.mjs.map +1 -0
- package/dist/{chunk-33XZFTQU.mjs → chunk-S5UE2T5P.mjs} +48 -6
- package/dist/chunk-S5UE2T5P.mjs.map +1 -0
- package/dist/components/directional-light.d.ts +2 -2
- package/dist/components/dynamic-resolution.d.ts +15 -0
- package/dist/components/dynamic-resolution.d.ts.map +1 -0
- package/dist/components/index.d.ts +1 -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 +1 -0
- package/dist/components/reflection-probe.d.ts.map +1 -1
- package/dist/components/skylight.d.ts +4 -1
- package/dist/components/skylight.d.ts.map +1 -1
- package/dist/construct-renderer.mjs +2172 -796
- package/dist/construct-renderer.mjs.map +1 -1
- package/dist/device/device-scope.d.ts +2 -0
- package/dist/device/device-scope.d.ts.map +1 -1
- package/dist/device/gpu-residency.d.ts +2 -2
- package/dist/device/gpu-residency.d.ts.map +1 -1
- package/dist/dynamic-geometry.d.ts.map +1 -1
- package/dist/environment/background.d.ts +3 -2
- package/dist/environment/background.d.ts.map +1 -1
- package/dist/environment/ibl.d.ts +11 -0
- package/dist/environment/ibl.d.ts.map +1 -0
- package/dist/environment/storage.d.ts +14 -0
- package/dist/environment/storage.d.ts.map +1 -0
- package/dist/errors/gpu-driven.d.ts +2 -2
- package/dist/errors/gpu-driven.d.ts.map +1 -1
- package/dist/errors/render.d.ts +35 -1
- package/dist/errors/render.d.ts.map +1 -1
- package/dist/extract/camera.d.ts.map +1 -1
- package/dist/extract/contracts.d.ts +7 -0
- package/dist/extract/contracts.d.ts.map +1 -1
- package/dist/extract/gpu-driven.d.ts +18 -1
- package/dist/extract/gpu-driven.d.ts.map +1 -1
- package/dist/gpu-driven/batch-topology.d.ts.map +1 -1
- package/dist/gpu-driven/material-artifacts.d.ts +24 -0
- package/dist/gpu-driven/material-artifacts.d.ts.map +1 -0
- package/dist/gpu-driven/material-bindings.d.ts +7 -0
- package/dist/gpu-driven/material-bindings.d.ts.map +1 -0
- package/dist/gpu-driven/prepared-draw.d.ts +2 -0
- package/dist/gpu-driven/prepared-draw.d.ts.map +1 -1
- package/dist/gpu-driven/production-raster.d.ts +27 -6
- package/dist/gpu-driven/production-raster.d.ts.map +1 -1
- package/dist/gpu-resource.d.ts +5 -2
- package/dist/gpu-resource.d.ts.map +1 -1
- package/dist/gpu-scene-schema.d.ts.map +1 -1
- package/dist/gpu-scene.d.ts.map +1 -1
- package/dist/hdrp-buffers.d.ts +3 -0
- package/dist/hdrp-buffers.d.ts.map +1 -1
- package/dist/ibl/IblPipelineCache.d.ts +2 -0
- package/dist/ibl/IblPipelineCache.d.ts.map +1 -1
- package/dist/ibl/skylight-bind-group.d.ts +3 -1
- package/dist/ibl/skylight-bind-group.d.ts.map +1 -1
- package/dist/index.d.ts +83 -81
- package/dist/index.d.ts.map +1 -1
- package/dist/index.mjs +7 -5
- package/dist/index.mjs.map +1 -1
- package/dist/inspection-types.d.ts +16 -1
- package/dist/inspection-types.d.ts.map +1 -1
- package/dist/internal.mjs +6 -6
- package/dist/material-row.d.ts +10 -0
- package/dist/material-row.d.ts.map +1 -1
- package/dist/pbr-pipeline.d.ts +3 -1
- package/dist/pbr-pipeline.d.ts.map +1 -1
- package/dist/pipeline/render-extent.d.ts +51 -0
- package/dist/pipeline/render-extent.d.ts.map +1 -0
- package/dist/pipeline/standard-build-context.d.ts +7 -0
- package/dist/pipeline/standard-build-context.d.ts.map +1 -0
- package/dist/pipeline/standard-forward-lane.d.ts +3 -2
- package/dist/pipeline/standard-forward-lane.d.ts.map +1 -1
- package/dist/pipeline/standard-pipeline.d.ts.map +1 -1
- package/dist/pipeline/standard-post.d.ts +1 -1
- package/dist/pipeline/standard-post.d.ts.map +1 -1
- package/dist/pipeline/standard-profile.d.ts +2 -1
- package/dist/pipeline/standard-profile.d.ts.map +1 -1
- package/dist/pipeline-builder.d.ts +3 -1
- package/dist/pipeline-builder.d.ts.map +1 -1
- package/dist/plugin.d.ts.map +1 -1
- package/dist/post-process-errors.d.ts +9 -2
- package/dist/post-process-errors.d.ts.map +1 -1
- package/dist/prepare/extended-lighting/resources.d.ts +3 -3
- package/dist/record/frame-lighting.d.ts.map +1 -1
- package/dist/record/frame-snapshot.d.ts +3 -8
- package/dist/record/frame-snapshot.d.ts.map +1 -1
- package/dist/record/frame.d.ts +3 -2
- package/dist/record/frame.d.ts.map +1 -1
- package/dist/record/main-pass-geometry.d.ts +7 -2
- package/dist/record/main-pass-geometry.d.ts.map +1 -1
- package/dist/record/main-pass-material.d.ts +6 -3
- package/dist/record/main-pass-material.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/prepared-material-bindings.d.ts.map +1 -1
- package/dist/record/recovery-pipeline.d.ts +9 -1
- package/dist/record/recovery-pipeline.d.ts.map +1 -1
- package/dist/record/render-context.d.ts +34 -3
- package/dist/record/render-context.d.ts.map +1 -1
- package/dist/record/shadow-pass.d.ts +2 -2
- package/dist/record/shadow-pass.d.ts.map +1 -1
- package/dist/record/typed-frame-graph.d.ts +5 -2
- package/dist/record/typed-frame-graph.d.ts.map +1 -1
- package/dist/recovery/render-system-candidate.d.ts.map +1 -1
- package/dist/reflection/background.d.ts +14 -0
- package/dist/reflection/background.d.ts.map +1 -0
- package/dist/reflection/filter.d.ts.map +1 -1
- package/dist/reflection/projection.d.ts +1 -0
- package/dist/reflection/projection.d.ts.map +1 -1
- package/dist/reflection/record-owner.d.ts +4 -2
- package/dist/reflection/record-owner.d.ts.map +1 -1
- package/dist/render-contract.d.ts +47 -32
- 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 +17 -1
- package/dist/render-pipeline.d.ts.map +1 -1
- package/dist/render-system-extract-tail.d.ts +9 -2
- package/dist/render-system-extract-tail.d.ts.map +1 -1
- package/dist/render-system-extract.d.ts +29 -2
- package/dist/render-system-extract.d.ts.map +1 -1
- package/dist/render-system.d.ts.map +1 -1
- package/dist/scene/render-scene.d.ts +2 -0
- package/dist/scene/render-scene.d.ts.map +1 -1
- package/dist/ssao-config.d.ts +8 -6
- package/dist/ssao-config.d.ts.map +1 -1
- package/dist/ssr/graph.d.ts.map +1 -1
- package/dist/temporal/gpu.d.ts.map +1 -1
- package/dist/temporal/index.mjs +5 -5
- package/dist/temporal/standard-scene-data.d.ts +2 -1
- package/dist/temporal/standard-scene-data.d.ts.map +1 -1
- package/dist/temporal/target-coverage-attachment.d.ts +15 -0
- package/dist/temporal/target-coverage-attachment.d.ts.map +1 -0
- package/dist/temporal/temporal-view.d.ts +6 -2
- package/dist/temporal/temporal-view.d.ts.map +1 -1
- package/dist/temporal/view.d.ts +6 -0
- package/dist/temporal/view.d.ts.map +1 -1
- package/dist/typed-render-graph-primitives.d.ts +6 -0
- package/dist/typed-render-graph-primitives.d.ts.map +1 -1
- package/dist/volume/component.d.ts +1 -0
- package/dist/volume/component.d.ts.map +1 -1
- package/package.json +21 -21
- package/src/__tests__/capture-scene-projection.unit.test.ts +24 -0
- package/src/__tests__/device-feature-admission.unit.test.ts +15 -24
- package/src/__tests__/device-loss-fanout.unit.test.ts +43 -0
- package/src/__tests__/dynamic-geometry-batch.unit.test.ts +157 -0
- package/src/__tests__/dynamic-geometry.unit.test.ts +36 -0
- package/src/__tests__/dynamic-resolution-plugin.integration.test.ts +81 -0
- package/src/__tests__/factory-contract.integration.test.ts +164 -1
- package/src/__tests__/frame-observation.contract.test.ts +21 -0
- package/src/__tests__/gpu-driven-baseline.characterization.test.ts +1 -1
- package/src/__tests__/gpu-driven-batch-topology-pbr.unit.test.ts +20 -1
- package/src/__tests__/gpu-driven-lod-cache.unit.test.ts +0 -3
- package/src/__tests__/gpu-driven-mesh-world-identity.unit.test.ts +0 -3
- package/src/__tests__/gpu-driven-pbr.dawn.test.ts +11 -6
- package/src/__tests__/gpu-driven-production.integration.test.ts +13 -25
- package/src/__tests__/gpu-driven-view.unit.test.ts +1 -0
- package/src/__tests__/gpu-pass-timing-browser-runner.ts +15 -0
- package/src/__tests__/gpu-pass-timing.browser.test.ts +14 -1
- package/src/__tests__/gpu-resource-scope.unit.test.ts +71 -0
- package/src/__tests__/gpu-scene.unit.test.ts +55 -1
- package/src/__tests__/materials-standard-contract.unit.test.ts +5 -1
- package/src/__tests__/mesh-submission-lifetime.unit.test.ts +8 -0
- package/src/__tests__/morph-neutral-admission.unit.test.ts +19 -0
- package/src/__tests__/physical-clearcoat.integration.test.ts +6 -1
- package/src/__tests__/post-process-error-policy-owner.unit.test.ts +6 -5
- package/src/__tests__/prepared-gpu-driven-pbr.integration.test.ts +216 -5
- package/src/__tests__/reflection-fallback-async-publication.unit.test.ts +68 -1
- package/src/__tests__/reflection-probe-authoring.unit.test.ts +12 -10
- package/src/__tests__/reflection-probe-box.dawn.test.ts +71 -0
- package/src/__tests__/reflection-probe-filter.unit.test.ts +9 -0
- package/src/__tests__/reflection-probe-orientation.dawn.test.ts +294 -0
- package/src/__tests__/reflection-probe-record-owner.characterization.unit.test.ts +5 -15
- package/src/__tests__/reflection-probe-updates.unit.test.ts +129 -0
- package/src/__tests__/render-error-code-owner.test-d.ts +3 -0
- package/src/__tests__/render-error-detail-ssot.test-d.ts +5 -1
- package/src/__tests__/render-extent.unit.test.ts +63 -0
- package/src/__tests__/render-scene-projection.unit.test.ts +3 -2
- package/src/__tests__/renderer-factory-material-contract.unit.test.ts +173 -9
- package/src/__tests__/shader-manifest-fixture.ts +6 -0
- package/src/__tests__/skinned-shadow-caster.test.ts +8 -1
- package/src/__tests__/specular-environment-scale.dawn.test.ts +4 -2
- package/src/__tests__/ssao-config.unit.test.ts +7 -0
- package/src/__tests__/ssao-surface.dawn.test.ts +252 -0
- package/src/__tests__/ssr-cube-silhouette.dawn.test.ts +270 -0
- package/src/__tests__/ssr-gpu-dispatch.browser.test.ts +51 -43
- package/src/__tests__/ssr-gpu-dispatch.dawn.test.ts +4 -0
- package/src/__tests__/ssr-gpu-dispatch.ts +10 -5
- package/src/__tests__/ssr-graph-topology.unit.test.ts +2 -2
- package/src/__tests__/ssr-hiz.browser.test.ts +1 -1
- package/src/__tests__/ssr-hiz.dawn.test.ts +1 -1
- package/src/__tests__/ssr-spatial.integration.test.ts +1 -1
- package/src/__tests__/standard-cluster-variant-resolution.unit.test.ts +40 -0
- package/src/__tests__/standard-pbr-artifact-assembly.unit.test.ts +238 -1
- package/src/__tests__/standard-profile-oracle.unit.test.ts +27 -0
- package/src/__tests__/taa-coverage-edge.dawn.test.ts +6 -0
- package/src/__tests__/taa-neighborhood-equivalence.dawn.test.ts +5 -1
- package/src/__tests__/taa-stability-feedback.ts +1 -0
- package/src/__tests__/temporal-reset-matrix.unit.test.ts +2 -2
- package/src/__tests__/temporal-view.unit.test.ts +17 -0
- package/src/__tests__/transmission-prewarm.unit.test.ts +57 -0
- package/src/__tests__/volumetric-fog-stage-readback.dawn.test.ts +62 -13
- package/src/__tests__/volumetric-fog-topology.unit.test.ts +7 -7
- package/src/assembly/atmosphere-shader-prewarm.ts +3 -2
- package/src/assembly/device-feature-admission.ts +9 -4
- package/src/assembly/dynamic-geometry-host.ts +236 -163
- package/src/assembly/host-contract.ts +9 -0
- package/src/assembly/material/assembly.ts +350 -6
- package/src/assembly/material/pipeline-helpers.ts +100 -0
- package/src/assembly/material-shader-policy.ts +39 -18
- package/src/assembly/recovery/device-loss-fanout.ts +5 -0
- package/src/assembly/recovery/recovery-attempt.ts +2 -29
- package/src/assembly/recovery/renderer-recover.ts +6 -9
- package/src/assembly/renderer-facade.ts +22 -1
- package/src/assembly/shader-prewarm-policy.ts +14 -1
- package/src/assembly/webgpu-ready.ts +28 -19
- package/src/assembly/webgpu-renderer.ts +95 -95
- package/src/capture/scene-projection.ts +37 -0
- package/src/components/__tests__/dynamic-resolution-schema.unit.test.ts +65 -0
- package/src/components/__tests__/light-radius.integration.test.ts +59 -0
- package/src/components/directional-light.ts +3 -3
- package/src/components/dynamic-resolution.ts +67 -0
- package/src/components/index.ts +1 -0
- package/src/components/light-helpers.ts +6 -1
- package/src/components/reflection-probe.ts +1 -0
- package/src/components/skylight.ts +4 -1
- package/src/device/device-scope.ts +13 -7
- package/src/device/gpu-residency.ts +11 -11
- package/src/dynamic-geometry.ts +13 -8
- package/src/environment/background.ts +30 -12
- package/src/environment/ibl.ts +211 -0
- package/src/environment/storage.ts +63 -0
- package/src/errors/gpu-driven.ts +10 -3
- package/src/errors/render.ts +64 -0
- package/src/extract/camera.ts +12 -1
- package/src/extract/contracts.ts +10 -0
- package/src/extract/gpu-driven.ts +72 -17
- package/src/gpu-driven/batch-topology.ts +33 -11
- package/src/gpu-driven/material-artifacts.ts +179 -0
- package/src/gpu-driven/material-bindings.ts +41 -0
- package/src/gpu-driven/prepared-draw.ts +13 -2
- package/src/gpu-driven/production-raster.ts +681 -164
- package/src/gpu-resource.ts +21 -2
- package/src/gpu-scene-schema.ts +11 -2
- package/src/gpu-scene.ts +14 -3
- package/src/hdrp-buffers.ts +69 -0
- package/src/ibl/IblPipelineCache.ts +5 -0
- package/src/ibl/skylight-bind-group.ts +27 -17
- package/src/index.ts +92 -81
- package/src/inspection-types.ts +16 -1
- package/src/material-row.ts +60 -11
- package/src/pbr-pipeline.ts +13 -2
- package/src/pipeline/render-extent.ts +111 -0
- package/src/pipeline/standard-build-context.ts +7 -0
- package/src/pipeline/standard-forward-lane.ts +41 -24
- package/src/pipeline/standard-pipeline.ts +47 -18
- package/src/pipeline/standard-post.ts +4 -0
- package/src/pipeline/standard-profile.ts +2 -1
- package/src/pipeline-builder.ts +12 -3
- package/src/plugin.ts +4 -0
- package/src/post-process-errors.ts +26 -18
- package/src/prepare/__tests__/extended-lighting-capability.unit.test.ts +2 -2
- package/src/prepare/extended-lighting/resources.ts +3 -3
- package/src/record/__tests__/main-pass-geometry.unit.test.ts +68 -0
- package/src/record/__tests__/material-bg-cache.unit.test.ts +45 -0
- package/src/record/__tests__/material-slot-plan.unit.test.ts +9 -0
- package/src/record/__tests__/recovery-pipeline.unit.test.ts +47 -1
- package/src/record/__tests__/sprite-material-abi.unit.test.ts +7 -3
- package/src/record/__tests__/temporal-payload.unit.test.ts +2 -0
- package/src/record/frame-lighting.ts +3 -1
- package/src/record/frame-snapshot.ts +13 -11
- package/src/record/frame.ts +150 -74
- package/src/record/main-pass-geometry.ts +60 -9
- package/src/record/main-pass-material.ts +47 -19
- package/src/record/main-pass.ts +63 -4
- package/src/record/prepared-material-bindings.ts +4 -0
- package/src/record/recovery-pipeline.ts +56 -0
- package/src/record/render-context.ts +34 -3
- package/src/record/shadow-pass.ts +187 -50
- package/src/record/typed-frame-graph.ts +60 -3
- package/src/record/view-ubo.ts +1 -1
- package/src/recovery/render-system-candidate.ts +54 -11
- package/src/reflection/background.ts +151 -0
- package/src/reflection/filter.ts +3 -0
- package/src/reflection/projection.ts +16 -6
- package/src/reflection/record-owner.ts +282 -86
- package/src/render-contract.ts +50 -32
- package/src/render-graph-primitives.ts +28 -3
- package/src/render-pipeline.ts +20 -1
- package/src/render-system-extract-tail.ts +23 -3
- package/src/render-system-extract.ts +127 -42
- package/src/render-system.ts +35 -7
- package/src/scene/render-scene.ts +8 -0
- package/src/ssao-config.ts +25 -8
- package/src/ssr/graph.ts +78 -58
- package/src/temporal/gpu.ts +5 -0
- package/src/temporal/standard-scene-data.ts +7 -1
- package/src/temporal/target-coverage-attachment.ts +72 -0
- package/src/temporal/temporal-view.ts +10 -4
- package/src/temporal/view.ts +12 -2
- package/src/transmission/__tests__/standard-transmission.dawn.test.ts +24 -9
- package/src/typed-render-graph-primitives.ts +38 -0
- package/src/volume/component.ts +1 -0
- package/src/volume/passes.ts +3 -3
- package/dist/chunk-33XZFTQU.mjs.map +0 -1
- package/dist/chunk-BQVQOQJH.mjs.map +0 -1
- package/dist/chunk-BTWH7BP4.mjs.map +0 -1
- package/dist/chunk-FUODTTIA.mjs.map +0 -1
- package/dist/chunk-JQTSEI3Z.mjs.map +0 -1
- package/dist/chunk-NICXSHAT.mjs.map +0 -1
- package/dist/chunk-NRNXBLIJ.mjs.map +0 -1
- package/dist/chunk-S4DNKQYQ.mjs.map +0 -1
|
@@ -9,6 +9,8 @@ import type {
|
|
|
9
9
|
TextureFormat,
|
|
10
10
|
TextureView,
|
|
11
11
|
} from '@forgeax/engine-rhi';
|
|
12
|
+
import { RhiError } from '@forgeax/engine-rhi';
|
|
13
|
+
import { toShared } from '@forgeax/engine-types';
|
|
12
14
|
import { buildCubeCameraFaceViews } from '../capture/cube-views';
|
|
13
15
|
import {
|
|
14
16
|
createFaceUniformsBuffer,
|
|
@@ -30,7 +32,6 @@ import {
|
|
|
30
32
|
createIblPipelines,
|
|
31
33
|
getOrCreateIblCache,
|
|
32
34
|
PREFILTER_MIP_LEVELS,
|
|
33
|
-
PREFILTER_SIZE,
|
|
34
35
|
} from '../ibl/IblPipelineCache';
|
|
35
36
|
import type {
|
|
36
37
|
ReflectionFallbackReadbackReceipt,
|
|
@@ -42,7 +43,8 @@ import type { ReflectionProbeRecordState, RenderSystemInternals } from '../recor
|
|
|
42
43
|
import type { ReflectionProbeGraphWork } from '../record/typed-frame-graph';
|
|
43
44
|
import { REFLECTION_PROBE_VIEW_SLOT_BASE, VIEW_UNIFORM_SLOT_STRIDE } from '../record/view-ubo';
|
|
44
45
|
import type { CameraSnapshot } from '../render-contract';
|
|
45
|
-
import type { SkylightSnapshot } from '../render-system-extract';
|
|
46
|
+
import type { SkyboxSnapshot, SkylightSnapshot } from '../render-system-extract';
|
|
47
|
+
import { createProbeBackgroundResources, type ProbeBackgroundResources } from './background';
|
|
46
48
|
import {
|
|
47
49
|
advanceProbeFilter,
|
|
48
50
|
commitProbeFilterStep,
|
|
@@ -76,6 +78,12 @@ type ProbeCubeSet = {
|
|
|
76
78
|
|
|
77
79
|
type ProbeGpuResource = {
|
|
78
80
|
fact: ReflectionProbeFact;
|
|
81
|
+
captureFact: ReflectionProbeFact;
|
|
82
|
+
diffusePayload: readonly number[];
|
|
83
|
+
captureSceneRevision: string;
|
|
84
|
+
captureStartedFrame: number;
|
|
85
|
+
lastCompletedFrame: number;
|
|
86
|
+
activeFact?: ReflectionProbeFact;
|
|
79
87
|
index: number;
|
|
80
88
|
filter: ProbeFilterState;
|
|
81
89
|
rawFaceCursor: number;
|
|
@@ -93,6 +101,7 @@ type ProbeGpuResource = {
|
|
|
93
101
|
};
|
|
94
102
|
|
|
95
103
|
type ProbeSharedResources = {
|
|
104
|
+
readonly background: ProbeBackgroundResources | undefined;
|
|
96
105
|
readonly faceUniforms: Buffer;
|
|
97
106
|
readonly prefilterUniforms: Buffer;
|
|
98
107
|
readonly vertexBuffer: Buffer;
|
|
@@ -126,6 +135,8 @@ export class ReflectionProbeRecordOwner {
|
|
|
126
135
|
private lastAcceptedCount = 0;
|
|
127
136
|
private lastScheduledRawFaces = 0;
|
|
128
137
|
private lastScheduledFilteredSteps = 0;
|
|
138
|
+
private workCursor = 0;
|
|
139
|
+
private currentFrame = 0;
|
|
129
140
|
private lastSelection: ReflectionProbeSelectionInspection = { kind: 'skylight' };
|
|
130
141
|
private outputFormat: TextureFormat;
|
|
131
142
|
private fallbackFormatAvailable: boolean;
|
|
@@ -171,6 +182,22 @@ export class ReflectionProbeRecordOwner {
|
|
|
171
182
|
if (resource.active !== undefined) activeCount += 1;
|
|
172
183
|
}
|
|
173
184
|
return {
|
|
185
|
+
updates: [...this.resources.values()].map((resource) => ({
|
|
186
|
+
worldId: resource.fact.worldId,
|
|
187
|
+
entityKey: resource.fact.entityKey,
|
|
188
|
+
intent: resource.fact.updateIntent ?? 'once',
|
|
189
|
+
activeGeneration: resource.filter.activeGeneration,
|
|
190
|
+
requestedRevision: resource.fact.revision,
|
|
191
|
+
capturedRevision: resource.captureFact.revision,
|
|
192
|
+
pending: resource.filter.cursor < resource.filter.faceCount * resource.filter.mipCount,
|
|
193
|
+
captureStartedFrame: resource.captureStartedFrame,
|
|
194
|
+
lastCompletedFrame: resource.lastCompletedFrame,
|
|
195
|
+
latencyFrames:
|
|
196
|
+
resource.lastCompletedFrame < resource.captureStartedFrame
|
|
197
|
+
? undefined
|
|
198
|
+
: resource.lastCompletedFrame - resource.captureStartedFrame,
|
|
199
|
+
})),
|
|
200
|
+
workBudgetPerFrame: 1,
|
|
174
201
|
selection: this.lastSelection,
|
|
175
202
|
factCount: this.lastFactCount,
|
|
176
203
|
acceptedCount: this.lastAcceptedCount,
|
|
@@ -304,7 +331,8 @@ export class ReflectionProbeRecordOwner {
|
|
|
304
331
|
if (factory === undefined) return;
|
|
305
332
|
const attempt = this.pipelineWarmupAttempts + 1;
|
|
306
333
|
this.pipelineWarmupAttempts = attempt;
|
|
307
|
-
|
|
334
|
+
const device = this.internals.device;
|
|
335
|
+
const warmup = createIblPipelines(
|
|
308
336
|
this.internals.deviceScope,
|
|
309
337
|
this.internals.device,
|
|
310
338
|
(device, descriptor) => {
|
|
@@ -317,20 +345,42 @@ export class ReflectionProbeRecordOwner {
|
|
|
317
345
|
: this.internals.createShaderModule(device, labeled);
|
|
318
346
|
},
|
|
319
347
|
this.outputFormat,
|
|
320
|
-
)
|
|
321
|
-
|
|
322
|
-
this.
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
348
|
+
)
|
|
349
|
+
.then(async (result) => {
|
|
350
|
+
if (this.pipelineWarmup !== warmup) return;
|
|
351
|
+
if (!result.ok) {
|
|
352
|
+
this.pipelineWarmupFailure = `${result.error.code}: ${result.error.hint}`;
|
|
353
|
+
console.warn('[forgeax] ReflectionProbe IBL warmup retry', this.pipelineWarmupFailure);
|
|
354
|
+
this.pipelineWarmup = undefined;
|
|
355
|
+
return;
|
|
356
|
+
}
|
|
357
|
+
const background = await createProbeBackgroundResources(this.internals, this.outputFormat);
|
|
358
|
+
if (this.pipelineWarmup !== warmup) {
|
|
359
|
+
if (background !== undefined) device.destroyBuffer(background.uniform);
|
|
360
|
+
return;
|
|
361
|
+
}
|
|
362
|
+
this.shared = this.createSharedResources(result.value.prefilterPipeline, background);
|
|
363
|
+
if (this.shared === undefined) {
|
|
364
|
+
this.pipelineWarmupFailure = 'renderer-owned IBL resources could not be allocated';
|
|
365
|
+
console.warn('[forgeax] ReflectionProbe IBL resource allocation retry');
|
|
366
|
+
this.pipelineWarmup = undefined;
|
|
367
|
+
}
|
|
368
|
+
})
|
|
369
|
+
.catch((cause: unknown) => {
|
|
370
|
+
if (this.pipelineWarmup !== warmup) return;
|
|
371
|
+
this.pipelineWarmupFailure = cause instanceof Error ? cause.message : String(cause);
|
|
331
372
|
this.pipelineWarmup = undefined;
|
|
332
|
-
|
|
333
|
-
|
|
373
|
+
this.internals.errorRegistry.fire(
|
|
374
|
+
cause instanceof RhiError
|
|
375
|
+
? cause
|
|
376
|
+
: new RhiError({
|
|
377
|
+
code: 'shader-compile-failed',
|
|
378
|
+
expected: 'complete reflection probe background and IBL pipelines',
|
|
379
|
+
hint: `inspect the shader manifest and device error: ${this.pipelineWarmupFailure}`,
|
|
380
|
+
}),
|
|
381
|
+
);
|
|
382
|
+
});
|
|
383
|
+
this.pipelineWarmup = warmup;
|
|
334
384
|
}
|
|
335
385
|
|
|
336
386
|
prepare(
|
|
@@ -339,7 +389,10 @@ export class ReflectionProbeRecordOwner {
|
|
|
339
389
|
displayCamera: CameraSnapshot | undefined,
|
|
340
390
|
frameId = this.nextFallbackTicket + 1,
|
|
341
391
|
skylight: SkylightSnapshot | undefined = undefined,
|
|
392
|
+
sceneRevision = '',
|
|
393
|
+
skybox?: SkyboxSnapshot,
|
|
342
394
|
): ReflectionProbeRecordState {
|
|
395
|
+
this.currentFrame = frameId;
|
|
343
396
|
this.refreshFallbackCapabilities(frameId);
|
|
344
397
|
this.lastFactCount = facts.length;
|
|
345
398
|
this.lastScheduledRawFaces = 0;
|
|
@@ -371,7 +424,7 @@ export class ReflectionProbeRecordOwner {
|
|
|
371
424
|
);
|
|
372
425
|
if (!admission.ok) continue;
|
|
373
426
|
const key = `${fact.worldId}:${fact.entityKey}`;
|
|
374
|
-
const resource = this.resourceFor(key, fact, acceptedCount);
|
|
427
|
+
const resource = this.resourceFor(key, fact, acceptedCount, sceneRevision, skylight);
|
|
375
428
|
if (resource === undefined) continue;
|
|
376
429
|
acceptedCount += 1;
|
|
377
430
|
acceptedBytes = admission.acceptedBytes;
|
|
@@ -389,7 +442,9 @@ export class ReflectionProbeRecordOwner {
|
|
|
389
442
|
}
|
|
390
443
|
const rows = [...accepted.values()]
|
|
391
444
|
.map((resource) => {
|
|
392
|
-
const active = resource.
|
|
445
|
+
const active = resource.activeFact?.center.every((v, i) => v === resource.fact.center[i])
|
|
446
|
+
? resource.active
|
|
447
|
+
: undefined;
|
|
393
448
|
if (active === undefined) return undefined;
|
|
394
449
|
return {
|
|
395
450
|
primitiveKey: `${resource.fact.worldId}:${resource.fact.entityKey}`,
|
|
@@ -408,7 +463,23 @@ export class ReflectionProbeRecordOwner {
|
|
|
408
463
|
.filter((row): row is NonNullable<typeof row> => row !== undefined);
|
|
409
464
|
const table = buildReflectionProbeTable(rows);
|
|
410
465
|
const work: ReflectionProbeGraphWork[] = [];
|
|
411
|
-
|
|
466
|
+
const environmentReady = [skylight?.equirectHandle, skybox?.equirectHandle].every(
|
|
467
|
+
(handle) =>
|
|
468
|
+
handle === undefined ||
|
|
469
|
+
handle === 0 ||
|
|
470
|
+
this.internals.gpuStore.getCubemapGpuView(toShared<'EquirectAsset'>(handle)) !== undefined,
|
|
471
|
+
);
|
|
472
|
+
const candidates = [...accepted.values()];
|
|
473
|
+
const captureTickets: Array<{
|
|
474
|
+
resource: ProbeGpuResource;
|
|
475
|
+
pending: NonNullable<ProbeGpuResource['pending']>;
|
|
476
|
+
}> = [];
|
|
477
|
+
const deviceGeneration = this.internals.deviceScope.generation;
|
|
478
|
+
for (let offset = 0; offset < candidates.length; offset++) {
|
|
479
|
+
const candidateIndex = (this.workCursor + offset) % candidates.length;
|
|
480
|
+
const resource = candidates[candidateIndex];
|
|
481
|
+
if (resource === undefined) continue;
|
|
482
|
+
if (resource.pending !== undefined) continue;
|
|
412
483
|
const rawCaptureFace =
|
|
413
484
|
resource.rawFaceCursor < resource.raw.faceViews.length ? resource.rawFaceCursor : undefined;
|
|
414
485
|
const step =
|
|
@@ -416,7 +487,7 @@ export class ReflectionProbeRecordOwner {
|
|
|
416
487
|
? advanceProbeFilter(resource.filter)
|
|
417
488
|
: undefined;
|
|
418
489
|
if (this.shared === undefined) continue;
|
|
419
|
-
if (rawCaptureFace === undefined && step === undefined) continue;
|
|
490
|
+
if (!environmentReady || (rawCaptureFace === undefined && step === undefined)) continue;
|
|
420
491
|
const filterGroup0 =
|
|
421
492
|
step === undefined
|
|
422
493
|
? undefined
|
|
@@ -449,15 +520,15 @@ export class ReflectionProbeRecordOwner {
|
|
|
449
520
|
],
|
|
450
521
|
});
|
|
451
522
|
if (filterGroup0 !== undefined && !filterGroup0.ok) continue;
|
|
452
|
-
if (resource.pending !== undefined) continue;
|
|
453
523
|
resource.pending = { rawCaptureFace, step };
|
|
524
|
+
captureTickets.push({ resource, pending: resource.pending });
|
|
454
525
|
if (rawCaptureFace !== undefined) this.lastScheduledRawFaces += 1;
|
|
455
526
|
if (step !== undefined) this.lastScheduledFilteredSteps += 1;
|
|
456
527
|
const face =
|
|
457
528
|
rawCaptureFace === undefined
|
|
458
529
|
? undefined
|
|
459
530
|
: buildCubeCameraFaceViews({
|
|
460
|
-
position: resource.
|
|
531
|
+
position: resource.captureFact.center,
|
|
461
532
|
near: 0.1,
|
|
462
533
|
far: 100,
|
|
463
534
|
})[rawCaptureFace];
|
|
@@ -467,9 +538,9 @@ export class ReflectionProbeRecordOwner {
|
|
|
467
538
|
: {
|
|
468
539
|
...displayCamera,
|
|
469
540
|
position: vec3.create(
|
|
470
|
-
resource.
|
|
471
|
-
resource.
|
|
472
|
-
resource.
|
|
541
|
+
resource.captureFact.center[0] ?? 0,
|
|
542
|
+
resource.captureFact.center[1] ?? 0,
|
|
543
|
+
resource.captureFact.center[2] ?? 0,
|
|
473
544
|
),
|
|
474
545
|
world: mat4.invert(mat4.create(), face.view),
|
|
475
546
|
fov: Math.PI / 2,
|
|
@@ -490,6 +561,7 @@ export class ReflectionProbeRecordOwner {
|
|
|
490
561
|
outputFormat: this.outputFormat,
|
|
491
562
|
sampler: resource.sampler,
|
|
492
563
|
filterPipeline: this.shared.filterPipeline,
|
|
564
|
+
...(this.shared.background === undefined ? {} : { background: this.shared.background }),
|
|
493
565
|
filterGroup0: filterGroup0?.value,
|
|
494
566
|
filterGroup1: resource.filterGroup1,
|
|
495
567
|
cubeVertexBuffer: this.shared.vertexBuffer,
|
|
@@ -506,6 +578,8 @@ export class ReflectionProbeRecordOwner {
|
|
|
506
578
|
filteredSize: resource.candidate.size,
|
|
507
579
|
step,
|
|
508
580
|
});
|
|
581
|
+
this.workCursor = (candidateIndex + 1) % candidates.length;
|
|
582
|
+
break;
|
|
509
583
|
}
|
|
510
584
|
return {
|
|
511
585
|
table,
|
|
@@ -530,6 +604,9 @@ export class ReflectionProbeRecordOwner {
|
|
|
530
604
|
completed,
|
|
531
605
|
fallbackOutput,
|
|
532
606
|
fallbackRequested,
|
|
607
|
+
captureTickets,
|
|
608
|
+
deviceGeneration,
|
|
609
|
+
frameId,
|
|
533
610
|
),
|
|
534
611
|
};
|
|
535
612
|
}
|
|
@@ -552,14 +629,13 @@ export class ReflectionProbeRecordOwner {
|
|
|
552
629
|
}>;
|
|
553
630
|
},
|
|
554
631
|
fallbackRequested = true,
|
|
632
|
+
captureTickets: readonly {
|
|
633
|
+
resource: ProbeGpuResource;
|
|
634
|
+
pending: NonNullable<ProbeGpuResource['pending']>;
|
|
635
|
+
}[] = [],
|
|
636
|
+
deviceGeneration = this.internals.deviceScope.generation,
|
|
637
|
+
submittedFrame = this.currentFrame,
|
|
555
638
|
): Promise<void> {
|
|
556
|
-
if (!fallbackRequested) {
|
|
557
|
-
// The scene has no Standard PBR renderable that can consume the
|
|
558
|
-
// producer's second output, so the graph intentionally omits the MRT.
|
|
559
|
-
// Retire only this frame's candidate tickets; keep any previously
|
|
560
|
-
// committed LKG receipt without manufacturing a readback failure.
|
|
561
|
-
return;
|
|
562
|
-
}
|
|
563
639
|
let completionFailure: ReflectionFallbackFailureInput | undefined;
|
|
564
640
|
if (completed !== undefined) {
|
|
565
641
|
try {
|
|
@@ -573,14 +649,20 @@ export class ReflectionProbeRecordOwner {
|
|
|
573
649
|
};
|
|
574
650
|
}
|
|
575
651
|
}
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
652
|
+
if (fallbackRequested)
|
|
653
|
+
await this.completeFallbackSubmission(
|
|
654
|
+
submitted,
|
|
655
|
+
fallbackTickets,
|
|
656
|
+
fallbackOutput,
|
|
657
|
+
completionFailure,
|
|
658
|
+
);
|
|
659
|
+
if (deviceGeneration !== this.internals.deviceScope.generation) return;
|
|
660
|
+
for (const { resource, pending } of captureTickets) {
|
|
661
|
+
if (
|
|
662
|
+
resource.pending !== pending ||
|
|
663
|
+
this.resources.get(`${resource.fact.worldId}:${resource.fact.entityKey}`) !== resource
|
|
664
|
+
)
|
|
665
|
+
continue;
|
|
584
666
|
delete resource.pending;
|
|
585
667
|
if (!submitted || pending === undefined) continue;
|
|
586
668
|
if (pending.rawCaptureFace !== undefined) {
|
|
@@ -595,6 +677,8 @@ export class ReflectionProbeRecordOwner {
|
|
|
595
677
|
if (resource.filter.cursor >= resource.filter.faceCount * resource.filter.mipCount) {
|
|
596
678
|
const previous = resource.active;
|
|
597
679
|
resource.active = resource.candidate;
|
|
680
|
+
resource.activeFact = resource.captureFact;
|
|
681
|
+
resource.lastCompletedFrame = submittedFrame;
|
|
598
682
|
resource.candidate = resource.spare ?? previous ?? resource.candidate;
|
|
599
683
|
resource.spare = undefined;
|
|
600
684
|
}
|
|
@@ -618,18 +702,29 @@ export class ReflectionProbeRecordOwner {
|
|
|
618
702
|
facts.length === 0 && skylight === undefined
|
|
619
703
|
? new Map([['__frame__', { kind: 'skylight' as const }]])
|
|
620
704
|
: selections;
|
|
705
|
+
const skylightSignature =
|
|
706
|
+
skylight === undefined
|
|
707
|
+
? ''
|
|
708
|
+
: `:${JSON.stringify([skylight.equirectHandle, skylight.intensity, ...skylight.color, ...skylight.rotation])}`;
|
|
621
709
|
for (const [renderableKey, selection] of stagedSelections) {
|
|
622
710
|
const probeKey =
|
|
623
711
|
selection.kind === 'probe' ? `${selection.worldId}:${selection.entityKey}` : undefined;
|
|
624
712
|
const resource = probeKey === undefined ? undefined : accepted.get(probeKey);
|
|
625
713
|
const source = resolveReflectionFallbackSource(
|
|
626
714
|
selection,
|
|
627
|
-
resource?.active !== undefined
|
|
715
|
+
resource?.active !== undefined &&
|
|
716
|
+
resource.activeFact?.center.every((v, i) => v === resource.fact.center[i]) === true,
|
|
628
717
|
skylight !== undefined,
|
|
629
718
|
);
|
|
630
719
|
const projection = deriveReflectionFallbackProjection({
|
|
631
720
|
renderableKey,
|
|
632
|
-
sourceKey:
|
|
721
|
+
sourceKey:
|
|
722
|
+
reflectionFallbackSourceKey(source, selection, skylight) +
|
|
723
|
+
(source === 'probe' && resource !== undefined
|
|
724
|
+
? `@${resource.filter.activeGeneration}:${resource.fact.boxProjection === true}:${resource.fact.intensity}`
|
|
725
|
+
: '') +
|
|
726
|
+
skylightSignature +
|
|
727
|
+
(source === 'neutral' ? '' : `:catalog:${this.internals.assets.catalogEpoch}`),
|
|
633
728
|
source,
|
|
634
729
|
coverage: reflectionFallbackCoverage(source, resource?.fact, selection),
|
|
635
730
|
...(resource === undefined ? {} : { extent: resource.fact.halfExtents }),
|
|
@@ -748,7 +843,8 @@ export class ReflectionProbeRecordOwner {
|
|
|
748
843
|
let sourceMatch: string | undefined;
|
|
749
844
|
for (const [key, pending] of tickets) {
|
|
750
845
|
const matches =
|
|
751
|
-
|
|
846
|
+
(selectedSourceKey !== undefined &&
|
|
847
|
+
pending.projection.sourceKey?.startsWith(`${selectedSourceKey}@`) === true) ||
|
|
752
848
|
(selectedSourceKey === undefined && pending.projection.source === 'skylight');
|
|
753
849
|
if (matches && (sourceMatch === undefined || key < sourceMatch)) sourceMatch = key;
|
|
754
850
|
}
|
|
@@ -793,8 +889,9 @@ export class ReflectionProbeRecordOwner {
|
|
|
793
889
|
source: previous?.sourceGeneration ?? 0,
|
|
794
890
|
projection: previous?.projectionGeneration ?? 0,
|
|
795
891
|
};
|
|
892
|
+
const { linearHdr: _referencePixel, ...projection } = pending.projection;
|
|
796
893
|
const receipt = Object.freeze({
|
|
797
|
-
...
|
|
894
|
+
...projection,
|
|
798
895
|
rendererId: this.internals.deviceScope.owner,
|
|
799
896
|
producerId: REFLECTION_PROBE_PRODUCER_ID,
|
|
800
897
|
...(this.internals.ssrIdentity === undefined ? {} : { identity: this.internals.ssrIdentity }),
|
|
@@ -869,11 +966,8 @@ export class ReflectionProbeRecordOwner {
|
|
|
869
966
|
if (!this.fallbackFormatAvailable) {
|
|
870
967
|
return;
|
|
871
968
|
}
|
|
872
|
-
//
|
|
873
|
-
//
|
|
874
|
-
// pending ticket and keep the last committed row (if any) as LKG. This
|
|
875
|
-
// prevents the projection's zero quartet from becoming false active
|
|
876
|
-
// evidence when the copy/readback owner has not run.
|
|
969
|
+
// Source/coverage publication follows real graph execution and GPU completion.
|
|
970
|
+
// Pixel validation is a separate, explicitly requested diagnostic capability.
|
|
877
971
|
if (!submitted || fallbackTickets.size === 0) {
|
|
878
972
|
if (!submitted) {
|
|
879
973
|
this.recordFallbackFailure(
|
|
@@ -887,10 +981,12 @@ export class ReflectionProbeRecordOwner {
|
|
|
887
981
|
}
|
|
888
982
|
return;
|
|
889
983
|
}
|
|
890
|
-
if (
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
984
|
+
if (
|
|
985
|
+
fallbackOutput === undefined ||
|
|
986
|
+
(this.internals.captureReflectionFallbackReadback === true &&
|
|
987
|
+
fallbackOutput.readback === undefined)
|
|
988
|
+
) {
|
|
989
|
+
// Neutral rows require no attachment; non-neutral rows need an executed output.
|
|
894
990
|
const committedNeutral = this.commitNeutralFallbacks(fallbackTickets);
|
|
895
991
|
const nonNeutral = new Map(
|
|
896
992
|
[...fallbackTickets].filter(([, pending]) => pending.projection.source !== 'neutral'),
|
|
@@ -902,20 +998,25 @@ export class ReflectionProbeRecordOwner {
|
|
|
902
998
|
if (nonNeutral.size > 0) {
|
|
903
999
|
this.recordFallbackFailure({
|
|
904
1000
|
stage: 'completion',
|
|
905
|
-
code:
|
|
906
|
-
|
|
1001
|
+
code:
|
|
1002
|
+
fallbackOutput === undefined
|
|
1003
|
+
? 'reflection-fallback-output-missing'
|
|
1004
|
+
: 'reflection-fallback-readback-missing',
|
|
1005
|
+
expected: 'a completed fallback MRT output and, when requested, mapped diagnostic bytes',
|
|
907
1006
|
detail: { frameId: fallbackTickets.values().next().value?.frameId },
|
|
908
1007
|
});
|
|
909
1008
|
}
|
|
910
1009
|
this.preserveFallbackLkg(nonNeutral);
|
|
911
1010
|
return;
|
|
912
1011
|
}
|
|
913
|
-
let readback:
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
1012
|
+
let readback:
|
|
1013
|
+
| {
|
|
1014
|
+
readonly linearHdr: readonly [number, number, number, number];
|
|
1015
|
+
readonly hash: string;
|
|
1016
|
+
readonly graphGeneration: number;
|
|
1017
|
+
readonly textureIdentity: number;
|
|
1018
|
+
}
|
|
1019
|
+
| undefined;
|
|
919
1020
|
try {
|
|
920
1021
|
readback = await fallbackOutput.readback;
|
|
921
1022
|
} catch (cause) {
|
|
@@ -934,8 +1035,9 @@ export class ReflectionProbeRecordOwner {
|
|
|
934
1035
|
return;
|
|
935
1036
|
}
|
|
936
1037
|
if (
|
|
937
|
-
readback
|
|
938
|
-
readback.
|
|
1038
|
+
readback !== undefined &&
|
|
1039
|
+
(readback.graphGeneration !== fallbackOutput.graphGeneration ||
|
|
1040
|
+
readback.textureIdentity !== fallbackOutput.textureIdentity)
|
|
939
1041
|
) {
|
|
940
1042
|
this.recordFallbackFailure({
|
|
941
1043
|
stage: 'completion',
|
|
@@ -994,6 +1096,7 @@ export class ReflectionProbeRecordOwner {
|
|
|
994
1096
|
const previousReadback = this.fallbackReadback;
|
|
995
1097
|
if (
|
|
996
1098
|
hasNonNeutral &&
|
|
1099
|
+
readback !== undefined &&
|
|
997
1100
|
(previousReadback === undefined || fallbackOutput.frameId >= previousReadback.frameId)
|
|
998
1101
|
) {
|
|
999
1102
|
this.fallbackReadback = Object.freeze({
|
|
@@ -1015,6 +1118,7 @@ export class ReflectionProbeRecordOwner {
|
|
|
1015
1118
|
readbackStatus: 'complete',
|
|
1016
1119
|
});
|
|
1017
1120
|
}
|
|
1121
|
+
if (readback === undefined) this.fallbackReadback = undefined;
|
|
1018
1122
|
for (const [renderableKey, pending] of eligible) {
|
|
1019
1123
|
this.commitFallbackProjection(
|
|
1020
1124
|
renderableKey,
|
|
@@ -1043,6 +1147,8 @@ export class ReflectionProbeRecordOwner {
|
|
|
1043
1147
|
this.fallbackFormatAvailable = this.internals.device.caps.rgba16floatRenderable === true;
|
|
1044
1148
|
this.fallbackReceipt = this.createFallbackReceipt('unavailable');
|
|
1045
1149
|
if (this.shared !== undefined) {
|
|
1150
|
+
if (this.shared.background !== undefined)
|
|
1151
|
+
this.internals.device.destroyBuffer(this.shared.background.uniform);
|
|
1046
1152
|
this.internals.device.destroyBuffer(this.shared.faceUniforms);
|
|
1047
1153
|
this.internals.device.destroyBuffer(this.shared.prefilterUniforms);
|
|
1048
1154
|
this.internals.device.destroyBuffer(this.shared.vertexBuffer);
|
|
@@ -1068,35 +1174,92 @@ export class ReflectionProbeRecordOwner {
|
|
|
1068
1174
|
key: string,
|
|
1069
1175
|
fact: ReflectionProbeFact,
|
|
1070
1176
|
index: number,
|
|
1177
|
+
sceneRevision = '',
|
|
1178
|
+
skylight?: SkylightSnapshot,
|
|
1071
1179
|
): ProbeGpuResource | undefined {
|
|
1072
|
-
const
|
|
1180
|
+
const diffuse =
|
|
1181
|
+
skylight === undefined
|
|
1182
|
+
? [0, 0, 0, 0, 0, 0, 0, 1]
|
|
1183
|
+
: [...skylight.color.map((value) => value * skylight.intensity), 0, ...skylight.rotation];
|
|
1184
|
+
let existing = this.resources.get(key);
|
|
1185
|
+
if (
|
|
1186
|
+
existing !== undefined &&
|
|
1187
|
+
existing.raw.size !== fact.resolution &&
|
|
1188
|
+
existing.pending === undefined
|
|
1189
|
+
) {
|
|
1190
|
+
this.destroyProbeResource(existing);
|
|
1191
|
+
this.resources.delete(key);
|
|
1192
|
+
existing = undefined;
|
|
1193
|
+
}
|
|
1073
1194
|
if (existing !== undefined) {
|
|
1074
|
-
|
|
1075
|
-
|
|
1195
|
+
const previous = existing.fact;
|
|
1196
|
+
const settled =
|
|
1197
|
+
existing.filter.cursor >= existing.filter.faceCount * existing.filter.mipCount;
|
|
1198
|
+
const moved = existing.captureFact.center.some((value, axis) => value !== fact.center[axis]);
|
|
1199
|
+
const requested =
|
|
1200
|
+
existing.captureFact.revision !== fact.revision ||
|
|
1201
|
+
moved ||
|
|
1202
|
+
fact.updateIntent === 'continuous' ||
|
|
1203
|
+
(fact.updateIntent === 'on-change' && existing.captureSceneRevision !== sceneRevision);
|
|
1204
|
+
// Finish the current bounded cycle. Coalesce newer changes into the next
|
|
1205
|
+
// cycle instead of continuously restarting face zero under motion.
|
|
1206
|
+
if (settled && existing.pending === undefined && requested) {
|
|
1207
|
+
existing.captureFact = fact;
|
|
1208
|
+
existing.captureSceneRevision = sceneRevision;
|
|
1209
|
+
existing.captureStartedFrame = this.currentFrame;
|
|
1076
1210
|
existing.filter = createProbeFilterState({
|
|
1077
1211
|
probeIndex: index,
|
|
1078
1212
|
mipCount: PREFILTER_MIP_LEVELS,
|
|
1079
1213
|
activeGeneration: existing.filter.activeGeneration,
|
|
1080
1214
|
});
|
|
1081
1215
|
existing.rawFaceCursor = 0;
|
|
1082
|
-
}
|
|
1083
|
-
|
|
1084
|
-
|
|
1216
|
+
}
|
|
1217
|
+
existing.fact = fact;
|
|
1218
|
+
existing.index = index;
|
|
1219
|
+
if (
|
|
1220
|
+
previous.intensity !== fact.intensity ||
|
|
1221
|
+
previous.boxProjection !== fact.boxProjection ||
|
|
1222
|
+
previous.center.some((v, i) => v !== fact.center[i]) ||
|
|
1223
|
+
previous.halfExtents.some((v, i) => v !== fact.halfExtents[i]) ||
|
|
1224
|
+
existing.diffusePayload.some((v, i) => v !== diffuse[i])
|
|
1225
|
+
) {
|
|
1226
|
+
const written = this.internals.device.queue.writeBuffer(
|
|
1227
|
+
existing.uniformBuffer,
|
|
1228
|
+
0,
|
|
1229
|
+
new Float32Array([
|
|
1230
|
+
-(Math.max(0, fact.intensity) + PROBE_INTENSITY_SENTINEL_OFFSET),
|
|
1231
|
+
...fact.center,
|
|
1232
|
+
...fact.halfExtents,
|
|
1233
|
+
fact.boxProjection === true ? 1 : 0,
|
|
1234
|
+
...diffuse,
|
|
1235
|
+
]),
|
|
1236
|
+
);
|
|
1237
|
+
if (!written.ok) this.internals.errorRegistry.fire(written.error);
|
|
1238
|
+
else existing.diffusePayload = diffuse;
|
|
1085
1239
|
}
|
|
1086
1240
|
return existing;
|
|
1087
1241
|
}
|
|
1088
1242
|
if (this.shared === undefined) return undefined;
|
|
1089
|
-
const raw = this.createCubeSet(`reflection-probe-${index}-raw`, fact.resolution);
|
|
1243
|
+
const raw = this.createCubeSet(`reflection-probe-${index}-raw`, fact.resolution, 1);
|
|
1090
1244
|
const candidate = this.createCubeSet(`reflection-probe-${index}-candidate`, fact.resolution);
|
|
1091
1245
|
const spare = this.createCubeSet(`reflection-probe-${index}-spare`, fact.resolution);
|
|
1092
|
-
|
|
1246
|
+
const releaseSets = () => {
|
|
1247
|
+
for (const set of [raw, candidate, spare]) if (set !== undefined) this.destroyCubeSet(set);
|
|
1248
|
+
};
|
|
1249
|
+
if (raw === undefined || candidate === undefined || spare === undefined) {
|
|
1250
|
+
releaseSets();
|
|
1251
|
+
return undefined;
|
|
1252
|
+
}
|
|
1093
1253
|
const uniformBuffer = this.internals.device.createBuffer({
|
|
1094
1254
|
label: `reflection-probe-${index}-uniforms`,
|
|
1095
|
-
size:
|
|
1255
|
+
size: 64,
|
|
1096
1256
|
usage: GPU_BUFFER_USAGE_UNIFORM | GPU_BUFFER_USAGE_COPY_DST,
|
|
1097
1257
|
mappedAtCreation: false,
|
|
1098
1258
|
});
|
|
1099
|
-
if (!uniformBuffer.ok)
|
|
1259
|
+
if (!uniformBuffer.ok) {
|
|
1260
|
+
releaseSets();
|
|
1261
|
+
return undefined;
|
|
1262
|
+
}
|
|
1100
1263
|
const payload = new Float32Array([
|
|
1101
1264
|
-(Math.max(0, fact.intensity) + PROBE_INTENSITY_SENTINEL_OFFSET),
|
|
1102
1265
|
fact.center[0],
|
|
@@ -1105,10 +1268,15 @@ export class ReflectionProbeRecordOwner {
|
|
|
1105
1268
|
fact.halfExtents[0],
|
|
1106
1269
|
fact.halfExtents[1],
|
|
1107
1270
|
fact.halfExtents[2],
|
|
1108
|
-
0,
|
|
1271
|
+
fact.boxProjection === true ? 1 : 0,
|
|
1272
|
+
...diffuse,
|
|
1109
1273
|
]);
|
|
1110
1274
|
const written = this.internals.device.queue.writeBuffer(uniformBuffer.value, 0, payload);
|
|
1111
|
-
if (!written.ok)
|
|
1275
|
+
if (!written.ok) {
|
|
1276
|
+
releaseSets();
|
|
1277
|
+
this.internals.device.destroyBuffer(uniformBuffer.value);
|
|
1278
|
+
return undefined;
|
|
1279
|
+
}
|
|
1112
1280
|
const filterGroup1 = this.internals.device.createBindGroup({
|
|
1113
1281
|
label: `reflection-probe-${index}-filter-input`,
|
|
1114
1282
|
layout: this.shared.cubeGroup1Bgl,
|
|
@@ -1117,11 +1285,20 @@ export class ReflectionProbeRecordOwner {
|
|
|
1117
1285
|
{ binding: 1, resource: { kind: 'sampler', value: this.shared.sampler } },
|
|
1118
1286
|
],
|
|
1119
1287
|
});
|
|
1120
|
-
if (!filterGroup1.ok)
|
|
1288
|
+
if (!filterGroup1.ok) {
|
|
1289
|
+
releaseSets();
|
|
1290
|
+
this.internals.device.destroyBuffer(uniformBuffer.value);
|
|
1291
|
+
return undefined;
|
|
1292
|
+
}
|
|
1121
1293
|
const resource: ProbeGpuResource = {
|
|
1122
1294
|
fact,
|
|
1295
|
+
captureFact: fact,
|
|
1296
|
+
diffusePayload: diffuse,
|
|
1297
|
+
captureSceneRevision: sceneRevision,
|
|
1298
|
+
captureStartedFrame: this.currentFrame,
|
|
1299
|
+
lastCompletedFrame: 0,
|
|
1123
1300
|
index,
|
|
1124
|
-
filter: createProbeFilterState({ probeIndex: index, mipCount:
|
|
1301
|
+
filter: createProbeFilterState({ probeIndex: index, mipCount: candidate.mipViews.length }),
|
|
1125
1302
|
rawFaceCursor: 0,
|
|
1126
1303
|
raw,
|
|
1127
1304
|
active: undefined,
|
|
@@ -1135,12 +1312,15 @@ export class ReflectionProbeRecordOwner {
|
|
|
1135
1312
|
return resource;
|
|
1136
1313
|
}
|
|
1137
1314
|
|
|
1138
|
-
private createSharedResources(
|
|
1315
|
+
private createSharedResources(
|
|
1316
|
+
filterPipeline: RenderPipeline,
|
|
1317
|
+
background?: ProbeBackgroundResources,
|
|
1318
|
+
): ProbeSharedResources | undefined {
|
|
1139
1319
|
const faceUniforms = createFaceUniformsBuffer(this.internals.device);
|
|
1140
1320
|
const prefilterUniforms = createPrefilterUniformsBuffer(this.internals.device);
|
|
1141
1321
|
if (!faceUniforms.ok || !prefilterUniforms.ok) return undefined;
|
|
1142
1322
|
if (!writeAllFaceUniforms(this.internals.device, faceUniforms.value).ok) return undefined;
|
|
1143
|
-
if (!writeAllPrefilterUniforms(this.internals.device, prefilterUniforms.value).ok)
|
|
1323
|
+
if (!writeAllPrefilterUniforms(this.internals.device, prefilterUniforms.value, 1, 'camera').ok)
|
|
1144
1324
|
return undefined;
|
|
1145
1325
|
const vertexBuffer = this.internals.device.createBuffer({
|
|
1146
1326
|
label: 'reflection-probe-capture-cube-vertices',
|
|
@@ -1173,6 +1353,7 @@ export class ReflectionProbeRecordOwner {
|
|
|
1173
1353
|
return undefined;
|
|
1174
1354
|
}
|
|
1175
1355
|
return {
|
|
1356
|
+
background,
|
|
1176
1357
|
faceUniforms: faceUniforms.value,
|
|
1177
1358
|
prefilterUniforms: prefilterUniforms.value,
|
|
1178
1359
|
vertexBuffer: vertexBuffer.value,
|
|
@@ -1183,9 +1364,11 @@ export class ReflectionProbeRecordOwner {
|
|
|
1183
1364
|
};
|
|
1184
1365
|
}
|
|
1185
1366
|
|
|
1186
|
-
private createCubeSet(
|
|
1187
|
-
|
|
1188
|
-
|
|
1367
|
+
private createCubeSet(
|
|
1368
|
+
label: string,
|
|
1369
|
+
size: number,
|
|
1370
|
+
mipCount = PREFILTER_MIP_LEVELS,
|
|
1371
|
+
): ProbeCubeSet | undefined {
|
|
1189
1372
|
const texture = this.internals.device.createTexture({
|
|
1190
1373
|
label,
|
|
1191
1374
|
size: { width: size, height: size, depthOrArrayLayers: 6 },
|
|
@@ -1205,7 +1388,10 @@ export class ReflectionProbeRecordOwner {
|
|
|
1205
1388
|
mipLevelCount: mipCount,
|
|
1206
1389
|
arrayLayerCount: 6,
|
|
1207
1390
|
});
|
|
1208
|
-
if (!cubeView.ok)
|
|
1391
|
+
if (!cubeView.ok) {
|
|
1392
|
+
this.internals.device.destroyTexture(texture.value);
|
|
1393
|
+
return undefined;
|
|
1394
|
+
}
|
|
1209
1395
|
const faceViews: TextureView[] = [];
|
|
1210
1396
|
const mipViews: TextureView[][] = [];
|
|
1211
1397
|
for (let mip = 0; mip < mipCount; mip += 1) {
|
|
@@ -1219,7 +1405,10 @@ export class ReflectionProbeRecordOwner {
|
|
|
1219
1405
|
baseArrayLayer: face,
|
|
1220
1406
|
arrayLayerCount: 1,
|
|
1221
1407
|
});
|
|
1222
|
-
if (!view.ok)
|
|
1408
|
+
if (!view.ok) {
|
|
1409
|
+
this.internals.device.destroyTexture(texture.value);
|
|
1410
|
+
return undefined;
|
|
1411
|
+
}
|
|
1223
1412
|
if (mip === 0) faceViews.push(view.value);
|
|
1224
1413
|
faces.push(view.value);
|
|
1225
1414
|
}
|
|
@@ -1236,12 +1425,19 @@ export class ReflectionProbeRecordOwner {
|
|
|
1236
1425
|
viewFormats: [],
|
|
1237
1426
|
textureBindingViewDimension: undefined,
|
|
1238
1427
|
});
|
|
1239
|
-
if (!depthTexture.ok)
|
|
1428
|
+
if (!depthTexture.ok) {
|
|
1429
|
+
this.internals.device.destroyTexture(texture.value);
|
|
1430
|
+
return undefined;
|
|
1431
|
+
}
|
|
1240
1432
|
const depthView = this.internals.device.createTextureView(depthTexture.value, {
|
|
1241
1433
|
label: `${label}-depth-view`,
|
|
1242
1434
|
dimension: '2d',
|
|
1243
1435
|
});
|
|
1244
|
-
if (!depthView.ok)
|
|
1436
|
+
if (!depthView.ok) {
|
|
1437
|
+
this.internals.device.destroyTexture(texture.value);
|
|
1438
|
+
this.internals.device.destroyTexture(depthTexture.value);
|
|
1439
|
+
return undefined;
|
|
1440
|
+
}
|
|
1245
1441
|
return {
|
|
1246
1442
|
texture: texture.value,
|
|
1247
1443
|
cubeView: cubeView.value,
|