@forgeax/engine-render 0.1.31 → 0.1.33
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 +447 -34
- package/dist/assembly/analytic-fog-registration.d.ts +3 -0
- package/dist/assembly/analytic-fog-registration.d.ts.map +1 -0
- package/dist/assembly/fxaa-registration.d.ts +4 -0
- package/dist/assembly/fxaa-registration.d.ts.map +1 -0
- package/dist/assembly/lod-observation.d.ts +4 -0
- package/dist/assembly/lod-observation.d.ts.map +1 -0
- package/dist/assembly/motion-blur-registration.d.ts +3 -0
- package/dist/assembly/motion-blur-registration.d.ts.map +1 -0
- package/dist/assembly/renderer-facade.d.ts.map +1 -1
- package/dist/assembly/temporal-post-process-prewarm.d.ts +13 -0
- package/dist/assembly/temporal-post-process-prewarm.d.ts.map +1 -0
- package/dist/assembly/webgpu-ready-contract.d.ts +4 -3
- package/dist/assembly/webgpu-ready-contract.d.ts.map +1 -1
- package/dist/assembly/webgpu-ready.d.ts +3 -2
- package/dist/assembly/webgpu-ready.d.ts.map +1 -1
- package/dist/assembly/webgpu-renderer.d.ts.map +1 -1
- package/dist/bloom-admission.d.ts +13 -0
- package/dist/bloom-admission.d.ts.map +1 -0
- package/dist/{chunk-FUUO4UND.mjs → chunk-3RTCJTH4.mjs} +12 -9
- package/dist/chunk-3RTCJTH4.mjs.map +1 -0
- package/dist/{chunk-NO4WZCAH.mjs → chunk-LEAXOMYJ.mjs} +3 -3
- package/dist/{chunk-NO4WZCAH.mjs.map → chunk-LEAXOMYJ.mjs.map} +1 -1
- package/dist/{chunk-JRBDO2KB.mjs → chunk-NB2S7ZRX.mjs} +166 -10
- package/dist/chunk-NB2S7ZRX.mjs.map +1 -0
- package/dist/{chunk-7MQ3XBSP.mjs → chunk-NNQL7CB3.mjs} +4 -4
- package/dist/{chunk-7MQ3XBSP.mjs.map → chunk-NNQL7CB3.mjs.map} +1 -1
- package/dist/{chunk-C3DDSXYK.mjs → chunk-OO3DRYK7.mjs} +171 -230
- package/dist/chunk-OO3DRYK7.mjs.map +1 -0
- package/dist/{chunk-S5UE2T5P.mjs → chunk-PLAXOOX5.mjs} +608 -7
- package/dist/chunk-PLAXOOX5.mjs.map +1 -0
- package/dist/{chunk-PSEQ6QPH.mjs → chunk-VOZWDM3L.mjs} +295 -198
- package/dist/chunk-VOZWDM3L.mjs.map +1 -0
- package/dist/{chunk-MDQJPY3T.mjs → chunk-ZDQWGQW7.mjs} +10 -4
- package/dist/chunk-ZDQWGQW7.mjs.map +1 -0
- package/dist/components/atmosphere.d.ts +2 -0
- package/dist/components/atmosphere.d.ts.map +1 -1
- package/dist/components/camera.d.ts +20 -4
- package/dist/components/camera.d.ts.map +1 -1
- package/dist/components/depth-of-field.d.ts +28 -0
- package/dist/components/depth-of-field.d.ts.map +1 -0
- package/dist/components/directional-light.d.ts +2 -1
- package/dist/components/directional-light.d.ts.map +1 -1
- package/dist/components/index.d.ts +1 -0
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/mesh-filter.d.ts +6 -5
- package/dist/components/mesh-filter.d.ts.map +1 -1
- package/dist/components/motion-blur.d.ts +1 -0
- package/dist/components/motion-blur.d.ts.map +1 -1
- package/dist/construct-renderer.mjs +3746 -837
- package/dist/construct-renderer.mjs.map +1 -1
- package/dist/device/gpu-residency.d.ts +6 -0
- package/dist/device/gpu-residency.d.ts.map +1 -1
- package/dist/environment/analytic-fog.d.ts +6 -0
- package/dist/environment/analytic-fog.d.ts.map +1 -0
- package/dist/errors/render.d.ts +6 -2
- 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/environment.d.ts +2 -0
- package/dist/extract/environment.d.ts.map +1 -1
- package/dist/features/depth-of-field/depth-of-field-assembly.d.ts +19 -0
- package/dist/features/depth-of-field/depth-of-field-assembly.d.ts.map +1 -0
- package/dist/features/depth-of-field/depth-of-field-feature.d.ts +43 -0
- package/dist/features/depth-of-field/depth-of-field-feature.d.ts.map +1 -0
- package/dist/features/depth-of-field/depth-of-field-inspection.d.ts +34 -0
- package/dist/features/depth-of-field/depth-of-field-inspection.d.ts.map +1 -0
- package/dist/features/depth-of-field/depth-of-field-params.d.ts +83 -0
- package/dist/features/depth-of-field/depth-of-field-params.d.ts.map +1 -0
- package/dist/features/error-reporting.d.ts +13 -0
- package/dist/features/error-reporting.d.ts.map +1 -0
- package/dist/features/host.d.ts +5 -0
- package/dist/features/host.d.ts.map +1 -1
- package/dist/features/motion-blur/motion-blur-feature.d.ts +20 -2
- package/dist/features/motion-blur/motion-blur-feature.d.ts.map +1 -1
- package/dist/features/motion-blur/motion-blur-params.d.ts +21 -0
- package/dist/features/motion-blur/motion-blur-params.d.ts.map +1 -1
- package/dist/features/motion-blur/motion-blur-runtime.d.ts +54 -0
- package/dist/features/motion-blur/motion-blur-runtime.d.ts.map +1 -0
- package/dist/features/plan.d.ts +7 -4
- package/dist/features/plan.d.ts.map +1 -1
- package/dist/features/prepared-gpu-work.d.ts +9 -5
- package/dist/features/prepared-gpu-work.d.ts.map +1 -1
- package/dist/features/render-graph-compute.d.ts.map +1 -1
- package/dist/features/render-graph-contribution.d.ts.map +1 -1
- package/dist/features/types.d.ts +19 -1
- package/dist/features/types.d.ts.map +1 -1
- package/dist/gpu-driven/material-artifacts.d.ts.map +1 -1
- package/dist/gpu-driven/prepared-draw.d.ts +7 -0
- package/dist/gpu-driven/prepared-draw.d.ts.map +1 -1
- package/dist/gpu-driven/production-raster.d.ts +3 -1
- package/dist/gpu-driven/production-raster.d.ts.map +1 -1
- package/dist/gpu-driven/view-gpu.d.ts +9 -0
- package/dist/gpu-driven/view-gpu.d.ts.map +1 -1
- package/dist/gpu-scene.d.ts +6 -1
- package/dist/gpu-scene.d.ts.map +1 -1
- package/dist/index.d.ts +8 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.mjs +6 -5
- package/dist/index.mjs.map +1 -1
- package/dist/inspection-types.d.ts +78 -2
- package/dist/inspection-types.d.ts.map +1 -1
- package/dist/instances.d.ts +15 -1
- package/dist/instances.d.ts.map +1 -1
- package/dist/internal.mjs +6 -6
- package/dist/mesh-material-bindings.d.ts +3 -0
- package/dist/mesh-material-bindings.d.ts.map +1 -1
- package/dist/pipeline/standard-output/graph.d.ts.map +1 -1
- package/dist/pipeline/standard-output/types.d.ts +4 -2
- package/dist/pipeline/standard-output/types.d.ts.map +1 -1
- package/dist/pipeline/standard-post.d.ts +28 -19
- package/dist/pipeline/standard-post.d.ts.map +1 -1
- package/dist/pipeline-spec.d.ts +2 -2
- package/dist/plugin.d.ts.map +1 -1
- package/dist/record/frame-snapshot.d.ts +24 -1
- package/dist/record/frame-snapshot.d.ts.map +1 -1
- package/dist/record/frame-targets.d.ts.map +1 -1
- package/dist/record/frame.d.ts +5 -2
- package/dist/record/frame.d.ts.map +1 -1
- package/dist/record/main-pass-geometry.d.ts.map +1 -1
- package/dist/record/main-pass.d.ts.map +1 -1
- package/dist/record/mesh-ssbo.d.ts +6 -5
- package/dist/record/mesh-ssbo.d.ts.map +1 -1
- package/dist/record/render-context.d.ts +12 -28
- 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 +5 -3
- package/dist/record/skybox-post-pass.d.ts.map +1 -1
- package/dist/record/typed-frame-graph.d.ts +8 -1
- package/dist/record/typed-frame-graph.d.ts.map +1 -1
- package/dist/recovery/render-system-candidate.d.ts.map +1 -1
- package/dist/render-contract.d.ts +32 -5
- package/dist/render-contract.d.ts.map +1 -1
- package/dist/render-graph-primitives.d.ts +2 -0
- package/dist/render-graph-primitives.d.ts.map +1 -1
- package/dist/render-pipeline.d.ts +15 -1
- package/dist/render-pipeline.d.ts.map +1 -1
- package/dist/render-system-extract-tail.d.ts.map +1 -1
- package/dist/render-system-extract.d.ts +26 -5
- package/dist/render-system-extract.d.ts.map +1 -1
- package/dist/render-system.d.ts +9 -2
- 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/temporal/frame-coordinator.d.ts.map +1 -1
- package/dist/temporal/frame.d.ts +7 -0
- package/dist/temporal/frame.d.ts.map +1 -1
- package/dist/temporal/index.mjs +5 -5
- package/dist/temporal/view.d.ts +6 -1
- package/dist/temporal/view.d.ts.map +1 -1
- package/dist/typed-render-graph-primitives.d.ts +10 -7
- package/dist/typed-render-graph-primitives.d.ts.map +1 -1
- package/dist/volume/component.d.ts +0 -1
- package/dist/volume/component.d.ts.map +1 -1
- package/dist/volume/passes.d.ts.map +1 -1
- package/dist/volume/temporal.d.ts +3 -1
- package/dist/volume/temporal.d.ts.map +1 -1
- package/package.json +21 -21
- package/src/__tests__/analytic-fog-graph.unit.test.ts +199 -0
- package/src/__tests__/analytic-fog-optics.unit.test.ts +38 -0
- package/src/__tests__/bloom-exact-zero.unit.test.ts +112 -18
- package/src/__tests__/bloom-lifecycle.integration.test.ts +17 -4
- package/src/__tests__/dynamic-resolution-plugin.integration.test.ts +20 -0
- package/src/__tests__/environment-fog-lanes.integration.test.ts +14 -0
- package/src/__tests__/environment-selection.unit.test.ts +12 -0
- package/src/__tests__/factory-contract.integration.test.ts +331 -68
- package/src/__tests__/frame-camera-selection.unit.test.ts +39 -1
- package/src/__tests__/frame-plan-contract.unit.test.ts +2 -0
- package/src/__tests__/gpu-driven-baseline.characterization.test.ts +12 -0
- package/src/__tests__/gpu-driven-indirect-raster-evidence.ts +2 -1
- package/src/__tests__/gpu-driven-production.integration.test.ts +27 -1
- package/src/__tests__/gpu-driven-shadow-views.dawn.test.ts +1 -1
- package/src/__tests__/gpu-driven-shadow-views.integration.test.ts +1 -1
- package/src/__tests__/gpu-driven-view-gpu-evidence.ts +11 -0
- package/src/__tests__/gpu-resource-store-stride.unit.test.ts +12 -0
- package/src/__tests__/gpu-scene.unit.test.ts +91 -0
- package/src/__tests__/instances-store.unit.test.ts +90 -0
- package/src/__tests__/mesh-submission-lifetime.unit.test.ts +31 -0
- package/src/__tests__/motion-blur-compute.dawn.test.ts +583 -0
- package/src/__tests__/prepared-gpu-driven-pbr.integration.test.ts +49 -0
- package/src/__tests__/prepared-graphics-lifecycle.unit.test.ts +86 -0
- package/src/__tests__/public-surface.test-d.ts +8 -0
- package/src/__tests__/render-error-code-owner.test-d.ts +2 -0
- package/src/__tests__/render-feature-error-reporting.unit.test.ts +24 -0
- package/src/__tests__/render-feature-stage-fault-recovery.unit.test.ts +23 -0
- package/src/__tests__/render-scene-temporal-retry.unit.test.ts +31 -0
- package/src/__tests__/renderer-frame-transaction.integration.test.ts +7 -1
- package/src/__tests__/shader-manifest-fixture.ts +4 -4
- package/src/__tests__/skinned-shadow-caster.test.ts +2 -0
- package/src/__tests__/standard-lighting-write.unit.test.ts +2 -1
- package/src/__tests__/standard-pipeline.dawn.test.ts +1 -1
- package/src/__tests__/standard-pipeline.integration.test.ts +18 -8
- package/src/__tests__/temporal-reset-matrix.unit.test.ts +10 -0
- package/src/__tests__/temporal-view.unit.test.ts +2 -1
- package/src/__tests__/typed-pipeline-topology.unit.test.ts +20 -4
- package/src/__tests__/volume-optics-oracle.unit.test.ts +3 -1
- package/src/__tests__/volumetric-fog-budget-recovery.integration.test.ts +177 -13
- package/src/__tests__/volumetric-fog-stage-readback.dawn.test.ts +447 -61
- package/src/__tests__/volumetric-fog-temporal.unit.test.ts +27 -0
- package/src/__tests__/volumetric-fog-topology.unit.test.ts +19 -3
- package/src/assembly/analytic-fog-registration.ts +14 -0
- package/src/assembly/fxaa-registration.ts +17 -0
- package/src/assembly/lod-observation.ts +12 -0
- package/src/assembly/motion-blur-registration.ts +17 -0
- package/src/assembly/renderer-facade.ts +2 -0
- package/src/assembly/temporal-post-process-prewarm.ts +40 -0
- package/src/assembly/webgpu-ready-contract.ts +8 -3
- package/src/assembly/webgpu-ready.ts +186 -250
- package/src/assembly/webgpu-renderer.ts +30 -45
- package/src/bloom-admission.ts +21 -0
- package/src/components/__tests__/motion-blur.unit.test.ts +1 -0
- package/src/components/atmosphere.ts +4 -0
- package/src/components/camera.ts +66 -10
- package/src/components/depth-of-field.ts +45 -0
- package/src/components/directional-light.ts +2 -1
- package/src/components/index.ts +1 -0
- package/src/components/mesh-filter.ts +11 -9
- package/src/components/motion-blur.ts +1 -0
- package/src/device/gpu-residency.ts +56 -12
- package/src/environment/analytic-fog.ts +44 -0
- package/src/environment/background.ts +2 -2
- package/src/errors/render.ts +14 -1
- package/src/extract/camera.ts +42 -9
- package/src/extract/contracts.ts +7 -0
- package/src/extract/environment.ts +4 -0
- package/src/features/depth-of-field/__tests__/depth-of-field-params.unit.test.ts +943 -0
- package/src/features/depth-of-field/depth-of-field-assembly.ts +100 -0
- package/src/features/depth-of-field/depth-of-field-feature.ts +295 -0
- package/src/features/depth-of-field/depth-of-field-inspection.ts +237 -0
- package/src/features/depth-of-field/depth-of-field-params.ts +556 -0
- package/src/features/error-reporting.ts +78 -0
- package/src/features/host.ts +26 -13
- package/src/features/motion-blur/__tests__/motion-blur-feature.unit.test.ts +111 -1
- package/src/features/motion-blur/__tests__/motion-blur-params.unit.test.ts +58 -3
- package/src/features/motion-blur/motion-blur-feature.ts +1519 -15
- package/src/features/motion-blur/motion-blur-params.ts +70 -2
- package/src/features/motion-blur/motion-blur-runtime.ts +176 -0
- package/src/features/plan.ts +25 -8
- package/src/features/prepared-gpu-work.ts +86 -35
- package/src/features/render-graph-compute.ts +13 -5
- package/src/features/render-graph-contribution.ts +2 -0
- package/src/features/types.ts +18 -1
- package/src/gpu-driven/material-artifacts.ts +2 -7
- package/src/gpu-driven/prepared-draw.ts +15 -10
- package/src/gpu-driven/production-raster.ts +83 -7
- package/src/gpu-driven/view-gpu.ts +17 -0
- package/src/gpu-scene.ts +188 -21
- package/src/index.ts +64 -0
- package/src/inspection-types.ts +98 -2
- package/src/instances.ts +93 -0
- package/src/mesh-material-bindings.ts +4 -0
- package/src/pipeline/standard-output/graph.ts +3 -0
- package/src/pipeline/standard-output/types.ts +4 -1
- package/src/pipeline/standard-post.ts +324 -76
- package/src/pipeline-spec.ts +5 -5
- package/src/plugin.ts +2 -0
- package/src/points-lines/__tests__/view-ubo.unit.test.ts +2 -1
- package/src/record/__tests__/temporal-payload.unit.test.ts +2 -1
- package/src/record/frame-snapshot.ts +31 -2
- package/src/record/frame-targets.ts +10 -6
- package/src/record/frame.ts +202 -28
- package/src/record/main-pass-geometry.ts +30 -1
- package/src/record/main-pass-sprite-draws.ts +6 -1
- package/src/record/main-pass.ts +1 -5
- package/src/record/mesh-ssbo.ts +43 -6
- package/src/record/render-context.ts +12 -28
- package/src/record/shadow-pass.ts +6 -1
- package/src/record/skybox-post-pass.ts +122 -196
- package/src/record/typed-frame-graph.ts +259 -15
- package/src/recovery/render-system-candidate.ts +28 -10
- package/src/render-contract.ts +34 -4
- package/src/render-graph-primitives.ts +8 -1
- package/src/render-pipeline.ts +22 -1
- package/src/render-system-extract-tail.ts +103 -13
- package/src/render-system-extract.ts +148 -38
- package/src/render-system.ts +332 -119
- package/src/scene/render-scene.ts +85 -4
- package/src/temporal/__tests__/temporal-frame-transaction.unit.test.ts +36 -0
- package/src/temporal/frame-coordinator.ts +8 -1
- package/src/temporal/frame.ts +20 -0
- package/src/temporal/view.ts +13 -2
- package/src/typed-render-graph-primitives.ts +124 -48
- package/src/volume/component.ts +0 -1
- package/src/volume/passes.ts +8 -4
- package/src/volume/resources.ts +1 -1
- package/src/volume/temporal.ts +11 -0
- package/dist/chunk-C3DDSXYK.mjs.map +0 -1
- package/dist/chunk-FUUO4UND.mjs.map +0 -1
- package/dist/chunk-JRBDO2KB.mjs.map +0 -1
- package/dist/chunk-MDQJPY3T.mjs.map +0 -1
- package/dist/chunk-PSEQ6QPH.mjs.map +0 -1
- package/dist/chunk-S5UE2T5P.mjs.map +0 -1
package/src/render-system.ts
CHANGED
|
@@ -39,6 +39,7 @@ import {
|
|
|
39
39
|
projectDirectionalShadowInspectionSource,
|
|
40
40
|
} from './assembly/directional-shadow-inspection';
|
|
41
41
|
import { createGpuDrivenOwner } from './assembly/gpu-driven-owner';
|
|
42
|
+
import { standardBloomAdmitted } from './bloom-admission';
|
|
42
43
|
import { createClusterBinScratch } from './cluster-binner';
|
|
43
44
|
import { EnvironmentLifecycle } from './environment/lifecycle';
|
|
44
45
|
import {
|
|
@@ -46,11 +47,26 @@ import {
|
|
|
46
47
|
type RenderError,
|
|
47
48
|
TransmissionCapabilityMissingError,
|
|
48
49
|
} from './errors/render';
|
|
50
|
+
import { projectDepthOfFieldInspection } from './features/depth-of-field/depth-of-field-inspection';
|
|
51
|
+
import { resolveDepthOfFieldFrameParams } from './features/depth-of-field/depth-of-field-params';
|
|
52
|
+
import { reportPendingRenderFeatureErrors } from './features/error-reporting';
|
|
49
53
|
import {
|
|
50
54
|
type RenderFeaturePreparedGraphicsResolverInput,
|
|
51
55
|
runRenderFeatureFrame,
|
|
52
56
|
settlePreparedGraphicsCompletion,
|
|
53
57
|
} from './features/host';
|
|
58
|
+
import {
|
|
59
|
+
createMotionBlurFeature,
|
|
60
|
+
type MotionBlurFeatureInput,
|
|
61
|
+
} from './features/motion-blur/motion-blur-feature';
|
|
62
|
+
import {
|
|
63
|
+
MotionBlurValidationError,
|
|
64
|
+
motionBlurTemporalDemand,
|
|
65
|
+
} from './features/motion-blur/motion-blur-params';
|
|
66
|
+
import {
|
|
67
|
+
planMotionBlurFrame,
|
|
68
|
+
projectMotionBlurInspection,
|
|
69
|
+
} from './features/motion-blur/motion-blur-runtime';
|
|
54
70
|
import { createFeatureNoiseResolver } from './features/noise-texture';
|
|
55
71
|
import {
|
|
56
72
|
createRenderFeatureGpuWorkOwner,
|
|
@@ -68,6 +84,7 @@ import {
|
|
|
68
84
|
} from './fullscreen-post-process-pass';
|
|
69
85
|
import type {
|
|
70
86
|
BloomInspection,
|
|
87
|
+
DepthOfFieldInspection,
|
|
71
88
|
DirectionalShadowInspection,
|
|
72
89
|
GpuDrivenProductionInspection,
|
|
73
90
|
LodOcclusionInspection,
|
|
@@ -80,6 +97,7 @@ import type {
|
|
|
80
97
|
TemporalTargetInspection,
|
|
81
98
|
TransmissionInspection,
|
|
82
99
|
} from './inspection-types';
|
|
100
|
+
import { emptyBloomInspection } from './inspection-types';
|
|
83
101
|
import { buildOcclusionProxyVertices } from './occlusion-proxy';
|
|
84
102
|
import {
|
|
85
103
|
AUTO_EXPOSURE_HISTOGRAM_BYTES,
|
|
@@ -215,6 +233,7 @@ import {
|
|
|
215
233
|
type RenderFeatureGraphCandidate,
|
|
216
234
|
recordRenderFeatureCandidate,
|
|
217
235
|
resetRenderFeatureGraphState,
|
|
236
|
+
settleDepthOfFieldGraphCandidate,
|
|
218
237
|
settleVolumetricFogGraphCandidate,
|
|
219
238
|
} from './record/typed-frame-graph';
|
|
220
239
|
import {
|
|
@@ -538,7 +557,10 @@ export interface RenderSystem {
|
|
|
538
557
|
options: FrameObservationOptions,
|
|
539
558
|
): Promise<Result<FrameObservation, ObservationUnavailableError>>;
|
|
540
559
|
/** Resolve the renderer-owned GPU LOD counters for the last accepted submit. */
|
|
541
|
-
observeLodOcclusion(
|
|
560
|
+
observeLodOcclusion(receipt?: {
|
|
561
|
+
readonly frameId: number;
|
|
562
|
+
readonly deviceGeneration: number;
|
|
563
|
+
}): Promise<void>;
|
|
542
564
|
/** Internal same-frame graph target access for backend diagnostics. */
|
|
543
565
|
getCurrentGraphTarget(name: string): CurrentGraphTarget | undefined;
|
|
544
566
|
/** Internal test capture copied into the draw's command submission. */
|
|
@@ -576,6 +598,9 @@ export interface RenderSystem {
|
|
|
576
598
|
readonly temporal: TemporalInspection;
|
|
577
599
|
readonly bloom: BloomInspection;
|
|
578
600
|
readonly motionBlurInspection: MotionBlurInspection | undefined;
|
|
601
|
+
/** The last extraction validation failure, preserved for public draw(). */
|
|
602
|
+
readonly motionBlurInvalidParams: MotionBlurValidationError | undefined;
|
|
603
|
+
readonly depthOfFieldInspection: DepthOfFieldInspection | undefined;
|
|
579
604
|
readonly temporalTargetInspection: TemporalTargetInspection | undefined;
|
|
580
605
|
readonly lodOcclusionInspection: LodOcclusionInspection | undefined;
|
|
581
606
|
/** Bounded GPU-driven counters without materializing the persistent scene table. */
|
|
@@ -718,13 +743,6 @@ function reportPreparedGraphicsCompletionError(
|
|
|
718
743
|
);
|
|
719
744
|
}
|
|
720
745
|
|
|
721
|
-
function isPendingRenderFeaturePreparation(error: RenderError): boolean {
|
|
722
|
-
return (
|
|
723
|
-
error.code === 'render-feature-preparation-failed' &&
|
|
724
|
-
error.detail.reason.startsWith('rhi-not-available:')
|
|
725
|
-
);
|
|
726
|
-
}
|
|
727
|
-
|
|
728
746
|
function makePreparedPipelinePendingError(): RhiError {
|
|
729
747
|
return new RhiError({
|
|
730
748
|
code: 'rhi-not-available',
|
|
@@ -892,6 +910,24 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
892
910
|
let preparedFeatureSkylightResources: SkylightBindGroupResources | undefined;
|
|
893
911
|
const dynamicGeometryFrames = createDynamicGeometryFrameBindings();
|
|
894
912
|
let latestCamera: CameraSnapshot | undefined;
|
|
913
|
+
// Last public parameter failure; cleared only after a valid extraction.
|
|
914
|
+
let lastMotionBlurInvalidParams: MotionBlurValidationError | undefined;
|
|
915
|
+
// Lazily install the compute lane when a capable frame demands it.
|
|
916
|
+
let motionBlurFeatureInput: MotionBlurFeatureInput | undefined;
|
|
917
|
+
const motionBlurFeature = createMotionBlurFeature(() => motionBlurFeatureInput);
|
|
918
|
+
const ensureMotionBlurFeature = (): void => {
|
|
919
|
+
const host = internals.featureHost;
|
|
920
|
+
if (
|
|
921
|
+
host === undefined ||
|
|
922
|
+
host.features.some((feature) => feature.identity === 'forgeax.motion-blur')
|
|
923
|
+
) {
|
|
924
|
+
return;
|
|
925
|
+
}
|
|
926
|
+
const installed = host.install(
|
|
927
|
+
motionBlurFeature as import('./features/types').RenderFeature<unknown>,
|
|
928
|
+
);
|
|
929
|
+
if (!installed.ok) internals.errorRegistry.fire(installed.error);
|
|
930
|
+
};
|
|
895
931
|
const pointsLinesOwner = new StandardPointsLinesOwner(internals);
|
|
896
932
|
const instanceCollections = new InstanceCollectionStore();
|
|
897
933
|
const reflectionProbeOwner = new ReflectionProbeRecordOwner(internals);
|
|
@@ -1159,6 +1195,14 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
1159
1195
|
compiledFrameGraph: null,
|
|
1160
1196
|
compiledFrameGraphTopologyKey: null,
|
|
1161
1197
|
compiledFrameGraphGeneration: 0,
|
|
1198
|
+
depthOfFieldPreviousGraph: null,
|
|
1199
|
+
depthOfFieldPreviousGraphKey: null,
|
|
1200
|
+
depthOfFieldPreviousPerFrameGraph: undefined,
|
|
1201
|
+
depthOfFieldPreviousGraphGeneration: 0,
|
|
1202
|
+
depthOfFieldPreviousStandardLightingGraphSignature: '',
|
|
1203
|
+
depthOfFieldCandidateGraph: null,
|
|
1204
|
+
depthOfFieldAccepted: undefined,
|
|
1205
|
+
depthOfFieldLastSubmitFailed: false,
|
|
1162
1206
|
volumetricFogPreviousGraph: null,
|
|
1163
1207
|
volumetricFogPreviousGraphKey: null,
|
|
1164
1208
|
volumetricFogCandidateGraph: null,
|
|
@@ -1278,6 +1322,11 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
1278
1322
|
// tiles until the first frame with a castShadow spot (AC-03).
|
|
1279
1323
|
spotShadowSnapshots: [],
|
|
1280
1324
|
};
|
|
1325
|
+
// A feature that is explicitly recoverable on the next frame must not
|
|
1326
|
+
// publish the same transient failure on every render tick. Keep one
|
|
1327
|
+
// renderer-owned cooldown per structured feature failure while retaining
|
|
1328
|
+
// the original error for the first and periodic reports.
|
|
1329
|
+
const pendingFeatureErrorLastReportedFrame = new Map<string, number>();
|
|
1281
1330
|
const resolveSsrDependencies = (requested: boolean): SsrDependenciesInspection => {
|
|
1282
1331
|
// Explicit SSR capability preparation belongs to initialization. Inspection
|
|
1283
1332
|
// only projects receipts and never starts work or creates image history.
|
|
@@ -1739,6 +1788,7 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
1739
1788
|
readonly visible: number;
|
|
1740
1789
|
readonly occluded: number;
|
|
1741
1790
|
readonly lodHistogram: readonly { readonly level: number; readonly count: number }[];
|
|
1791
|
+
readonly submit?: { readonly frameId: number; readonly deviceGeneration: number };
|
|
1742
1792
|
readonly worldSelections?: readonly {
|
|
1743
1793
|
readonly worldKey: number;
|
|
1744
1794
|
readonly primitiveSlot: number;
|
|
@@ -1750,9 +1800,11 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
1750
1800
|
}[];
|
|
1751
1801
|
}
|
|
1752
1802
|
| undefined,
|
|
1803
|
+
targetInspection: LodOcclusionInspection | undefined = lastLodOcclusionInspection,
|
|
1804
|
+
targetWorldAttachments: ReadonlyMap<number, string> = lastLodWorldAttachments,
|
|
1753
1805
|
): void => {
|
|
1754
|
-
if (selection === undefined ||
|
|
1755
|
-
const inspection =
|
|
1806
|
+
if (selection === undefined || targetInspection === undefined) return;
|
|
1807
|
+
const inspection = targetInspection;
|
|
1756
1808
|
// The GPU readback histogram is the selector fact, while final submitted
|
|
1757
1809
|
// counts are owned by the persistent visibility projection. Keeping the
|
|
1758
1810
|
// projection count here excludes ordinary non-LOD geometry (for example a
|
|
@@ -1764,7 +1816,7 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
1764
1816
|
const selectionsByAttachment = new Map<string, (typeof worldSelections)[number][]>();
|
|
1765
1817
|
let attributionValid = true;
|
|
1766
1818
|
for (const selected of worldSelections) {
|
|
1767
|
-
const attachmentId =
|
|
1819
|
+
const attachmentId = targetWorldAttachments.get(selected.worldKey);
|
|
1768
1820
|
if (attachmentId === undefined) {
|
|
1769
1821
|
attributionValid = false;
|
|
1770
1822
|
break;
|
|
@@ -1777,15 +1829,16 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
1777
1829
|
const nextWorlds = worlds.map((world) => {
|
|
1778
1830
|
const selected = selectionsByAttachment.get(world.attachmentId);
|
|
1779
1831
|
const baseRow = world.rows[0];
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1832
|
+
// A World with only plain meshes has no LOD selection row. Keep its
|
|
1833
|
+
// projection-only receipt and allow Worlds with valid LOD rows to
|
|
1834
|
+
// retain same-submit attribution. Unknown selected world keys still
|
|
1835
|
+
// fail closed above.
|
|
1836
|
+
if (selected === undefined || baseRow === undefined) return world;
|
|
1837
|
+
// The projection row is intentionally CPU-scoped and may omit
|
|
1838
|
+
// selector-only candidates that remain in the full GPU plan. The
|
|
1839
|
+
// same-submit GPU row owns the denominator; comparing it to the
|
|
1840
|
+
// projection count would reject a valid receipt (for example 11 GPU
|
|
1841
|
+
// candidates versus 10 CPU-admitted renderables).
|
|
1789
1842
|
return Object.freeze({
|
|
1790
1843
|
...world,
|
|
1791
1844
|
attribution: Object.freeze({
|
|
@@ -1815,7 +1868,7 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
1815
1868
|
lastLodOcclusionInspection = inspectLodOcclusion({
|
|
1816
1869
|
...inspection,
|
|
1817
1870
|
count: {
|
|
1818
|
-
...
|
|
1871
|
+
...inspection.count,
|
|
1819
1872
|
candidates: selection.candidateCount,
|
|
1820
1873
|
visible: selection.visible,
|
|
1821
1874
|
occluded: selection.occluded,
|
|
@@ -2261,24 +2314,40 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
2261
2314
|
});
|
|
2262
2315
|
},
|
|
2263
2316
|
get motionBlurInspection(): MotionBlurInspection | undefined {
|
|
2317
|
+
return projectMotionBlurInspection({
|
|
2318
|
+
camera: latestCamera,
|
|
2319
|
+
invalidParams: lastMotionBlurInvalidParams,
|
|
2320
|
+
capabilities: internals.device.caps,
|
|
2321
|
+
acceptedTemporal: frameState.lastSuccessfulTemporalView,
|
|
2322
|
+
transaction: frameState.temporalFrameTransaction.inspect(),
|
|
2323
|
+
execution: frameState.motionBlurExecution,
|
|
2324
|
+
temporalFrameId: frameState.temporalFrame?.frameId,
|
|
2325
|
+
deviceGeneration: internals.deviceScope.generation,
|
|
2326
|
+
graphGeneration: frameState.graphGeneration,
|
|
2327
|
+
});
|
|
2328
|
+
},
|
|
2329
|
+
get motionBlurInvalidParams(): MotionBlurValidationError | undefined {
|
|
2330
|
+
return lastMotionBlurInvalidParams;
|
|
2331
|
+
},
|
|
2332
|
+
get depthOfFieldInspection(): DepthOfFieldInspection | undefined {
|
|
2264
2333
|
const camera = latestCamera;
|
|
2265
|
-
if (camera
|
|
2266
|
-
const
|
|
2267
|
-
|
|
2268
|
-
|
|
2269
|
-
|
|
2270
|
-
|
|
2271
|
-
|
|
2272
|
-
|
|
2273
|
-
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
|
|
2277
|
-
|
|
2278
|
-
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
};
|
|
2334
|
+
if (camera === undefined) return undefined;
|
|
2335
|
+
const graph = frameState.compiledFrameGraph?.inspect();
|
|
2336
|
+
return projectDepthOfFieldInspection({
|
|
2337
|
+
...(camera.depthOfField === undefined ? {} : { params: camera.depthOfField }),
|
|
2338
|
+
...(camera.depthOfFieldError === undefined ? {} : { error: camera.depthOfFieldError }),
|
|
2339
|
+
...(graph === undefined ? {} : { graph }),
|
|
2340
|
+
// The explicit property keeps the inspector on the submit-bound
|
|
2341
|
+
// transaction path even before the first accepted frame. A missing
|
|
2342
|
+
// property remains supported for direct structural callers/tests.
|
|
2343
|
+
accepted: frameState.depthOfFieldAccepted,
|
|
2344
|
+
...(frameState.depthOfFieldLastSubmitFailed === true ? { lastSubmitFailed: true } : {}),
|
|
2345
|
+
// Inspection can be queried while the renderer is being assembled,
|
|
2346
|
+
// before a device scope has been published. Keep that observation
|
|
2347
|
+
// bounded instead of turning a not-yet-ready renderer into a getter
|
|
2348
|
+
// exception.
|
|
2349
|
+
deviceGeneration: internals.deviceScope?.generation ?? 0,
|
|
2350
|
+
});
|
|
2282
2351
|
},
|
|
2283
2352
|
get temporalTargetInspection(): TemporalTargetInspection | undefined {
|
|
2284
2353
|
const graph = frameState.compiledFrameGraph?.inspect();
|
|
@@ -2321,22 +2390,7 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
2321
2390
|
const lifecycle = resources?.inspectBloomResources?.(
|
|
2322
2391
|
frameState.compiledFrameGraph?.inspect(),
|
|
2323
2392
|
);
|
|
2324
|
-
return Object.freeze(
|
|
2325
|
-
lifecycle ?? {
|
|
2326
|
-
graphStatus: 'empty',
|
|
2327
|
-
enabled: false,
|
|
2328
|
-
targetCount: 0,
|
|
2329
|
-
targetBytes: 0,
|
|
2330
|
-
resourceCount: 0,
|
|
2331
|
-
passCount: 0,
|
|
2332
|
-
encodeCount: 0,
|
|
2333
|
-
bindGroupCount: 0,
|
|
2334
|
-
uploadCount: 0,
|
|
2335
|
-
residentChildBytes: 0,
|
|
2336
|
-
generation: 0,
|
|
2337
|
-
state: 'off',
|
|
2338
|
-
},
|
|
2339
|
-
);
|
|
2393
|
+
return Object.freeze(lifecycle ?? emptyBloomInspection());
|
|
2340
2394
|
},
|
|
2341
2395
|
get transmission(): TransmissionInspection | undefined {
|
|
2342
2396
|
return lastTransmissionInspection;
|
|
@@ -2411,6 +2465,10 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
2411
2465
|
const profileSession = internals.profiler?.activeSession();
|
|
2412
2466
|
let ownsProfileFrame = false;
|
|
2413
2467
|
let submitted = false;
|
|
2468
|
+
// A prior failed record/submit may have staged a temporal capture. A
|
|
2469
|
+
// capture belongs only to the draw call that created it; discard it
|
|
2470
|
+
// before this call can prepare or commit a new candidate.
|
|
2471
|
+
persistentRenderScene.discardTemporalFrame();
|
|
2414
2472
|
// A failed draw must never leave a previous frame eligible to publish a
|
|
2415
2473
|
// newly accepted dynamic-geometry candidate.
|
|
2416
2474
|
dynamicGeometryFrames.begin();
|
|
@@ -2442,55 +2500,67 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
2442
2500
|
dispatchCounts.unlit = 0;
|
|
2443
2501
|
|
|
2444
2502
|
const resourceWorld = compositionWorlds[resourceOwner] as World;
|
|
2445
|
-
|
|
2446
|
-
|
|
2447
|
-
|
|
2448
|
-
|
|
2449
|
-
|
|
2450
|
-
|
|
2451
|
-
|
|
2452
|
-
|
|
2453
|
-
|
|
2454
|
-
|
|
2455
|
-
|
|
2456
|
-
|
|
2457
|
-
|
|
2458
|
-
|
|
2459
|
-
|
|
2460
|
-
|
|
2461
|
-
|
|
2462
|
-
|
|
2463
|
-
|
|
2464
|
-
|
|
2465
|
-
|
|
2466
|
-
|
|
2467
|
-
|
|
2468
|
-
|
|
2469
|
-
|
|
2470
|
-
|
|
2471
|
-
|
|
2472
|
-
:
|
|
2473
|
-
|
|
2474
|
-
|
|
2475
|
-
|
|
2476
|
-
|
|
2477
|
-
|
|
2478
|
-
|
|
2479
|
-
|
|
2480
|
-
|
|
2481
|
-
|
|
2482
|
-
|
|
2483
|
-
|
|
2484
|
-
|
|
2485
|
-
|
|
2486
|
-
|
|
2487
|
-
|
|
2488
|
-
|
|
2489
|
-
|
|
2490
|
-
|
|
2491
|
-
|
|
2492
|
-
|
|
2493
|
-
|
|
2503
|
+
let frame: ReturnType<PersistentRenderScene['extractComposition']>;
|
|
2504
|
+
try {
|
|
2505
|
+
frame = runProfiledRenderPhase(profileSession, 'extract', () => {
|
|
2506
|
+
return persistentRenderScene.extractComposition(
|
|
2507
|
+
compositionWorlds,
|
|
2508
|
+
{ cameraOwner, resourceOwner },
|
|
2509
|
+
internals.assets.catalogEpoch,
|
|
2510
|
+
(renderables) =>
|
|
2511
|
+
extractFrames(
|
|
2512
|
+
compositionWorlds,
|
|
2513
|
+
{
|
|
2514
|
+
cameraOwner,
|
|
2515
|
+
resourceOwner,
|
|
2516
|
+
...(cameraEntityKey === undefined ? {} : { cameraEntityKey }),
|
|
2517
|
+
},
|
|
2518
|
+
internals.assets,
|
|
2519
|
+
internals.getPipelineState(),
|
|
2520
|
+
persistentRenderScene.materialSnapshotCacheStore(),
|
|
2521
|
+
{
|
|
2522
|
+
...(internals.device.caps.backendKind === 'null'
|
|
2523
|
+
? {}
|
|
2524
|
+
: {
|
|
2525
|
+
materialContext: {
|
|
2526
|
+
backend:
|
|
2527
|
+
internals.device.caps.backendKind === 'wgpu-webgl2'
|
|
2528
|
+
? ('webgl2' as const)
|
|
2529
|
+
: internals.device.caps.backendKind,
|
|
2530
|
+
capability: internals.device.caps.storageBuffer
|
|
2531
|
+
? ('storage-buffer' as const)
|
|
2532
|
+
: ('uniform-fallback' as const),
|
|
2533
|
+
pipeline: 'forward' as const,
|
|
2534
|
+
geometry: 'mesh' as const,
|
|
2535
|
+
pass: 'forward' as const,
|
|
2536
|
+
profile: 'forgeax-material-wgsl-v1' as const,
|
|
2537
|
+
toolchain: 'naga-oil' as const,
|
|
2538
|
+
instrumentation: 'none' as const,
|
|
2539
|
+
},
|
|
2540
|
+
}),
|
|
2541
|
+
cull: 'none',
|
|
2542
|
+
retainHidden: true,
|
|
2543
|
+
renderables,
|
|
2544
|
+
instanceCollections,
|
|
2545
|
+
...(!internals.device.caps.storageBuffer ||
|
|
2546
|
+
internals.getMaterialShaderArtifact === undefined
|
|
2547
|
+
? {}
|
|
2548
|
+
: { getMaterialShaderArtifact: internals.getMaterialShaderArtifact }),
|
|
2549
|
+
},
|
|
2550
|
+
),
|
|
2551
|
+
compositionLeases,
|
|
2552
|
+
);
|
|
2553
|
+
});
|
|
2554
|
+
} catch (cause) {
|
|
2555
|
+
if (cause instanceof MotionBlurValidationError) {
|
|
2556
|
+
lastMotionBlurInvalidParams = cause;
|
|
2557
|
+
latestCamera = undefined;
|
|
2558
|
+
internals.errorRegistry.fire(cause);
|
|
2559
|
+
return false;
|
|
2560
|
+
}
|
|
2561
|
+
throw cause;
|
|
2562
|
+
}
|
|
2563
|
+
lastMotionBlurInvalidParams = undefined;
|
|
2494
2564
|
const {
|
|
2495
2565
|
cameras: extractedCameras,
|
|
2496
2566
|
cubeCameras,
|
|
@@ -2727,6 +2797,15 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
2727
2797
|
const submissionRenderables = visibilityProjection.renderables;
|
|
2728
2798
|
const submissionDispatch = visibilityProjection.dispatch;
|
|
2729
2799
|
const inspectionCamera = latestCamera;
|
|
2800
|
+
// The public frame receipt is allocated by WebGPURenderer immediately
|
|
2801
|
+
// before this draw (`observationFrameId`). RenderSystem's private
|
|
2802
|
+
// frameNumber is an internal generation and also advances on failed
|
|
2803
|
+
// record attempts, so it cannot be used as receipt identity. Keep the
|
|
2804
|
+
// internal generation for recovery/visibility state, but bind the LOD
|
|
2805
|
+
// inspection to the frame id that the caller will receive.
|
|
2806
|
+
const lodSubmitFrameId =
|
|
2807
|
+
(internals as RenderSystemInternals & { readonly observationFrameId?: number })
|
|
2808
|
+
.observationFrameId ?? frameState.frameNumber;
|
|
2730
2809
|
let lodCandidateCountForFrame = 0;
|
|
2731
2810
|
if (inspectionCamera !== undefined) {
|
|
2732
2811
|
const firstRenderable = renderables[0];
|
|
@@ -2769,7 +2848,7 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
2769
2848
|
renderables,
|
|
2770
2849
|
submissionRenderables,
|
|
2771
2850
|
inspectionCamera,
|
|
2772
|
-
|
|
2851
|
+
lodSubmitFrameId,
|
|
2773
2852
|
worldKeys,
|
|
2774
2853
|
slotByEntity,
|
|
2775
2854
|
{
|
|
@@ -2801,7 +2880,7 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
2801
2880
|
firstRenderable === undefined
|
|
2802
2881
|
? 'none'
|
|
2803
2882
|
: `asset-handle:${firstRenderable.assetHandle}`,
|
|
2804
|
-
sourceKey: `render-frame:${
|
|
2883
|
+
sourceKey: `render-frame:${lodSubmitFrameId}`,
|
|
2805
2884
|
},
|
|
2806
2885
|
view: {
|
|
2807
2886
|
attachmentId:
|
|
@@ -2814,7 +2893,7 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
2814
2893
|
primitiveSlot: 0,
|
|
2815
2894
|
slotGeneration: persistentRenderScene.inspect().topology.revision,
|
|
2816
2895
|
},
|
|
2817
|
-
generation:
|
|
2896
|
+
generation: lodSubmitFrameId,
|
|
2818
2897
|
count: {
|
|
2819
2898
|
candidates: candidateCount,
|
|
2820
2899
|
visible: inspectionRenderables.length,
|
|
@@ -2833,7 +2912,7 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
2833
2912
|
visible: true,
|
|
2834
2913
|
})),
|
|
2835
2914
|
submit: {
|
|
2836
|
-
frameId:
|
|
2915
|
+
frameId: lodSubmitFrameId,
|
|
2837
2916
|
build: resolveInspectionBuild(internals),
|
|
2838
2917
|
deviceGeneration: internals.deviceScope.generation,
|
|
2839
2918
|
},
|
|
@@ -2845,7 +2924,14 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
2845
2924
|
lastLodWorldAttachments = new Map();
|
|
2846
2925
|
}
|
|
2847
2926
|
const temporalDemanded =
|
|
2848
|
-
cameras[0]?.antialias === 'taa' ||
|
|
2927
|
+
cameras[0]?.antialias === 'taa' ||
|
|
2928
|
+
(cameras[0]?.motionBlur !== undefined &&
|
|
2929
|
+
motionBlurTemporalDemand({
|
|
2930
|
+
shutterAngle: cameras[0].motionBlur.shutterAngle,
|
|
2931
|
+
maxRadiusPixels: cameras[0].motionBlur.maxRadiusPixels,
|
|
2932
|
+
sampleCount: cameras[0].motionBlur.sampleCount,
|
|
2933
|
+
targetFps: cameras[0].motionBlur.targetFps ?? 60,
|
|
2934
|
+
}));
|
|
2849
2935
|
if (temporalDemanded) {
|
|
2850
2936
|
persistentRenderScene.prepareTemporalFrame(submissionRenderables);
|
|
2851
2937
|
}
|
|
@@ -2888,6 +2974,7 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
2888
2974
|
const materialWorld = preparedWorlds[renderable.worldId];
|
|
2889
2975
|
return projectMeshMaterialBindingObservation({
|
|
2890
2976
|
worldId: renderable.worldId,
|
|
2977
|
+
...(materialWorld === undefined ? {} : { worldIdentity: materialWorld.identity }),
|
|
2891
2978
|
entityKey: renderable.entityKey,
|
|
2892
2979
|
bindings: renderable.materials.map((material, slotIndex) => ({
|
|
2893
2980
|
handle: material.materialHandle ?? 0,
|
|
@@ -2955,6 +3042,44 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
2955
3042
|
storageBuffer: internals.device.caps.storageBuffer,
|
|
2956
3043
|
multisample: internals.device.caps.backendKind !== 'wgpu-webgl2',
|
|
2957
3044
|
});
|
|
3045
|
+
const motionBlurParams = cameras[0]?.motionBlur;
|
|
3046
|
+
let motionBlurDelta = 0;
|
|
3047
|
+
try {
|
|
3048
|
+
const delta = (compositionWorlds[cameraOwner] as World).getResource(Time).delta;
|
|
3049
|
+
motionBlurDelta = Number.isFinite(delta) ? Math.max(0, delta) : 0;
|
|
3050
|
+
} catch {
|
|
3051
|
+
motionBlurDelta = 0;
|
|
3052
|
+
}
|
|
3053
|
+
const acceptedSampleTime = frameState.lastSuccessfulTemporalView?.sampleTimeSeconds;
|
|
3054
|
+
const cameraViewIdentity = `camera:${cameras[0]?.entityKey ?? 0}`;
|
|
3055
|
+
const canvasWidth = Math.max(1, internals.canvas.width);
|
|
3056
|
+
const canvasHeight = Math.max(1, internals.canvas.height);
|
|
3057
|
+
const motionBlurPlan = planMotionBlurFrame({
|
|
3058
|
+
params: motionBlurParams,
|
|
3059
|
+
sampleTimeSeconds: opts.sampleTimeSeconds,
|
|
3060
|
+
acceptedSampleTimeSeconds: acceptedSampleTime,
|
|
3061
|
+
fallbackDeltaSeconds: motionBlurDelta,
|
|
3062
|
+
acceptedTemporal: frameState.lastSuccessfulTemporalView,
|
|
3063
|
+
temporalReset: opts.temporalReset === true,
|
|
3064
|
+
width: canvasWidth,
|
|
3065
|
+
height: canvasHeight,
|
|
3066
|
+
cameraViewIdentity,
|
|
3067
|
+
historyVersion: cameras[0]?.historyVersion ?? 0,
|
|
3068
|
+
environmentSignature: environment?.environmentSignature ?? '',
|
|
3069
|
+
fogSignature: environment?.fogSignature ?? '',
|
|
3070
|
+
deviceGeneration: internals.deviceScope?.generation ?? 0,
|
|
3071
|
+
});
|
|
3072
|
+
const demandedMotionBlur = motionBlurPlan.demanded;
|
|
3073
|
+
motionBlurFeatureInput = motionBlurPlan.featureInput;
|
|
3074
|
+
if (
|
|
3075
|
+
demandedMotionBlur &&
|
|
3076
|
+
internals.device.caps.compute === true &&
|
|
3077
|
+
internals.device.caps.storageBuffer === true &&
|
|
3078
|
+
internals.device.caps.storageTexture === true &&
|
|
3079
|
+
internals.device.caps.rgba16floatRenderable === true
|
|
3080
|
+
) {
|
|
3081
|
+
ensureMotionBlurFeature();
|
|
3082
|
+
}
|
|
2958
3083
|
preparedFeatureSkylightResources =
|
|
2959
3084
|
preparedPipelineState === null
|
|
2960
3085
|
? undefined
|
|
@@ -2967,6 +3092,7 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
2967
3092
|
worlds: compositionWorlds,
|
|
2968
3093
|
owner: resourceOwner,
|
|
2969
3094
|
frameNumber: frameState.frameNumber,
|
|
3095
|
+
frameSize: { width: internals.canvas.width, height: internals.canvas.height },
|
|
2970
3096
|
visibilitySnapshots: frame.featureVisibilitySnapshots,
|
|
2971
3097
|
hiddenEntityReports: frame.hiddenEntityReports,
|
|
2972
3098
|
targets: featureTargets,
|
|
@@ -3001,11 +3127,12 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
3001
3127
|
gpuWork: featureGpuWork,
|
|
3002
3128
|
});
|
|
3003
3129
|
lastVisibilityStats.explicitlyHidden = featureFrame.hiddenEntityReports.length;
|
|
3004
|
-
|
|
3005
|
-
|
|
3006
|
-
|
|
3007
|
-
|
|
3008
|
-
|
|
3130
|
+
reportPendingRenderFeatureErrors(
|
|
3131
|
+
featureFrame.errors,
|
|
3132
|
+
frameState.frameNumber,
|
|
3133
|
+
pendingFeatureErrorLastReportedFrame,
|
|
3134
|
+
internals.errorRegistry,
|
|
3135
|
+
);
|
|
3009
3136
|
const postProcessParamsCandidate = preparePostProcessParamsResources(
|
|
3010
3137
|
featureFrame.fullscreenEffects,
|
|
3011
3138
|
);
|
|
@@ -3138,7 +3265,8 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
3138
3265
|
}
|
|
3139
3266
|
return runProfiledRenderPhase(profileSession, phase, action);
|
|
3140
3267
|
};
|
|
3141
|
-
|
|
3268
|
+
const bloomAdmitted = standardBloomAdmitted(cameras[0]);
|
|
3269
|
+
if (bloomAdmitted) {
|
|
3142
3270
|
internals.getPipelineState()?.perPassResources.ensureBloomResources?.();
|
|
3143
3271
|
}
|
|
3144
3272
|
const liveOutput = cameras[0]?.output;
|
|
@@ -3192,6 +3320,10 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
3192
3320
|
activeEntityKeys: visibilityProjection.activeEntityKeys,
|
|
3193
3321
|
activeEntityRevision: visibilityProjection.activeEntityRevision,
|
|
3194
3322
|
telemetryCandidateCount: lodCandidateCountForFrame,
|
|
3323
|
+
telemetrySubmit: {
|
|
3324
|
+
frameId: lodSubmitFrameId,
|
|
3325
|
+
deviceGeneration: internals.deviceScope.generation,
|
|
3326
|
+
},
|
|
3195
3327
|
...(occlusionProjection === undefined ? {} : { occlusion: occlusionProjection }),
|
|
3196
3328
|
},
|
|
3197
3329
|
compositionLeases,
|
|
@@ -3220,6 +3352,9 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
3220
3352
|
undefined,
|
|
3221
3353
|
ssrDependencies,
|
|
3222
3354
|
dynamicGeometryFrames.onRenderableDraw(compositionWorlds),
|
|
3355
|
+
environment?.fog,
|
|
3356
|
+
opts.sampleTimeSeconds,
|
|
3357
|
+
opts.temporalReset === true,
|
|
3223
3358
|
),
|
|
3224
3359
|
);
|
|
3225
3360
|
dynamicGeometryFrames.commit(submitted);
|
|
@@ -3283,8 +3418,31 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
3283
3418
|
internals.errorRegistry.fire(temporalCommit.error);
|
|
3284
3419
|
}
|
|
3285
3420
|
frameState.lastSuccessfulCameraAntialias = cameras[0]?.antialias;
|
|
3421
|
+
const submittedCamera = cameras[0];
|
|
3422
|
+
const submittedDepthOfField =
|
|
3423
|
+
submittedCamera === undefined
|
|
3424
|
+
? undefined
|
|
3425
|
+
: resolveDepthOfFieldFrameParams(
|
|
3426
|
+
submittedCamera.depthOfField,
|
|
3427
|
+
submittedCamera.depthOfFieldError,
|
|
3428
|
+
frameState.depthOfFieldAccepted?.params,
|
|
3429
|
+
);
|
|
3430
|
+
const submittedDepthOfFieldGraph = frameState.compiledFrameGraph?.inspect();
|
|
3431
|
+
if (submittedDepthOfField !== undefined && submittedDepthOfFieldGraph !== undefined) {
|
|
3432
|
+
frameState.depthOfFieldAccepted = {
|
|
3433
|
+
params: submittedDepthOfField,
|
|
3434
|
+
graph: submittedDepthOfFieldGraph,
|
|
3435
|
+
deviceGeneration: internals.deviceScope.generation,
|
|
3436
|
+
};
|
|
3437
|
+
frameState.depthOfFieldLastSubmitFailed = false;
|
|
3438
|
+
} else if (submittedDepthOfField === undefined) {
|
|
3439
|
+
frameState.depthOfFieldAccepted = undefined;
|
|
3440
|
+
frameState.depthOfFieldLastSubmitFailed = false;
|
|
3441
|
+
} else {
|
|
3442
|
+
frameState.depthOfFieldLastSubmitFailed = true;
|
|
3443
|
+
}
|
|
3286
3444
|
internals.getPipelineState()?.perPassResources.commitBloomResources?.();
|
|
3287
|
-
const nextBloom =
|
|
3445
|
+
const nextBloom = bloomAdmitted ? 'on' : 'off';
|
|
3288
3446
|
if (frameState.lastSuccessfulBloom === 'on' && nextBloom !== 'on') {
|
|
3289
3447
|
internals
|
|
3290
3448
|
.getPipelineState()
|
|
@@ -3294,6 +3452,9 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
3294
3452
|
}
|
|
3295
3453
|
frameState.lastSuccessfulBloom = nextBloom;
|
|
3296
3454
|
} else {
|
|
3455
|
+
if (cameras[0]?.depthOfField !== undefined) {
|
|
3456
|
+
frameState.depthOfFieldLastSubmitFailed = true;
|
|
3457
|
+
}
|
|
3297
3458
|
internals.getPipelineState()?.perPassResources.discardBloomResources?.();
|
|
3298
3459
|
}
|
|
3299
3460
|
if (!submitted && frameState.environmentGeneration !== undefined) {
|
|
@@ -3346,6 +3507,7 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
3346
3507
|
}),
|
|
3347
3508
|
);
|
|
3348
3509
|
} finally {
|
|
3510
|
+
if (!submitted) persistentRenderScene.discardTemporalFrame();
|
|
3349
3511
|
internals.recoveryColdWorkGuard?.endFrame();
|
|
3350
3512
|
if (ownsProfileFrame) {
|
|
3351
3513
|
try {
|
|
@@ -3364,13 +3526,46 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
3364
3526
|
const currentFrameId = frameState.frameNumber - 1;
|
|
3365
3527
|
return observeCurrentFrame(options, frameState.currentFrameObservationSource, currentFrameId);
|
|
3366
3528
|
},
|
|
3367
|
-
async observeLodOcclusion(
|
|
3529
|
+
async observeLodOcclusion(receipt?: {
|
|
3530
|
+
readonly frameId: number;
|
|
3531
|
+
readonly deviceGeneration: number;
|
|
3532
|
+
}): Promise<void> {
|
|
3533
|
+
const capturedInspection = lastLodOcclusionInspection;
|
|
3534
|
+
const capturedWorldAttachments = lastLodWorldAttachments;
|
|
3535
|
+
if (capturedInspection === undefined) return;
|
|
3536
|
+
if (
|
|
3537
|
+
receipt !== undefined &&
|
|
3538
|
+
(capturedInspection.submit.frameId !== receipt.frameId ||
|
|
3539
|
+
capturedInspection.submit.deviceGeneration !== receipt.deviceGeneration)
|
|
3540
|
+
)
|
|
3541
|
+
return;
|
|
3368
3542
|
await ensureOcclusionRuntime().waitForCompletions();
|
|
3369
|
-
|
|
3370
|
-
|
|
3543
|
+
if (lastLodOcclusionInspection !== capturedInspection) return;
|
|
3544
|
+
const selection = await gpuDrivenProduction.readLodSelection();
|
|
3545
|
+
if (lastLodOcclusionInspection !== capturedInspection || selection === undefined) return;
|
|
3546
|
+
if (
|
|
3547
|
+
selection.submit !== undefined &&
|
|
3548
|
+
(selection.submit.frameId !== capturedInspection.submit.frameId ||
|
|
3549
|
+
selection.submit.deviceGeneration !== capturedInspection.submit.deviceGeneration)
|
|
3550
|
+
)
|
|
3551
|
+
return;
|
|
3552
|
+
if (
|
|
3553
|
+
receipt !== undefined &&
|
|
3554
|
+
(selection.submit === undefined ||
|
|
3555
|
+
selection.submit.frameId !== receipt.frameId ||
|
|
3556
|
+
selection.submit.deviceGeneration !== receipt.deviceGeneration)
|
|
3557
|
+
)
|
|
3558
|
+
return;
|
|
3559
|
+
applyLodSelectionTelemetry(selection, capturedInspection, capturedWorldAttachments);
|
|
3560
|
+
const published = lastLodOcclusionInspection;
|
|
3561
|
+
if (
|
|
3562
|
+
published !== undefined &&
|
|
3563
|
+
published.submit.frameId === capturedInspection.submit.frameId &&
|
|
3564
|
+
published.submit.deviceGeneration === capturedInspection.submit.deviceGeneration
|
|
3565
|
+
) {
|
|
3371
3566
|
const queryLatency = ensureOcclusionRuntime().inspectQueryLatency();
|
|
3372
3567
|
lastLodOcclusionInspection = inspectLodOcclusion({
|
|
3373
|
-
...
|
|
3568
|
+
...published,
|
|
3374
3569
|
queryLatencyUs: {
|
|
3375
3570
|
median: queryLatency.median,
|
|
3376
3571
|
p95: queryLatency.p95,
|
|
@@ -3638,6 +3833,7 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
3638
3833
|
frameState.volumetricFogHistorySlot = null;
|
|
3639
3834
|
frameState.volumetricFogHistorySignature = null;
|
|
3640
3835
|
frameState.hdrpClusterMembership = null;
|
|
3836
|
+
settleDepthOfFieldGraphCandidate(frameState, false);
|
|
3641
3837
|
const compiled = frameState.compiledFrameGraph;
|
|
3642
3838
|
frameState.compiledFrameGraph = null;
|
|
3643
3839
|
frameState.compiledFrameGraphTopologyKey = null;
|
|
@@ -3645,6 +3841,14 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
3645
3841
|
frameState.standardLightingGraphSignature = '';
|
|
3646
3842
|
frameState.standardLightingInspection = undefined;
|
|
3647
3843
|
frameState.pointShadowInspection = undefined;
|
|
3844
|
+
frameState.depthOfFieldPreviousGraph = null;
|
|
3845
|
+
frameState.depthOfFieldPreviousGraphKey = null;
|
|
3846
|
+
frameState.depthOfFieldPreviousPerFrameGraph = undefined;
|
|
3847
|
+
frameState.depthOfFieldPreviousGraphGeneration = 0;
|
|
3848
|
+
frameState.depthOfFieldPreviousStandardLightingGraphSignature = '';
|
|
3849
|
+
frameState.depthOfFieldCandidateGraph = null;
|
|
3850
|
+
frameState.depthOfFieldAccepted = undefined;
|
|
3851
|
+
frameState.depthOfFieldLastSubmitFailed = false;
|
|
3648
3852
|
if (compiled !== null) compiled.retire().catch(() => undefined);
|
|
3649
3853
|
for (const retired of frameState.retiredCompiledFrameGraphs) {
|
|
3650
3854
|
retired.retire().catch(() => undefined);
|
|
@@ -3746,12 +3950,19 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
3746
3950
|
// handles cannot be used on the fresh device and the next draw must
|
|
3747
3951
|
// lazily build a new graph from the preserved ECS / asset POD caches.
|
|
3748
3952
|
settleVolumetricFogGraphCandidate(frameState, false);
|
|
3953
|
+
settleDepthOfFieldGraphCandidate(frameState, false);
|
|
3749
3954
|
frameState.compiledFrameGraph?.retire().catch(() => undefined);
|
|
3750
3955
|
frameState.compiledFrameGraph = null;
|
|
3751
3956
|
frameState.compiledFrameGraphTopologyKey = null;
|
|
3752
3957
|
frameState.volumetricFogPreviousGraph = null;
|
|
3753
3958
|
frameState.volumetricFogPreviousGraphKey = null;
|
|
3754
3959
|
frameState.volumetricFogCandidateGraph = null;
|
|
3960
|
+
frameState.depthOfFieldPreviousGraph = null;
|
|
3961
|
+
frameState.depthOfFieldPreviousGraphKey = null;
|
|
3962
|
+
frameState.depthOfFieldPreviousPerFrameGraph = undefined;
|
|
3963
|
+
frameState.depthOfFieldPreviousGraphGeneration = 0;
|
|
3964
|
+
frameState.depthOfFieldPreviousStandardLightingGraphSignature = '';
|
|
3965
|
+
frameState.depthOfFieldCandidateGraph = null;
|
|
3755
3966
|
frameState.volumetricFogAccepted = undefined;
|
|
3756
3967
|
frameState.volumetricFogAcceptedContext = undefined;
|
|
3757
3968
|
frameState.volumetricFogHistoryGraph = null;
|
|
@@ -3772,6 +3983,8 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
3772
3983
|
frameState.standardLightingGraphSignature = '';
|
|
3773
3984
|
frameState.standardLightingInspection = undefined;
|
|
3774
3985
|
frameState.pointShadowInspection = undefined;
|
|
3986
|
+
frameState.depthOfFieldAccepted = undefined;
|
|
3987
|
+
frameState.depthOfFieldLastSubmitFailed = false;
|
|
3775
3988
|
frameState.directionalShadowCache = null;
|
|
3776
3989
|
frameState.directionalShadowCacheRecorded = false;
|
|
3777
3990
|
frameState.currentFrameObservationSource = undefined;
|