@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
package/src/record/frame.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { encodeAnalyticFogParams } from '../environment/analytic-fog';
|
|
2
|
+
import type { FogFrame } from '../extract/environment';
|
|
1
3
|
import { collectGpuDrivenMaterialArtifacts } from '../gpu-driven/material-artifacts';
|
|
2
4
|
import { materialBindingKey, projectMaterialBindingClasses } from '../gpu-driven/material-bindings';
|
|
3
5
|
import { uploadMaterialUniforms } from './material-uniforms';
|
|
@@ -5,7 +7,7 @@ import { uploadMaterialUniforms } from './material-uniforms';
|
|
|
5
7
|
// Extracted from render-system-record.ts (feat-20260704 M3/w17, pure move).
|
|
6
8
|
|
|
7
9
|
import { HANDLE_NINESLICE_QUAD, resolveAssetHandle } from '@forgeax/engine-assets-runtime';
|
|
8
|
-
import type
|
|
10
|
+
import { Time, type World } from '@forgeax/engine-ecs';
|
|
9
11
|
import type { RenderReadLease } from '@forgeax/engine-ecs/projection';
|
|
10
12
|
import { deriveVertexCount } from '@forgeax/engine-geometry';
|
|
11
13
|
import { frustum, mat4, vec3 } from '@forgeax/engine-math';
|
|
@@ -44,6 +46,7 @@ import {
|
|
|
44
46
|
} from '../features/depth-of-field/depth-of-field-params';
|
|
45
47
|
import type { GpuDrivenProduction, PreparedGpuDrivenFrame } from '../gpu-driven/production-raster';
|
|
46
48
|
import type { ShadowViewIdentity } from '../gpu-driven/shadow-views';
|
|
49
|
+
import type { GpuDrivenLodSubmitIdentity } from '../gpu-driven/view-gpu';
|
|
47
50
|
import { GpuBuffer } from '../gpu-resource';
|
|
48
51
|
import { GPU_TEXTURE_USAGE_COPY_SRC } from '../gpu-texture-usage';
|
|
49
52
|
import {
|
|
@@ -304,6 +307,14 @@ export async function observeCurrentFrame(
|
|
|
304
307
|
}
|
|
305
308
|
|
|
306
309
|
import { acknowledgeRenderFeatureSubmission } from '../features/host';
|
|
310
|
+
import {
|
|
311
|
+
effectiveMotionBlurSampleCount,
|
|
312
|
+
isMotionBlurIntervalValid,
|
|
313
|
+
MOTION_BLUR_PARAMS_BYTE_SIZE,
|
|
314
|
+
motionBlurExposureScale,
|
|
315
|
+
motionBlurSampleDelta,
|
|
316
|
+
motionBlurTemporalDemand,
|
|
317
|
+
} from '../features/motion-blur/motion-blur-params';
|
|
307
318
|
import { createTemporalView, resolveTemporalReset, type TemporalView } from '../temporal/view';
|
|
308
319
|
import { inspectVolumetricFog } from '../volume/inspection';
|
|
309
320
|
import {
|
|
@@ -904,6 +915,7 @@ function volumeTemporalSignature(
|
|
|
904
915
|
densityGeneration: prepared.densityGeneration,
|
|
905
916
|
width,
|
|
906
917
|
height,
|
|
918
|
+
...(fog.worldTimeSeconds === undefined ? {} : { worldTimeSeconds: fog.worldTimeSeconds }),
|
|
907
919
|
...(fog.lightKind === undefined ? {} : { lightKind: fog.lightKind }),
|
|
908
920
|
...(fog.lightEntity === undefined ? {} : { lightEntity: fog.lightEntity }),
|
|
909
921
|
...(fog.pointLightEntity === undefined ? {} : { pointLightEntity: fog.pointLightEntity }),
|
|
@@ -1008,7 +1020,7 @@ function prepareVolumetricFogFrame(
|
|
|
1008
1020
|
}
|
|
1009
1021
|
return undefined;
|
|
1010
1022
|
}
|
|
1011
|
-
const params = new Float32Array(
|
|
1023
|
+
const params = new Float32Array(36);
|
|
1012
1024
|
params.set(fog.fog.bounds.min, 0);
|
|
1013
1025
|
params.set(fog.fog.bounds.max, 4);
|
|
1014
1026
|
params.set(fog.fog.extinction, 8);
|
|
@@ -1029,10 +1041,8 @@ function prepareVolumetricFogFrame(
|
|
|
1029
1041
|
const lightColor = selectedSpot?.color ?? lights.directional?.color ?? vec3.create(0, 0, 0);
|
|
1030
1042
|
if (lightDirection === undefined || lightColor === undefined) return undefined;
|
|
1031
1043
|
params.set(lightDirection, 20);
|
|
1032
|
-
//
|
|
1033
|
-
|
|
1034
|
-
// public fog component or allocating another uniform buffer.
|
|
1035
|
-
params[23] = frameState.frameNumber % 1024;
|
|
1044
|
+
// Reserved padding: render frame identity must not move volume samples.
|
|
1045
|
+
params[23] = 0;
|
|
1036
1046
|
const selectedPointIndex =
|
|
1037
1047
|
selectedPoint === undefined
|
|
1038
1048
|
? -1
|
|
@@ -1065,6 +1075,10 @@ function prepareVolumetricFogFrame(
|
|
|
1065
1075
|
frameState.temporalFrame !== undefined && frameState.temporalFrame.resetReason === 'none'
|
|
1066
1076
|
? 1
|
|
1067
1077
|
: 0;
|
|
1078
|
+
// World elapsed time is the sole authored-medium clock. The adjacent
|
|
1079
|
+
// frame phase above remains the deterministic sub-froxel jitter identity;
|
|
1080
|
+
// it never advances density motion.
|
|
1081
|
+
params[32] = fog.worldTimeSeconds ?? 0;
|
|
1068
1082
|
|
|
1069
1083
|
const paramsBuffer = stageVolumetricFogParams(internals, frameState, params);
|
|
1070
1084
|
if (paramsBuffer === undefined) return undefined;
|
|
@@ -1219,6 +1233,8 @@ function mapSsrHistoryResetReason(
|
|
|
1219
1233
|
case 'environment-change':
|
|
1220
1234
|
case 'fog-change':
|
|
1221
1235
|
return 'reflection-generation';
|
|
1236
|
+
case 'time-discontinuity':
|
|
1237
|
+
return 'camera-cut';
|
|
1222
1238
|
case 'device-recover':
|
|
1223
1239
|
return 'device-recovery';
|
|
1224
1240
|
case 'submit-failure':
|
|
@@ -1227,6 +1243,50 @@ function mapSsrHistoryResetReason(
|
|
|
1227
1243
|
}
|
|
1228
1244
|
}
|
|
1229
1245
|
|
|
1246
|
+
interface FrameClockSample {
|
|
1247
|
+
readonly deltaSeconds: number;
|
|
1248
|
+
readonly elapsedSeconds: number | undefined;
|
|
1249
|
+
/** Explicit host/replay clock was present but invalid. */
|
|
1250
|
+
readonly invalidSampleTime: boolean;
|
|
1251
|
+
}
|
|
1252
|
+
|
|
1253
|
+
/** Read the render sample clock from the camera's composition world once per frame. */
|
|
1254
|
+
function frameClockSample(
|
|
1255
|
+
world: World,
|
|
1256
|
+
worlds: readonly World[],
|
|
1257
|
+
camera: CameraSnapshot,
|
|
1258
|
+
sampleTimeSeconds?: number,
|
|
1259
|
+
): FrameClockSample {
|
|
1260
|
+
const owner = worlds[camera.worldId ?? 0] ?? world;
|
|
1261
|
+
const invalidSampleTime = sampleTimeSeconds !== undefined && !Number.isFinite(sampleTimeSeconds);
|
|
1262
|
+
try {
|
|
1263
|
+
const clock = owner.getResource(Time);
|
|
1264
|
+
return {
|
|
1265
|
+
deltaSeconds: Number.isFinite(clock.delta) ? Math.max(0, clock.delta) : 0,
|
|
1266
|
+
// Keep the raw host sample even when ECS accepted only a clamped
|
|
1267
|
+
// simulation delta. Temporal admission compares this value with the
|
|
1268
|
+
// last successfully submitted sample and therefore sees real hitches.
|
|
1269
|
+
elapsedSeconds:
|
|
1270
|
+
sampleTimeSeconds === undefined
|
|
1271
|
+
? Number.isFinite(clock.elapsed)
|
|
1272
|
+
? clock.elapsed
|
|
1273
|
+
: undefined
|
|
1274
|
+
: Number.isFinite(sampleTimeSeconds)
|
|
1275
|
+
? sampleTimeSeconds
|
|
1276
|
+
: undefined,
|
|
1277
|
+
invalidSampleTime,
|
|
1278
|
+
};
|
|
1279
|
+
} catch {
|
|
1280
|
+
// Test and recovery callers may provide a minimal World-shaped owner. An
|
|
1281
|
+
// absent clock is an invalid temporal pair and therefore safely resets.
|
|
1282
|
+
return {
|
|
1283
|
+
deltaSeconds: 0,
|
|
1284
|
+
elapsedSeconds: Number.isFinite(sampleTimeSeconds) ? sampleTimeSeconds : undefined,
|
|
1285
|
+
invalidSampleTime,
|
|
1286
|
+
};
|
|
1287
|
+
}
|
|
1288
|
+
}
|
|
1289
|
+
|
|
1230
1290
|
function stageSsrHistoryCandidate(
|
|
1231
1291
|
internals: RenderSystemInternals,
|
|
1232
1292
|
frameState: RenderFrameState,
|
|
@@ -1611,6 +1671,7 @@ export function recordFrame(
|
|
|
1611
1671
|
readonly activeEntityKeys?: ReadonlySet<number>;
|
|
1612
1672
|
readonly activeEntityRevision?: number;
|
|
1613
1673
|
readonly telemetryCandidateCount?: number;
|
|
1674
|
+
readonly telemetrySubmit?: GpuDrivenLodSubmitIdentity;
|
|
1614
1675
|
readonly occlusion?: OcclusionFrameProjection;
|
|
1615
1676
|
},
|
|
1616
1677
|
renderReadLeases?: readonly RenderReadLease[],
|
|
@@ -1631,6 +1692,9 @@ export function recordFrame(
|
|
|
1631
1692
|
preparedLighting?: ReturnType<typeof prepareFrameLighting>,
|
|
1632
1693
|
ssrDependencies?: SsrDependenciesInspection,
|
|
1633
1694
|
onRenderableDraw?: (entry: ValidatedRenderable) => void,
|
|
1695
|
+
analyticFog?: FogFrame,
|
|
1696
|
+
sampleTimeSeconds?: number,
|
|
1697
|
+
temporalReset = false,
|
|
1634
1698
|
): boolean {
|
|
1635
1699
|
void shadowCasterEntityKeys;
|
|
1636
1700
|
frameState.reflectionFallbackObservationSource = undefined;
|
|
@@ -2046,6 +2110,9 @@ export function recordFrame(
|
|
|
2046
2110
|
...(frameGpuDriven.telemetryCandidateCount === undefined
|
|
2047
2111
|
? {}
|
|
2048
2112
|
: { telemetryCandidateCount: frameGpuDriven.telemetryCandidateCount }),
|
|
2113
|
+
...(frameGpuDriven.telemetrySubmit === undefined
|
|
2114
|
+
? {}
|
|
2115
|
+
: { telemetrySubmit: frameGpuDriven.telemetrySubmit }),
|
|
2049
2116
|
...(frameGpuDriven.occlusion === undefined ? {} : { occlusion: frameGpuDriven.occlusion }),
|
|
2050
2117
|
...(frameGpuDriven.scene?.structureMetrics === undefined
|
|
2051
2118
|
? {}
|
|
@@ -2190,6 +2257,7 @@ export function recordFrame(
|
|
|
2190
2257
|
undefined,
|
|
2191
2258
|
ssrAdmission,
|
|
2192
2259
|
renderExtent,
|
|
2260
|
+
analyticFog !== undefined && analyticFog.density > 0 && analyticFog.maxOpacity > 0,
|
|
2193
2261
|
),
|
|
2194
2262
|
);
|
|
2195
2263
|
if (preflightGraph === null) {
|
|
@@ -2268,6 +2336,38 @@ export function recordFrame(
|
|
|
2268
2336
|
const targetH = swapTarget.targetH;
|
|
2269
2337
|
|
|
2270
2338
|
const previousTemporalView = frameState.lastSuccessfulTemporalView;
|
|
2339
|
+
const motionBlurDemand =
|
|
2340
|
+
camera.motionBlur === undefined
|
|
2341
|
+
? false
|
|
2342
|
+
: motionBlurTemporalDemand({
|
|
2343
|
+
shutterAngle: camera.motionBlur.shutterAngle,
|
|
2344
|
+
maxRadiusPixels: camera.motionBlur.maxRadiusPixels,
|
|
2345
|
+
sampleCount: camera.motionBlur.sampleCount,
|
|
2346
|
+
targetFps: camera.motionBlur.targetFps ?? 60,
|
|
2347
|
+
});
|
|
2348
|
+
const temporalDemand = camera.antialias === 'taa' || motionBlurDemand;
|
|
2349
|
+
const clock = frameClockSample(world, worlds, camera, sampleTimeSeconds);
|
|
2350
|
+
const deltaSeconds =
|
|
2351
|
+
temporalReset || clock.invalidSampleTime
|
|
2352
|
+
? Number.NaN
|
|
2353
|
+
: motionBlurSampleDelta(
|
|
2354
|
+
clock.elapsedSeconds,
|
|
2355
|
+
previousTemporalView?.sampleTimeSeconds,
|
|
2356
|
+
clock.deltaSeconds,
|
|
2357
|
+
);
|
|
2358
|
+
const intervalValid = isMotionBlurIntervalValid(deltaSeconds);
|
|
2359
|
+
// An off MB-only frame still carries an unjittered temporal view so the
|
|
2360
|
+
// accepted sample clock remains observable. Its history flag is false,
|
|
2361
|
+
// however, and must form a new baseline when the effect is enabled again.
|
|
2362
|
+
// A reset frame already has an explicit reason and is the valid baseline
|
|
2363
|
+
// for the following pair, so it is deliberately excluded here.
|
|
2364
|
+
const motionBlurFirstFrame =
|
|
2365
|
+
motionBlurDemand &&
|
|
2366
|
+
camera.antialias !== 'taa' &&
|
|
2367
|
+
(previousTemporalView === undefined ||
|
|
2368
|
+
(previousTemporalView.mode === 'off' &&
|
|
2369
|
+
!previousTemporalView.historyValid &&
|
|
2370
|
+
previousTemporalView.resetReason === undefined));
|
|
2271
2371
|
const currentUnjitteredViewProjection = mat4.multiply(
|
|
2272
2372
|
mat4.create(),
|
|
2273
2373
|
computeProjectionMatrix(camera),
|
|
@@ -2294,19 +2394,32 @@ export function recordFrame(
|
|
|
2294
2394
|
internalHeight: renderExtent.internalHeight,
|
|
2295
2395
|
}),
|
|
2296
2396
|
...(camera.historyVersion === undefined ? {} : { historyVersion: camera.historyVersion }),
|
|
2397
|
+
...(clock.elapsedSeconds === undefined ? {} : { sampleTimeSeconds: clock.elapsedSeconds }),
|
|
2297
2398
|
historyValid: false,
|
|
2298
2399
|
currentUnjitteredViewProjection,
|
|
2299
2400
|
currentCameraPosition,
|
|
2300
2401
|
});
|
|
2301
2402
|
const resetReason =
|
|
2302
|
-
|
|
2303
|
-
? resolveTemporalReset(previousTemporalView, temporalCandidate)
|
|
2403
|
+
temporalDemand && environmentReady
|
|
2404
|
+
? (resolveTemporalReset(previousTemporalView, temporalCandidate) ??
|
|
2405
|
+
(temporalReset || (motionBlurDemand && !intervalValid)
|
|
2406
|
+
? 'time-discontinuity'
|
|
2407
|
+
: motionBlurFirstFrame
|
|
2408
|
+
? 'first-frame'
|
|
2409
|
+
: undefined))
|
|
2304
2410
|
: undefined;
|
|
2305
2411
|
const canReusePrevious = previousTemporalView !== undefined && resetReason === undefined;
|
|
2306
2412
|
const temporalView = createTemporalView({
|
|
2307
2413
|
...temporalCandidate.input,
|
|
2308
2414
|
frameIndex: resetReason === undefined ? temporalCandidate.input.frameIndex : 0,
|
|
2309
|
-
|
|
2415
|
+
// Motion Blur needs a finite positive pair before it can read the
|
|
2416
|
+
// baseline. TAA-only frames retain their existing temporal contract and
|
|
2417
|
+
// do not depend on the simulation clock being present in a test host.
|
|
2418
|
+
historyValid:
|
|
2419
|
+
temporalDemand &&
|
|
2420
|
+
environmentReady &&
|
|
2421
|
+
canReusePrevious &&
|
|
2422
|
+
(!motionBlurDemand || intervalValid),
|
|
2310
2423
|
resetReason,
|
|
2311
2424
|
...(canReusePrevious && previousTemporalView.currentUnjitteredViewProjection !== undefined
|
|
2312
2425
|
? {
|
|
@@ -2357,17 +2470,26 @@ export function recordFrame(
|
|
|
2357
2470
|
);
|
|
2358
2471
|
activeVolumetricFogContext = resolvedHistory.context;
|
|
2359
2472
|
activeVolumetricFogSignature = resolvedHistory.signature;
|
|
2360
|
-
const
|
|
2473
|
+
const previousTime = frameState.volumetricFogHistorySignature?.worldTimeSeconds;
|
|
2474
|
+
const currentTime = resolvedHistory.signature.worldTimeSeconds;
|
|
2475
|
+
// Adjacent UBO lanes: validity, World time, elapsed time since accepted history.
|
|
2476
|
+
const historyParams = new Float32Array([
|
|
2477
|
+
activeVolumetricFogContext.historyValid ? 1 : 0,
|
|
2478
|
+
currentTime ?? 0,
|
|
2479
|
+
previousTime === undefined || currentTime === undefined
|
|
2480
|
+
? 0
|
|
2481
|
+
: Math.max(0, currentTime - previousTime),
|
|
2482
|
+
]);
|
|
2361
2483
|
if (frameState.volumetricFogPendingParams !== undefined) {
|
|
2362
|
-
frameState.volumetricFogPendingParams
|
|
2484
|
+
frameState.volumetricFogPendingParams.set(historyParams, 31);
|
|
2363
2485
|
}
|
|
2364
|
-
const
|
|
2486
|
+
const historyParamsWritten = internals.device.queue.writeBuffer(
|
|
2365
2487
|
activeVolumetricFogContext.paramsBuffer,
|
|
2366
2488
|
31 * Float32Array.BYTES_PER_ELEMENT,
|
|
2367
|
-
|
|
2489
|
+
historyParams,
|
|
2368
2490
|
);
|
|
2369
|
-
if (!
|
|
2370
|
-
internals.errorRegistry.fire(
|
|
2491
|
+
if (!historyParamsWritten.ok) {
|
|
2492
|
+
internals.errorRegistry.fire(historyParamsWritten.error);
|
|
2371
2493
|
abortPreparedGpuDriven();
|
|
2372
2494
|
return false;
|
|
2373
2495
|
}
|
|
@@ -2652,14 +2774,33 @@ export function recordFrame(
|
|
|
2652
2774
|
// builtin motion-blur pass receives its all-zero registration default and
|
|
2653
2775
|
// becomes a no-op even though the temporal scene target is populated.
|
|
2654
2776
|
const framePostProcessParams = new Map(postProcessParams);
|
|
2777
|
+
if (analyticFog !== undefined)
|
|
2778
|
+
framePostProcessParams.set(
|
|
2779
|
+
'forgeax.analytic-fog',
|
|
2780
|
+
encodeAnalyticFogParams(analyticFog, recordCamera),
|
|
2781
|
+
);
|
|
2655
2782
|
if (camera.motionBlur !== undefined) {
|
|
2656
|
-
|
|
2657
|
-
|
|
2658
|
-
|
|
2659
|
-
|
|
2660
|
-
|
|
2661
|
-
|
|
2662
|
-
|
|
2783
|
+
if (motionBlurDemand) {
|
|
2784
|
+
const motionBlurParams = new Uint8Array(MOTION_BLUR_PARAMS_BYTE_SIZE);
|
|
2785
|
+
const motionBlurView = new DataView(motionBlurParams.buffer);
|
|
2786
|
+
const uniformDeltaSeconds = Number.isFinite(deltaSeconds) ? deltaSeconds : 0;
|
|
2787
|
+
motionBlurView.setFloat32(0, camera.motionBlur.shutterAngle, true);
|
|
2788
|
+
motionBlurView.setFloat32(4, camera.motionBlur.maxRadiusPixels, true);
|
|
2789
|
+
motionBlurView.setUint32(
|
|
2790
|
+
8,
|
|
2791
|
+
effectiveMotionBlurSampleCount(camera.motionBlur.sampleCount),
|
|
2792
|
+
true,
|
|
2793
|
+
);
|
|
2794
|
+
motionBlurView.setUint32(12, temporalView?.historyValid === true ? 0 : 1, true);
|
|
2795
|
+
motionBlurView.setFloat32(16, camera.motionBlur.targetFps ?? 60, true);
|
|
2796
|
+
motionBlurView.setFloat32(
|
|
2797
|
+
20,
|
|
2798
|
+
motionBlurExposureScale(uniformDeltaSeconds, camera.motionBlur.targetFps ?? 60),
|
|
2799
|
+
true,
|
|
2800
|
+
);
|
|
2801
|
+
motionBlurView.setFloat32(24, uniformDeltaSeconds, true);
|
|
2802
|
+
framePostProcessParams.set('forgeax.motion-blur', motionBlurParams);
|
|
2803
|
+
}
|
|
2663
2804
|
}
|
|
2664
2805
|
if (camera.depthOfField !== undefined) {
|
|
2665
2806
|
const dofParams = packDepthOfFieldParams(camera.depthOfField, {
|
|
@@ -1481,6 +1481,7 @@ function uploadInstanceRanges(
|
|
|
1481
1481
|
ranges: readonly { readonly start: number; readonly end: number }[],
|
|
1482
1482
|
storageBacked: boolean,
|
|
1483
1483
|
sourceOffsetInstances = 0,
|
|
1484
|
+
previousInst: NonNullable<RenderableSnapshot['temporal']>['previousInstances'] = undefined,
|
|
1484
1485
|
): InstanceUploadResult {
|
|
1485
1486
|
const strideBytes =
|
|
1486
1487
|
(storageBacked ? INSTANCE_STORAGE_STRIDE_FLOATS : 16) * Float32Array.BYTES_PER_ELEMENT;
|
|
@@ -1494,7 +1495,31 @@ function uploadInstanceRanges(
|
|
|
1494
1495
|
(sourceOffsetInstances + start) * 16,
|
|
1495
1496
|
(sourceOffsetInstances + end) * 16,
|
|
1496
1497
|
);
|
|
1497
|
-
|
|
1498
|
+
// A generation-bearing previous collection is kept whole so a compacted
|
|
1499
|
+
// or reordered current range can resolve its real prior ordinal. Without
|
|
1500
|
+
// identity proof, keep the old range-local shape and let the packer seed
|
|
1501
|
+
// on count mismatch rather than pairing an unrelated slot.
|
|
1502
|
+
const hasIdentityProof =
|
|
1503
|
+
inst.generations !== undefined && previousInst?.generations !== undefined;
|
|
1504
|
+
const previousSource = hasIdentityProof
|
|
1505
|
+
? previousInst?.transforms
|
|
1506
|
+
: previousInst?.transforms.subarray(
|
|
1507
|
+
(sourceOffsetInstances + start) * 16,
|
|
1508
|
+
(sourceOffsetInstances + end) * 16,
|
|
1509
|
+
);
|
|
1510
|
+
const currentGenerations = inst.generations?.subarray(
|
|
1511
|
+
sourceOffsetInstances + start,
|
|
1512
|
+
sourceOffsetInstances + end,
|
|
1513
|
+
);
|
|
1514
|
+
const previousGenerations = hasIdentityProof
|
|
1515
|
+
? previousInst?.generations
|
|
1516
|
+
: previousInst?.generations?.subarray(
|
|
1517
|
+
sourceOffsetInstances + start,
|
|
1518
|
+
sourceOffsetInstances + end,
|
|
1519
|
+
);
|
|
1520
|
+
const payload = storageBacked
|
|
1521
|
+
? packInstanceStorageBuffer(source, previousSource, currentGenerations, previousGenerations)
|
|
1522
|
+
: source;
|
|
1498
1523
|
const written = c.runtime.device.queue.writeBuffer(buffer, start * strideBytes, payload);
|
|
1499
1524
|
if (!written.ok) {
|
|
1500
1525
|
c.runtime.errorRegistry.fire(written.error);
|
|
@@ -1673,6 +1698,7 @@ export function resolveStorageInstanceChunks(
|
|
|
1673
1698
|
rangesToUpload,
|
|
1674
1699
|
true,
|
|
1675
1700
|
start,
|
|
1701
|
+
entry.source.temporal?.previousInstances,
|
|
1676
1702
|
);
|
|
1677
1703
|
for (const range of upload.ranges) {
|
|
1678
1704
|
uploadedRanges.push({ start: range.start + start, end: range.end + start });
|
|
@@ -1858,6 +1884,7 @@ function resolveGeometryInstanceBuffer(
|
|
|
1858
1884
|
rangesToUpload,
|
|
1859
1885
|
false,
|
|
1860
1886
|
start,
|
|
1887
|
+
entry.source.temporal?.previousInstances,
|
|
1861
1888
|
);
|
|
1862
1889
|
for (const range of upload.ranges) {
|
|
1863
1890
|
uploadedRanges.push({ start: range.start + start, end: range.end + start });
|
|
@@ -1997,6 +2024,8 @@ function resolveGeometryInstanceBuffer(
|
|
|
1997
2024
|
active.buffer.handle,
|
|
1998
2025
|
ranges,
|
|
1999
2026
|
!uniformFallback,
|
|
2027
|
+
0,
|
|
2028
|
+
entry.source.temporal?.previousInstances,
|
|
2000
2029
|
);
|
|
2001
2030
|
uploadRanges = upload.ranges;
|
|
2002
2031
|
uploadedBytes = upload.bytes;
|
|
@@ -690,7 +690,12 @@ function recordSpriteEntityDraws(
|
|
|
690
690
|
{
|
|
691
691
|
const instancePayload = uniformFallback
|
|
692
692
|
? spriteInst.transforms
|
|
693
|
-
: packInstanceStorageBuffer(
|
|
693
|
+
: packInstanceStorageBuffer(
|
|
694
|
+
spriteInst.transforms,
|
|
695
|
+
spriteEntry.source.temporal?.previousInstances?.transforms,
|
|
696
|
+
spriteInst.generations,
|
|
697
|
+
spriteEntry.source.temporal?.previousInstances?.generations,
|
|
698
|
+
);
|
|
694
699
|
const requestedBytes = instancePayload.byteLength;
|
|
695
700
|
const cap = runtime.device.limits.maxStorageBufferBindingSize;
|
|
696
701
|
if (typeof cap === 'number' && requestedBytes > cap) {
|
package/src/record/mesh-ssbo.ts
CHANGED
|
@@ -43,23 +43,58 @@ export const MAX_UNIFORM_INSTANCES = 128;
|
|
|
43
43
|
/** The storage-backed InstanceData layout is current + previous mat4. */
|
|
44
44
|
export const INSTANCE_STORAGE_STRIDE_FLOATS = 32;
|
|
45
45
|
|
|
46
|
+
function hasStableGenerationColumn(generations: Uint32Array | undefined, count: number): boolean {
|
|
47
|
+
if (generations === undefined || generations.length !== count) return false;
|
|
48
|
+
const seen = new Set<number>();
|
|
49
|
+
for (const generation of generations) {
|
|
50
|
+
if (generation === 0 || seen.has(generation)) return false;
|
|
51
|
+
seen.add(generation);
|
|
52
|
+
}
|
|
53
|
+
return true;
|
|
54
|
+
}
|
|
55
|
+
|
|
46
56
|
/**
|
|
47
57
|
* Project the ECS transform snapshot into the storage-backed InstanceData
|
|
48
|
-
* layout.
|
|
49
|
-
* the
|
|
50
|
-
* previous
|
|
51
|
-
*
|
|
58
|
+
* layout. Unique identity generations select the previous matrix only when
|
|
59
|
+
* the producer proves that the instance survived. Replaced slots seed
|
|
60
|
+
* previous=current; reordered slots map back to the real prior ordinal so a
|
|
61
|
+
* compaction cannot exchange velocities. Uniform-backed variants keep the
|
|
62
|
+
* compact 16-float payload and do not use this projection.
|
|
52
63
|
*/
|
|
53
|
-
export function packInstanceStorageBuffer(
|
|
64
|
+
export function packInstanceStorageBuffer(
|
|
65
|
+
transforms: Float32Array,
|
|
66
|
+
previousTransforms: Float32Array = transforms,
|
|
67
|
+
generations?: Uint32Array,
|
|
68
|
+
previousGenerations?: Uint32Array,
|
|
69
|
+
): Float32Array {
|
|
54
70
|
const count = Math.floor(transforms.length / 16);
|
|
55
71
|
const out = new Float32Array(count * INSTANCE_STORAGE_STRIDE_FLOATS);
|
|
72
|
+
const previousCount = Math.floor(previousTransforms.length / 16);
|
|
73
|
+
const generationInput = generations !== undefined || previousGenerations !== undefined;
|
|
74
|
+
const identityProof =
|
|
75
|
+
hasStableGenerationColumn(generations, count) &&
|
|
76
|
+
hasStableGenerationColumn(previousGenerations, previousCount);
|
|
77
|
+
const previousIndexByGeneration = identityProof
|
|
78
|
+
? new Map(
|
|
79
|
+
Array.from(previousGenerations ?? [], (generation, index) => [generation, index] as const),
|
|
80
|
+
)
|
|
81
|
+
: undefined;
|
|
56
82
|
for (let i = 0; i < count; i++) {
|
|
57
83
|
const sourceBase = i * 16;
|
|
58
84
|
const targetBase = i * INSTANCE_STORAGE_STRIDE_FLOATS;
|
|
85
|
+
const previousIndex = identityProof
|
|
86
|
+
? previousIndexByGeneration?.get(generations?.[i] ?? 0)
|
|
87
|
+
: !generationInput && previousCount === count
|
|
88
|
+
? i
|
|
89
|
+
: undefined;
|
|
90
|
+
const sameIdentity = previousIndex !== undefined && previousIndex < previousCount;
|
|
91
|
+
const previousBase = (previousIndex ?? i) * 16;
|
|
59
92
|
for (let k = 0; k < 16; k++) {
|
|
60
93
|
const value = transforms[sourceBase + k] ?? 0;
|
|
61
94
|
out[targetBase + k] = value;
|
|
62
|
-
out[targetBase + 16 + k] =
|
|
95
|
+
out[targetBase + 16 + k] = sameIdentity
|
|
96
|
+
? (previousTransforms[previousBase + k] ?? value)
|
|
97
|
+
: value;
|
|
63
98
|
}
|
|
64
99
|
}
|
|
65
100
|
return out;
|
|
@@ -451,6 +486,7 @@ export function uploadMeshSsboBatch(
|
|
|
451
486
|
_meshSsboScratchFloats[slot + 38] = 1;
|
|
452
487
|
_meshSsboScratchFloats[slot + 43] = 1;
|
|
453
488
|
_meshSsboScratchFloats[slot + 44] = 1;
|
|
489
|
+
_meshSsboScratchFloats[slot + 45] = 1;
|
|
454
490
|
} else {
|
|
455
491
|
const worldFromLocal = entry.source.transform.world;
|
|
456
492
|
for (let k = 0; k < 16; k++) _meshSsboScratchFloats[slot + k] = worldFromLocal[k] ?? 0;
|
|
@@ -483,6 +519,7 @@ export function uploadMeshSsboBatch(
|
|
|
483
519
|
}
|
|
484
520
|
_meshSsboScratchFloats[slot + 44] =
|
|
485
521
|
entry.source.temporal?.reactive === true || reactiveMaterial ? 1 : 0;
|
|
522
|
+
_meshSsboScratchFloats[slot + 45] = entry.source.temporal?.motionValid === false ? 0 : 1;
|
|
486
523
|
}
|
|
487
524
|
}
|
|
488
525
|
if (neededBytes > 0) {
|
|
@@ -337,17 +337,15 @@ export interface PerPassResources {
|
|
|
337
337
|
readonly skyboxBindGroupLayout: BindGroupLayout | null;
|
|
338
338
|
readonly skyboxSampler: Sampler | null;
|
|
339
339
|
readonly skyboxRotationBuffer: Buffer | null;
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
bloomBlurVPipeline: RhiRenderPipeline | null;
|
|
340
|
+
bloomDownsamplePipeline: RhiRenderPipeline | null;
|
|
341
|
+
bloomUpsamplePipeline: RhiRenderPipeline | null;
|
|
343
342
|
bloomCompositePipeline: RhiRenderPipeline | null;
|
|
344
|
-
|
|
345
|
-
|
|
343
|
+
bloomDownsampleBindGroupLayout: BindGroupLayout | null;
|
|
344
|
+
bloomUpsampleBindGroupLayout: BindGroupLayout | null;
|
|
346
345
|
bloomCompositeBindGroupLayout: BindGroupLayout | null;
|
|
347
346
|
bloomSampler: Sampler | null;
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
bloomBlurVParamsBuffer: Buffer | null;
|
|
347
|
+
bloomDownsampleParamsBuffer: Buffer | null;
|
|
348
|
+
bloomUpsampleParamsBuffer: Buffer | null;
|
|
351
349
|
bloomCompositeParamsBuffer: Buffer | null;
|
|
352
350
|
ensureBloomResources?: () => void;
|
|
353
351
|
getBloomResources?: () => BloomPersistentBundle | null;
|
|
@@ -358,18 +356,6 @@ export interface PerPassResources {
|
|
|
358
356
|
/** Drain candidate, active, and fence-retiring Bloom generations. */
|
|
359
357
|
drainBloomResources?: () => void;
|
|
360
358
|
inspectBloomResources?: (graph?: CompiledRenderGraphInfo) => BloomInspection;
|
|
361
|
-
bloomBrightTexture: Texture | null;
|
|
362
|
-
bloomBrightView: TextureView | null;
|
|
363
|
-
bloomBrightWidth: number;
|
|
364
|
-
bloomBrightHeight: number;
|
|
365
|
-
bloomBlurHTexture: Texture | null;
|
|
366
|
-
bloomBlurHView: TextureView | null;
|
|
367
|
-
bloomBlurHWidth: number;
|
|
368
|
-
bloomBlurHHeight: number;
|
|
369
|
-
bloomBlurVTexture: Texture | null;
|
|
370
|
-
bloomBlurVView: TextureView | null;
|
|
371
|
-
bloomBlurVWidth: number;
|
|
372
|
-
bloomBlurVHeight: number;
|
|
373
359
|
ssaoCalcPipeline: RhiRenderPipeline | null;
|
|
374
360
|
ssaoBlurPipeline: RhiRenderPipeline | null;
|
|
375
361
|
ssaoBgl: BindGroupLayout | null;
|
|
@@ -392,17 +378,15 @@ export interface PerPassResources {
|
|
|
392
378
|
export interface BloomPersistentBundle {
|
|
393
379
|
readonly scope: DeviceScope;
|
|
394
380
|
readonly generation: number;
|
|
395
|
-
readonly
|
|
396
|
-
readonly
|
|
397
|
-
readonly bloomBlurVPipeline: RhiRenderPipeline | null;
|
|
381
|
+
readonly bloomDownsamplePipeline: RhiRenderPipeline | null;
|
|
382
|
+
readonly bloomUpsamplePipeline: RhiRenderPipeline | null;
|
|
398
383
|
readonly bloomCompositePipeline: RhiRenderPipeline | null;
|
|
399
|
-
readonly
|
|
400
|
-
readonly
|
|
384
|
+
readonly bloomDownsampleBindGroupLayout: BindGroupLayout | null;
|
|
385
|
+
readonly bloomUpsampleBindGroupLayout: BindGroupLayout | null;
|
|
401
386
|
readonly bloomCompositeBindGroupLayout: BindGroupLayout | null;
|
|
402
387
|
readonly bloomSampler: Sampler | null;
|
|
403
|
-
readonly
|
|
404
|
-
readonly
|
|
405
|
-
readonly bloomBlurVParamsBuffer: Buffer | null;
|
|
388
|
+
readonly bloomDownsampleParamsBuffer: Buffer | null;
|
|
389
|
+
readonly bloomUpsampleParamsBuffer: Buffer | null;
|
|
406
390
|
readonly bloomCompositeParamsBuffer: Buffer | null;
|
|
407
391
|
}
|
|
408
392
|
|
|
@@ -1503,7 +1503,12 @@ export function recordShadowCasterDraws(
|
|
|
1503
1503
|
: GPU_BUFFER_USAGE_STORAGE | GPU_BUFFER_USAGE_COPY_DST;
|
|
1504
1504
|
const instancePayload = uniformFallback
|
|
1505
1505
|
? shadowInst.transforms
|
|
1506
|
-
: packInstanceStorageBuffer(
|
|
1506
|
+
: packInstanceStorageBuffer(
|
|
1507
|
+
shadowInst.transforms,
|
|
1508
|
+
entry.source.temporal?.previousInstances?.transforms,
|
|
1509
|
+
shadowInst.generations,
|
|
1510
|
+
entry.source.temporal?.previousInstances?.generations,
|
|
1511
|
+
);
|
|
1507
1512
|
const requestedBytes = instancePayload.byteLength;
|
|
1508
1513
|
const cap = runtime.device.limits.maxStorageBufferBindingSize;
|
|
1509
1514
|
if (!uniformFallback && typeof cap === 'number' && cap > 0 && requestedBytes > cap) {
|