@forgeax/engine-render 0.1.32 → 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 +379 -33
- 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 +1 -1
- 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-DRR7D3KX.mjs → chunk-3RTCJTH4.mjs} +12 -9
- package/dist/chunk-3RTCJTH4.mjs.map +1 -0
- package/dist/{chunk-S665NJNF.mjs → chunk-LEAXOMYJ.mjs} +3 -3
- package/dist/{chunk-S665NJNF.mjs.map → chunk-LEAXOMYJ.mjs.map} +1 -1
- package/dist/{chunk-6TFBXLRJ.mjs → chunk-NB2S7ZRX.mjs} +155 -11
- package/dist/chunk-NB2S7ZRX.mjs.map +1 -0
- package/dist/{chunk-LULCA3OF.mjs → chunk-NNQL7CB3.mjs} +4 -4
- package/dist/{chunk-LULCA3OF.mjs.map → chunk-NNQL7CB3.mjs.map} +1 -1
- package/dist/{chunk-4NNZQCL3.mjs → chunk-OO3DRYK7.mjs} +66 -200
- package/dist/chunk-OO3DRYK7.mjs.map +1 -0
- package/dist/{chunk-GWCEMDVR.mjs → chunk-PLAXOOX5.mjs} +232 -7
- package/dist/chunk-PLAXOOX5.mjs.map +1 -0
- package/dist/{chunk-JRIPCMYC.mjs → chunk-VOZWDM3L.mjs} +283 -193
- package/dist/chunk-VOZWDM3L.mjs.map +1 -0
- package/dist/{chunk-JCIRYQ4V.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/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 +2865 -526
- 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/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/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 +5 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.mjs +5 -5
- package/dist/inspection-types.d.ts +43 -2
- package/dist/inspection-types.d.ts.map +1 -1
- package/dist/instances.d.ts +8 -1
- package/dist/instances.d.ts.map +1 -1
- package/dist/internal.mjs +6 -6
- 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/record/frame-snapshot.d.ts +3 -0
- 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/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 +1 -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 +24 -4
- package/dist/render-contract.d.ts.map +1 -1
- package/dist/render-pipeline.d.ts +3 -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 +8 -1
- package/dist/render-system-extract.d.ts.map +1 -1
- package/dist/render-system.d.ts +7 -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/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-indirect-raster-evidence.ts +2 -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 +75 -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 +21 -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 +181 -245
- package/src/assembly/webgpu-renderer.ts +16 -31
- 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/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 +20 -7
- package/src/extract/contracts.ts +7 -0
- package/src/extract/environment.ts +4 -0
- package/src/features/error-reporting.ts +78 -0
- package/src/features/host.ts +25 -12
- 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/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 +32 -0
- package/src/inspection-types.ts +60 -2
- package/src/instances.ts +80 -1
- package/src/pipeline/standard-post.ts +307 -78
- package/src/pipeline-spec.ts +5 -5
- 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 +5 -1
- package/src/record/frame-targets.ts +10 -6
- package/src/record/frame.ts +163 -22
- package/src/record/main-pass-geometry.ts +30 -1
- package/src/record/main-pass-sprite-draws.ts +6 -1
- 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 +153 -9
- package/src/recovery/render-system-candidate.ts +22 -10
- package/src/render-contract.ts +23 -4
- package/src/render-pipeline.ts +6 -1
- package/src/render-system-extract-tail.ts +16 -0
- package/src/render-system-extract.ts +45 -13
- package/src/render-system.ts +255 -120
- 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 +121 -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-4NNZQCL3.mjs.map +0 -1
- package/dist/chunk-6TFBXLRJ.mjs.map +0 -1
- package/dist/chunk-DRR7D3KX.mjs.map +0 -1
- package/dist/chunk-GWCEMDVR.mjs.map +0 -1
- package/dist/chunk-JCIRYQ4V.mjs.map +0 -1
- package/dist/chunk-JRIPCMYC.mjs.map +0 -1
|
@@ -5,6 +5,7 @@ import type {
|
|
|
5
5
|
} from '@forgeax/engine-render-graph';
|
|
6
6
|
import { RenderGraphError } from '@forgeax/engine-render-graph';
|
|
7
7
|
import { err, ok, type Result } from '@forgeax/engine-types';
|
|
8
|
+
import { standardBloomAdmitted } from '../bloom-admission';
|
|
8
9
|
import { addTypedDebugOverlayPass } from '../debug-draw-glue';
|
|
9
10
|
import { SceneDataUnavailableError } from '../errors/render';
|
|
10
11
|
import { addDepthOfFieldPasses } from '../features/depth-of-field/depth-of-field-feature';
|
|
@@ -30,6 +31,7 @@ import {
|
|
|
30
31
|
TYPED_BLOOM_PASS_NAMES,
|
|
31
32
|
type TypedTemporalResolveTargets,
|
|
32
33
|
} from '../typed-render-graph-primitives';
|
|
34
|
+
import { renderExtentSize } from './render-extent';
|
|
33
35
|
import {
|
|
34
36
|
addAutoExposureExposurePass,
|
|
35
37
|
addAutoExposureGraphPasses,
|
|
@@ -42,22 +44,81 @@ interface StandardPostSurface {
|
|
|
42
44
|
readonly storage: RenderPipelineTarget;
|
|
43
45
|
}
|
|
44
46
|
|
|
47
|
+
export const STANDARD_BLOOM_MAX_LEVELS = 5;
|
|
48
|
+
|
|
45
49
|
/** One authored Bloom contract drives declaration and compiled-graph validation. */
|
|
46
50
|
export const STANDARD_BLOOM_TARGET_SPEC = {
|
|
47
|
-
composited: { label: 'bloom-composited', format: 'rgba16float'
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
51
|
+
composited: { label: 'bloom-composited', format: 'rgba16float' },
|
|
52
|
+
downsamplePrefix: 'bloom-downsample-',
|
|
53
|
+
upsamplePrefix: 'bloom-upsample-',
|
|
54
|
+
} as const;
|
|
55
|
+
|
|
56
|
+
export interface StandardBloomLevelDimensions {
|
|
57
|
+
readonly width: number;
|
|
58
|
+
readonly height: number;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/** Derive the bounded ceil-halving output pyramid, including D0. */
|
|
62
|
+
export function deriveStandardBloomLevels(
|
|
63
|
+
outputWidth: number,
|
|
64
|
+
outputHeight: number,
|
|
65
|
+
): readonly StandardBloomLevelDimensions[] {
|
|
66
|
+
const levels: StandardBloomLevelDimensions[] = [];
|
|
67
|
+
let width = Math.max(1, Math.ceil(outputWidth / 2));
|
|
68
|
+
let height = Math.max(1, Math.ceil(outputHeight / 2));
|
|
69
|
+
for (let level = 0; level < STANDARD_BLOOM_MAX_LEVELS; level += 1) {
|
|
70
|
+
levels.push({ width, height });
|
|
71
|
+
if (width === 1 && height === 1) break;
|
|
72
|
+
width = Math.max(1, Math.ceil(width / 2));
|
|
73
|
+
height = Math.max(1, Math.ceil(height / 2));
|
|
74
|
+
}
|
|
75
|
+
return levels;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export interface StandardBloomTargetSpecs {
|
|
79
|
+
readonly composited: GraphTextureDescriptor & { readonly label: string };
|
|
80
|
+
readonly downsample: readonly (GraphTextureDescriptor & { readonly label: string })[];
|
|
81
|
+
readonly upsample: readonly (GraphTextureDescriptor & { readonly label: string })[];
|
|
82
|
+
readonly levels: readonly StandardBloomLevelDimensions[];
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function standardBloomTargetSpecs(
|
|
86
|
+
outputWidth: number,
|
|
87
|
+
outputHeight: number,
|
|
88
|
+
): StandardBloomTargetSpecs {
|
|
89
|
+
const levels = deriveStandardBloomLevels(outputWidth, outputHeight);
|
|
90
|
+
return {
|
|
91
|
+
composited: {
|
|
92
|
+
label: STANDARD_BLOOM_TARGET_SPEC.composited.label,
|
|
93
|
+
format: STANDARD_BLOOM_TARGET_SPEC.composited.format,
|
|
94
|
+
size: { width: outputWidth, height: outputHeight },
|
|
95
|
+
domain: 'linear-hdr',
|
|
96
|
+
},
|
|
97
|
+
downsample: levels.map((size, level) => ({
|
|
98
|
+
label: `${STANDARD_BLOOM_TARGET_SPEC.downsamplePrefix}${level}`,
|
|
99
|
+
format: 'rgba16float' as const,
|
|
100
|
+
size,
|
|
101
|
+
domain: 'linear-hdr' as const,
|
|
102
|
+
})),
|
|
103
|
+
upsample: levels.slice(0, -1).map((size, level) => ({
|
|
104
|
+
label: `${STANDARD_BLOOM_TARGET_SPEC.upsamplePrefix}${level}`,
|
|
105
|
+
format: 'rgba16float' as const,
|
|
106
|
+
size,
|
|
107
|
+
domain: 'linear-hdr' as const,
|
|
108
|
+
})),
|
|
109
|
+
levels,
|
|
110
|
+
};
|
|
111
|
+
}
|
|
55
112
|
|
|
56
113
|
export interface StandardBloomGraphInspection {
|
|
57
114
|
readonly status: 'empty' | 'valid' | 'invalid';
|
|
58
115
|
readonly targetCount: number;
|
|
59
116
|
readonly targetBytes: number;
|
|
60
117
|
readonly passCount: number;
|
|
118
|
+
readonly levelCount: number;
|
|
119
|
+
readonly levelDimensions: readonly StandardBloomLevelDimensions[];
|
|
120
|
+
readonly downsamplePassCount: number;
|
|
121
|
+
readonly upsamplePassCount: number;
|
|
61
122
|
}
|
|
62
123
|
|
|
63
124
|
const emptyBloomGraphInspection = (): StandardBloomGraphInspection => ({
|
|
@@ -65,6 +126,10 @@ const emptyBloomGraphInspection = (): StandardBloomGraphInspection => ({
|
|
|
65
126
|
targetCount: 0,
|
|
66
127
|
targetBytes: 0,
|
|
67
128
|
passCount: 0,
|
|
129
|
+
levelCount: 0,
|
|
130
|
+
levelDimensions: [],
|
|
131
|
+
downsamplePassCount: 0,
|
|
132
|
+
upsamplePassCount: 0,
|
|
68
133
|
});
|
|
69
134
|
|
|
70
135
|
const invalidBloomGraphInspection = (): StandardBloomGraphInspection => ({
|
|
@@ -72,21 +137,23 @@ const invalidBloomGraphInspection = (): StandardBloomGraphInspection => ({
|
|
|
72
137
|
targetCount: 0,
|
|
73
138
|
targetBytes: 0,
|
|
74
139
|
passCount: 0,
|
|
140
|
+
levelCount: 0,
|
|
141
|
+
levelDimensions: [],
|
|
142
|
+
downsamplePassCount: 0,
|
|
143
|
+
upsamplePassCount: 0,
|
|
75
144
|
});
|
|
76
145
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
): number {
|
|
146
|
+
type CompiledBloomResource = CompiledRenderGraphInfo['resources'][number];
|
|
147
|
+
|
|
148
|
+
function textureBytes(resource: CompiledBloomResource): number | undefined {
|
|
81
149
|
const descriptor = resource.descriptor;
|
|
82
150
|
if (
|
|
151
|
+
resource.kind !== 'texture' ||
|
|
83
152
|
descriptor === undefined ||
|
|
84
153
|
descriptor.kind !== 'texture' ||
|
|
85
|
-
descriptor.format !==
|
|
86
|
-
!('size' in descriptor) ||
|
|
87
|
-
descriptor.size !== expected.size
|
|
154
|
+
descriptor.format !== 'rgba16float'
|
|
88
155
|
)
|
|
89
|
-
return
|
|
156
|
+
return undefined;
|
|
90
157
|
const texelBytes = 8;
|
|
91
158
|
let bytes = 0;
|
|
92
159
|
for (let level = 0; level < descriptor.mipLevelCount; level += 1) {
|
|
@@ -96,7 +163,56 @@ function textureBytes(
|
|
|
96
163
|
descriptor.depthOrArrayLayers *
|
|
97
164
|
texelBytes;
|
|
98
165
|
}
|
|
99
|
-
|
|
166
|
+
const descriptorBytes = bytes * descriptor.sampleCount;
|
|
167
|
+
return resource.byteSize === descriptorBytes && descriptorBytes > 0 ? descriptorBytes : undefined;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
function resourceSize(
|
|
171
|
+
resource: CompiledBloomResource,
|
|
172
|
+
): { readonly width: number; readonly height: number } | undefined {
|
|
173
|
+
const descriptor = resource.descriptor;
|
|
174
|
+
if (resource.kind !== 'texture' || descriptor.kind !== 'texture') return undefined;
|
|
175
|
+
if (typeof descriptor.size === 'string') return undefined;
|
|
176
|
+
if (
|
|
177
|
+
resource.extent === undefined ||
|
|
178
|
+
resource.extent.width !== descriptor.width ||
|
|
179
|
+
resource.extent.height !== descriptor.height ||
|
|
180
|
+
resource.extent.depthOrArrayLayers !== descriptor.depthOrArrayLayers
|
|
181
|
+
) {
|
|
182
|
+
return undefined;
|
|
183
|
+
}
|
|
184
|
+
if (
|
|
185
|
+
descriptor.format !== 'rgba16float' ||
|
|
186
|
+
descriptor.domain !== 'linear-hdr' ||
|
|
187
|
+
descriptor.width <= 0 ||
|
|
188
|
+
descriptor.height <= 0 ||
|
|
189
|
+
descriptor.depthOrArrayLayers !== 1 ||
|
|
190
|
+
descriptor.mipLevelCount !== 1 ||
|
|
191
|
+
descriptor.sampleCount !== 1 ||
|
|
192
|
+
resource.dimension !== '2d' ||
|
|
193
|
+
descriptor.size.width !== descriptor.width ||
|
|
194
|
+
descriptor.size.height !== descriptor.height ||
|
|
195
|
+
textureBytes(resource) === undefined
|
|
196
|
+
) {
|
|
197
|
+
return undefined;
|
|
198
|
+
}
|
|
199
|
+
return { width: descriptor.width, height: descriptor.height };
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
function hasPassAccesses(
|
|
203
|
+
pass: CompiledRenderGraphInfo['passes'][number] | undefined,
|
|
204
|
+
accesses: readonly { readonly resource: string; readonly usage: string }[],
|
|
205
|
+
): boolean {
|
|
206
|
+
return (
|
|
207
|
+
pass !== undefined &&
|
|
208
|
+
pass.kind === 'raster' &&
|
|
209
|
+
pass.accesses.length === accesses.length &&
|
|
210
|
+
accesses.every(
|
|
211
|
+
(access, index) =>
|
|
212
|
+
pass.accesses[index]?.resource === access.resource &&
|
|
213
|
+
pass.accesses[index]?.usage === access.usage,
|
|
214
|
+
)
|
|
215
|
+
);
|
|
100
216
|
}
|
|
101
217
|
|
|
102
218
|
/** Derive Bloom target/pass facts solely from the compiled Standard graph. */
|
|
@@ -104,33 +220,125 @@ export function inspectStandardBloomGraph(
|
|
|
104
220
|
graph: CompiledRenderGraphInfo | undefined,
|
|
105
221
|
): StandardBloomGraphInspection {
|
|
106
222
|
if (graph === undefined) return emptyBloomGraphInspection();
|
|
107
|
-
|
|
108
|
-
(
|
|
109
|
-
const targetSpec = new Map<string, BloomTargetSpec>(
|
|
110
|
-
Object.values(STANDARD_BLOOM_TARGET_SPEC).map((entry) => [entry.label, entry] as const),
|
|
223
|
+
const composited = graph.resources.filter(
|
|
224
|
+
(resource) => resource.label === STANDARD_BLOOM_TARGET_SPEC.composited.label,
|
|
111
225
|
);
|
|
112
|
-
const
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
226
|
+
const downsample = graph.resources
|
|
227
|
+
.filter((resource) => resource.label.startsWith(STANDARD_BLOOM_TARGET_SPEC.downsamplePrefix))
|
|
228
|
+
.sort((a, b) => a.label.localeCompare(b.label, undefined, { numeric: true }));
|
|
229
|
+
const upsample = graph.resources
|
|
230
|
+
.filter((resource) => resource.label.startsWith(STANDARD_BLOOM_TARGET_SPEC.upsamplePrefix))
|
|
231
|
+
.sort((a, b) => a.label.localeCompare(b.label, undefined, { numeric: true }));
|
|
232
|
+
const targets = [...composited, ...downsample, ...upsample];
|
|
233
|
+
const passes = graph.passes
|
|
234
|
+
.filter(
|
|
235
|
+
(pass) =>
|
|
236
|
+
pass.name === TYPED_BLOOM_PASS_NAMES.composite ||
|
|
237
|
+
pass.name.startsWith(`${TYPED_BLOOM_PASS_NAMES.downsample}-`) ||
|
|
238
|
+
pass.name.startsWith(`${TYPED_BLOOM_PASS_NAMES.upsample}-`),
|
|
239
|
+
)
|
|
240
|
+
.sort((left, right) => left.executionIndex - right.executionIndex);
|
|
118
241
|
if (targets.length === 0 && passes.length === 0) return emptyBloomGraphInspection();
|
|
242
|
+
if (composited.length !== 1) return invalidBloomGraphInspection();
|
|
243
|
+
const compositedResource = composited[0];
|
|
244
|
+
if (compositedResource === undefined) return invalidBloomGraphInspection();
|
|
245
|
+
const compositedSize = resourceSize(compositedResource);
|
|
246
|
+
if (compositedSize === undefined) return invalidBloomGraphInspection();
|
|
247
|
+
|
|
248
|
+
const expected = standardBloomTargetSpecs(compositedSize.width, compositedSize.height);
|
|
249
|
+
const expectedDownsampleLabels = expected.downsample.map((entry) => entry.label);
|
|
250
|
+
const expectedUpsampleLabels = expected.upsample.map((entry) => entry.label);
|
|
251
|
+
const orderedDownsample = downsample.sort((left, right) =>
|
|
252
|
+
left.label.localeCompare(right.label, undefined, { numeric: true }),
|
|
253
|
+
);
|
|
254
|
+
const orderedUpsample = upsample.sort((left, right) =>
|
|
255
|
+
left.label.localeCompare(right.label, undefined, { numeric: true }),
|
|
256
|
+
);
|
|
119
257
|
const completeTargetSet =
|
|
120
|
-
targets.length ===
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
258
|
+
targets.length === 1 + expectedDownsampleLabels.length + expectedUpsampleLabels.length &&
|
|
259
|
+
orderedDownsample.length === expectedDownsampleLabels.length &&
|
|
260
|
+
orderedUpsample.length === expectedUpsampleLabels.length &&
|
|
261
|
+
orderedDownsample.every(
|
|
262
|
+
(resource, level) => resource.label === expectedDownsampleLabels[level],
|
|
263
|
+
) &&
|
|
264
|
+
orderedUpsample.every((resource, level) => resource.label === expectedUpsampleLabels[level]) &&
|
|
265
|
+
orderedDownsample.every(
|
|
266
|
+
(resource, level) =>
|
|
267
|
+
resourceSize(resource)?.width === expected.levels[level]?.width &&
|
|
268
|
+
resourceSize(resource)?.height === expected.levels[level]?.height,
|
|
269
|
+
) &&
|
|
270
|
+
orderedUpsample.every(
|
|
271
|
+
(resource, level) =>
|
|
272
|
+
resourceSize(resource)?.width === expected.levels[level]?.width &&
|
|
273
|
+
resourceSize(resource)?.height === expected.levels[level]?.height,
|
|
274
|
+
);
|
|
275
|
+
const expectedPassNames = [
|
|
276
|
+
...expectedDownsampleLabels,
|
|
277
|
+
...[...expectedUpsampleLabels].reverse(),
|
|
278
|
+
TYPED_BLOOM_PASS_NAMES.composite,
|
|
279
|
+
];
|
|
280
|
+
const completePassSet =
|
|
281
|
+
passes.length === expected.levels.length + expected.upsample.length + 1 &&
|
|
282
|
+
passes.every((pass, index) => pass.name === expectedPassNames[index]);
|
|
283
|
+
const sceneLabel = passes[0]?.accesses[0]?.resource;
|
|
284
|
+
const passTopology =
|
|
285
|
+
completePassSet &&
|
|
286
|
+
sceneLabel !== undefined &&
|
|
287
|
+
!sceneLabel.startsWith(STANDARD_BLOOM_TARGET_SPEC.downsamplePrefix) &&
|
|
288
|
+
!sceneLabel.startsWith(STANDARD_BLOOM_TARGET_SPEC.upsamplePrefix) &&
|
|
289
|
+
sceneLabel !== STANDARD_BLOOM_TARGET_SPEC.composited.label &&
|
|
290
|
+
graph.resources.some((resource) => resource.label === sceneLabel) &&
|
|
291
|
+
orderedDownsample.every((_, level) =>
|
|
292
|
+
hasPassAccesses(passes[level], [
|
|
293
|
+
{
|
|
294
|
+
resource: level === 0 ? sceneLabel : `bloom-downsample-${level - 1}`,
|
|
295
|
+
usage: 'sampled-read',
|
|
296
|
+
},
|
|
297
|
+
{ resource: `bloom-downsample-${level}`, usage: 'color-attachment' },
|
|
298
|
+
]),
|
|
299
|
+
) &&
|
|
300
|
+
orderedUpsample.every((_, level) => {
|
|
301
|
+
const passIndex = expected.levels.length + expected.upsample.length - 1 - level;
|
|
302
|
+
return hasPassAccesses(passes[passIndex], [
|
|
303
|
+
{ resource: `bloom-downsample-${level}`, usage: 'sampled-read' },
|
|
304
|
+
{
|
|
305
|
+
resource:
|
|
306
|
+
level === expected.levels.length - 2
|
|
307
|
+
? `bloom-downsample-${level + 1}`
|
|
308
|
+
: `bloom-upsample-${level + 1}`,
|
|
309
|
+
usage: 'sampled-read',
|
|
310
|
+
},
|
|
311
|
+
{ resource: `bloom-upsample-${level}`, usage: 'color-attachment' },
|
|
312
|
+
]);
|
|
313
|
+
}) &&
|
|
314
|
+
hasPassAccesses(passes.at(-1), [
|
|
315
|
+
{ resource: sceneLabel, usage: 'sampled-read' },
|
|
316
|
+
{
|
|
317
|
+
resource: expected.levels.length === 1 ? 'bloom-downsample-0' : 'bloom-upsample-0',
|
|
318
|
+
usage: 'sampled-read',
|
|
319
|
+
},
|
|
320
|
+
{ resource: STANDARD_BLOOM_TARGET_SPEC.composited.label, usage: 'color-attachment' },
|
|
321
|
+
]);
|
|
322
|
+
if (!completeTargetSet || !passTopology) {
|
|
124
323
|
return invalidBloomGraphInspection();
|
|
125
324
|
}
|
|
325
|
+
const levelDimensions = orderedDownsample.flatMap((resource) => {
|
|
326
|
+
const size = resourceSize(resource);
|
|
327
|
+
return size === undefined ? [] : [size];
|
|
328
|
+
});
|
|
329
|
+
if (levelDimensions.length !== orderedDownsample.length) {
|
|
330
|
+
return invalidBloomGraphInspection();
|
|
331
|
+
}
|
|
332
|
+
const targetBytes = targets.reduce((bytes, resource) => bytes + (textureBytes(resource) ?? 0), 0);
|
|
126
333
|
return {
|
|
127
334
|
status: 'valid',
|
|
128
335
|
targetCount: targets.length,
|
|
129
|
-
targetBytes
|
|
130
|
-
(bytes, target) => bytes + textureBytes(target.resource, target.expected),
|
|
131
|
-
0,
|
|
132
|
-
),
|
|
336
|
+
targetBytes,
|
|
133
337
|
passCount: passes.length,
|
|
338
|
+
levelCount: orderedDownsample.length,
|
|
339
|
+
levelDimensions,
|
|
340
|
+
downsamplePassCount: orderedDownsample.length,
|
|
341
|
+
upsamplePassCount: orderedUpsample.length,
|
|
134
342
|
};
|
|
135
343
|
}
|
|
136
344
|
|
|
@@ -160,8 +368,8 @@ function missingTemporalContributor(
|
|
|
160
368
|
/**
|
|
161
369
|
* Build the one Standard post chain shared by direct and clustered lighting.
|
|
162
370
|
* Bloom is admitted before any Bloom target is declared, keeping the disabled
|
|
163
|
-
* path exact-zero while
|
|
164
|
-
*
|
|
371
|
+
* path exact-zero while building one bounded five-level HDR
|
|
372
|
+
* downsample/tent-upsample pyramid for the enabled path.
|
|
165
373
|
*/
|
|
166
374
|
export function addStandardPost(
|
|
167
375
|
context: RenderPipelineBuildContext<RenderPipelineFrame>,
|
|
@@ -179,7 +387,7 @@ export function addStandardPost(
|
|
|
179
387
|
lane: topology.standardProfile?.renderPath === 'deferred' ? 'clustered' : 'direct',
|
|
180
388
|
temporal: !clearOnly && topology.camera.antialias === 'taa',
|
|
181
389
|
meter: topology.output?.autoExposure === true,
|
|
182
|
-
bloom: !clearOnly && topology.camera
|
|
390
|
+
bloom: !clearOnly && standardBloomAdmitted(topology.camera),
|
|
183
391
|
dof: !clearOnly && topology.camera.depthOfField !== undefined,
|
|
184
392
|
exposure: topology.output?.autoExposure === true,
|
|
185
393
|
whiteBalance: topology.output?.whiteBalance === true,
|
|
@@ -220,6 +428,33 @@ export function addStandardPost(
|
|
|
220
428
|
const finalPresent = surface.storage;
|
|
221
429
|
let postInput = scene;
|
|
222
430
|
let postTemporal = sceneTemporal;
|
|
431
|
+
if (!clearOnly && topology.analyticFog === true) {
|
|
432
|
+
if (depth.sampleCount !== 1)
|
|
433
|
+
return err(
|
|
434
|
+
new RenderGraphError({
|
|
435
|
+
code: 'resource-resolution-failed',
|
|
436
|
+
expected: 'analytic fog receives single-sample scene depth',
|
|
437
|
+
hint: 'select FXAA, TAA or no AA for analytic fog',
|
|
438
|
+
detail: { resourceLabel: 'scene-depth' },
|
|
439
|
+
}),
|
|
440
|
+
);
|
|
441
|
+
const fogged = target(context, 'analytic-fog-color', {
|
|
442
|
+
format: 'rgba16float',
|
|
443
|
+
size:
|
|
444
|
+
topology.extent === undefined ? 'surface' : renderExtentSize(topology.extent, 'internal'),
|
|
445
|
+
domain: hdr ? 'linear-hdr' : 'linear-ldr',
|
|
446
|
+
});
|
|
447
|
+
if (!fogged.ok) return fogged;
|
|
448
|
+
const fog = addTypedFullscreenPass(context.graph, {
|
|
449
|
+
name: 'analytic-fog',
|
|
450
|
+
shader: 'forgeax.analytic-fog',
|
|
451
|
+
input: postInput,
|
|
452
|
+
depth,
|
|
453
|
+
output: fogged.value,
|
|
454
|
+
});
|
|
455
|
+
if (!fog.ok) return fog;
|
|
456
|
+
postInput = fogged.value;
|
|
457
|
+
}
|
|
223
458
|
|
|
224
459
|
const autoExposure = context.standardOutput?.autoExposure;
|
|
225
460
|
if (outputPlan.features.exposure && autoExposure === undefined) {
|
|
@@ -241,7 +476,7 @@ export function addStandardPost(
|
|
|
241
476
|
return err(missingTemporalContributor(topology, 'forgeax::standard::taa-history'));
|
|
242
477
|
}
|
|
243
478
|
const resolveTargets: TypedTemporalResolveTargets = {
|
|
244
|
-
scene,
|
|
479
|
+
scene: postInput,
|
|
245
480
|
depth,
|
|
246
481
|
currentTemporal: sceneTemporal,
|
|
247
482
|
...(coverage === undefined ? {} : { coverage }),
|
|
@@ -262,6 +497,20 @@ export function addStandardPost(
|
|
|
262
497
|
postTemporal = history.currentTemporal;
|
|
263
498
|
}
|
|
264
499
|
|
|
500
|
+
// Meter the temporally resolved color before lens-domain filters. Motion
|
|
501
|
+
// Blur and Bloom must consume a single exposure decision for this frame;
|
|
502
|
+
// running the meter after either filter makes the measured luminance depend
|
|
503
|
+
// on the authored streak radius and changes the exposure feedback loop.
|
|
504
|
+
if (outputPlan.features.exposure && autoExposure !== undefined) {
|
|
505
|
+
const added = addAutoExposureGraphPasses(context, {
|
|
506
|
+
source: postInput,
|
|
507
|
+
resources: autoExposure,
|
|
508
|
+
width: topology.surface.width,
|
|
509
|
+
height: topology.surface.height,
|
|
510
|
+
});
|
|
511
|
+
if (!added.ok) return added;
|
|
512
|
+
}
|
|
513
|
+
|
|
265
514
|
// Feature projection and the built-in fallback share one target contract.
|
|
266
515
|
// The projection runs after TAA so Motion Blur consumes the resolved color,
|
|
267
516
|
// then both paths feed the same linear float target into Bloom/Output.
|
|
@@ -315,18 +564,6 @@ export function addStandardPost(
|
|
|
315
564
|
}
|
|
316
565
|
}
|
|
317
566
|
|
|
318
|
-
// Meter the temporally resolved color before DoF/Bloom. This preserves the
|
|
319
|
-
// Standard order: temporal -> motion -> meter -> DoF -> bloom -> output.
|
|
320
|
-
if (outputPlan.features.exposure && autoExposure !== undefined) {
|
|
321
|
-
const added = addAutoExposureGraphPasses(context, {
|
|
322
|
-
source: postInput,
|
|
323
|
-
resources: autoExposure,
|
|
324
|
-
width: topology.surface.width,
|
|
325
|
-
height: topology.surface.height,
|
|
326
|
-
});
|
|
327
|
-
if (!added.ok) return added;
|
|
328
|
-
}
|
|
329
|
-
|
|
330
567
|
if (outputPlan.features.dof) {
|
|
331
568
|
const dof = addDepthOfFieldPasses(
|
|
332
569
|
{
|
|
@@ -343,38 +580,30 @@ export function addStandardPost(
|
|
|
343
580
|
if (!dof.ok) return dof;
|
|
344
581
|
postInput = dof.value;
|
|
345
582
|
}
|
|
346
|
-
|
|
347
583
|
if (bloomActive) {
|
|
348
|
-
const
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
);
|
|
584
|
+
const outputWidth = topology.extent?.outputWidth ?? topology.surface.width;
|
|
585
|
+
const outputHeight = topology.extent?.outputHeight ?? topology.surface.height;
|
|
586
|
+
const bloomSpecs = standardBloomTargetSpecs(outputWidth, outputHeight);
|
|
587
|
+
const composited = target(context, bloomSpecs.composited.label, bloomSpecs.composited);
|
|
353
588
|
if (!composited.ok) return composited;
|
|
354
|
-
const
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
const
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
const blurV = target(
|
|
367
|
-
context,
|
|
368
|
-
STANDARD_BLOOM_TARGET_SPEC.blurV.label,
|
|
369
|
-
STANDARD_BLOOM_TARGET_SPEC.blurV,
|
|
370
|
-
);
|
|
371
|
-
if (!blurV.ok) return blurV;
|
|
589
|
+
const downsample: RenderPipelineTarget[] = [];
|
|
590
|
+
for (const spec of bloomSpecs.downsample) {
|
|
591
|
+
const level = target(context, spec.label, spec);
|
|
592
|
+
if (!level.ok) return level;
|
|
593
|
+
downsample.push(level.value);
|
|
594
|
+
}
|
|
595
|
+
const upsample: RenderPipelineTarget[] = [];
|
|
596
|
+
for (const spec of bloomSpecs.upsample) {
|
|
597
|
+
const level = target(context, spec.label, spec);
|
|
598
|
+
if (!level.ok) return level;
|
|
599
|
+
upsample.push(level.value);
|
|
600
|
+
}
|
|
372
601
|
const bloom = addTypedBloomPasses(context.graph, {
|
|
373
602
|
scene: postInput,
|
|
374
603
|
composited: composited.value,
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
604
|
+
downsample,
|
|
605
|
+
upsample,
|
|
606
|
+
levelDimensions: bloomSpecs.levels,
|
|
378
607
|
});
|
|
379
608
|
if (!bloom.ok) return bloom;
|
|
380
609
|
postInput = composited.value;
|
package/src/pipeline-spec.ts
CHANGED
|
@@ -562,8 +562,8 @@ export interface PassKindAttachmentPolicy {
|
|
|
562
562
|
* 4. `'point-shadow-caster'` — HDRP point-shadow caster: depth-only
|
|
563
563
|
* 5. `'skybox'` — fullscreen skybox: color-only clear/store
|
|
564
564
|
* 6. `'tonemap'` — HDR→LDR tonemap fullscreen: color-only clear/store
|
|
565
|
-
* 7. `'bloom-
|
|
566
|
-
* clear/store
|
|
565
|
+
* 7. `'bloom-downsample'` / `'bloom-upsample'` — multiscale Bloom pyramid:
|
|
566
|
+
* color-only clear/store
|
|
567
567
|
* 8. `'bloom-composite'` — bloom add-back: color-only load/store (NOT clear)
|
|
568
568
|
* 9. `'fxaa'` — fullscreen FXAA: color-only clear/store
|
|
569
569
|
* 10. `'post-process'` — generic fullscreen primitive (SSAO, render-graph
|
|
@@ -633,7 +633,7 @@ export const passKindPolicyTable: Readonly<Record<string, PassKindAttachmentPoli
|
|
|
633
633
|
},
|
|
634
634
|
defaultDepthOps: undefined,
|
|
635
635
|
},
|
|
636
|
-
'bloom-
|
|
636
|
+
'bloom-downsample': {
|
|
637
637
|
shape: 'color-only',
|
|
638
638
|
defaultColorOps: {
|
|
639
639
|
loadOp: 'clear',
|
|
@@ -642,7 +642,7 @@ export const passKindPolicyTable: Readonly<Record<string, PassKindAttachmentPoli
|
|
|
642
642
|
},
|
|
643
643
|
defaultDepthOps: undefined,
|
|
644
644
|
},
|
|
645
|
-
'bloom-
|
|
645
|
+
'bloom-upsample': {
|
|
646
646
|
shape: 'color-only',
|
|
647
647
|
defaultColorOps: {
|
|
648
648
|
loadOp: 'clear',
|
|
@@ -1220,7 +1220,7 @@ export function buildSpecConstTable(
|
|
|
1220
1220
|
// has sampleCount=4. Both use empty vertexLayout (fullscreen triangle, no
|
|
1221
1221
|
// attributes) and cullMode='none' (forward cull for fullscreen-quad passthrough).
|
|
1222
1222
|
//
|
|
1223
|
-
// Shadow-probe / fxaa /
|
|
1223
|
+
// Shadow-probe / fxaa / Bloom 10-pass / SSAO 2-stage are lazy-build — not in
|
|
1224
1224
|
// SPEC_CONST_TABLE (R-D4 decision: only entries that are always-present on
|
|
1225
1225
|
// every boot).
|
|
1226
1226
|
|
|
@@ -22,6 +22,7 @@ import type { EnvironmentGeneration } from '../environment/generation';
|
|
|
22
22
|
import type { EnvironmentLifecycle } from '../environment/lifecycle';
|
|
23
23
|
import type { DepthOfFieldParams } from '../features/depth-of-field/depth-of-field-params';
|
|
24
24
|
import type { GpuBuffer } from '../gpu-resource';
|
|
25
|
+
import type { MotionBlurExecutionReceipt } from '../inspection-types';
|
|
25
26
|
import type { InstanceCollectionStore } from '../instances';
|
|
26
27
|
import type { IblBindingInspection } from '../mesh-material-bindings';
|
|
27
28
|
import type { StandardLightingInspection } from '../pipeline/standard-lighting/inspection';
|
|
@@ -382,7 +383,8 @@ export function makeZeroCameraFallbackSnapshot(): CameraSnapshot {
|
|
|
382
383
|
bloom: 'off',
|
|
383
384
|
bloomThreshold: 1.0,
|
|
384
385
|
bloomIntensity: 1.0,
|
|
385
|
-
|
|
386
|
+
bloomSoftKnee: 0.5,
|
|
387
|
+
bloomScatter: 0.7,
|
|
386
388
|
clearColor: ZERO_CAMERA_CLEAR_FALLBACK,
|
|
387
389
|
};
|
|
388
390
|
}
|
|
@@ -407,6 +409,8 @@ export function makeZeroCameraFallbackSnapshot(): CameraSnapshot {
|
|
|
407
409
|
*/
|
|
408
410
|
export interface RenderFrameState {
|
|
409
411
|
frameNumber: number;
|
|
412
|
+
/** Last successful Motion Blur compute execution; failed submits retain the prior receipt. */
|
|
413
|
+
motionBlurExecution?: MotionBlurExecutionReceipt;
|
|
410
414
|
/** Final-submit Standard IBL binding-chain receipt for this frame. */
|
|
411
415
|
iblBindingInspection?: IblBindingInspection;
|
|
412
416
|
/** Demand for the frame-local Standard fallback MRT. */
|
|
@@ -18,6 +18,12 @@ export function graphExecutionPhase(passName: string): RenderGraphExecutionPhase
|
|
|
18
18
|
return 'record/graph-execute/ssr-reflection-mip';
|
|
19
19
|
}
|
|
20
20
|
if (passName === 'ssr-compose') return 'record/graph-execute/ssr-compose';
|
|
21
|
+
if (passName.startsWith('bloom-downsample-')) {
|
|
22
|
+
return 'record/graph-execute/bloom-downsample';
|
|
23
|
+
}
|
|
24
|
+
if (passName.startsWith('bloom-upsample-')) {
|
|
25
|
+
return 'record/graph-execute/bloom-upsample';
|
|
26
|
+
}
|
|
21
27
|
switch (passName) {
|
|
22
28
|
case 'cluster-binner-upload':
|
|
23
29
|
case 'cluster-membership-producer':
|
|
@@ -47,12 +53,10 @@ export function graphExecutionPhase(passName: string): RenderGraphExecutionPhase
|
|
|
47
53
|
return 'record/graph-execute/main';
|
|
48
54
|
case 'fxaa':
|
|
49
55
|
return 'record/graph-execute/fxaa';
|
|
50
|
-
case 'bloom-
|
|
51
|
-
return 'record/graph-execute/bloom-
|
|
52
|
-
case 'bloom-
|
|
53
|
-
return 'record/graph-execute/bloom-
|
|
54
|
-
case 'bloom-blur-v':
|
|
55
|
-
return 'record/graph-execute/bloom-blur-v';
|
|
56
|
+
case 'bloom-downsample':
|
|
57
|
+
return 'record/graph-execute/bloom-downsample';
|
|
58
|
+
case 'bloom-upsample':
|
|
59
|
+
return 'record/graph-execute/bloom-upsample';
|
|
56
60
|
case 'bloom-composite':
|
|
57
61
|
return 'record/graph-execute/bloom-composite';
|
|
58
62
|
default:
|