@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
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { execFileSync } from 'node:child_process';
|
|
2
2
|
import { mkdir, writeFile } from 'node:fs/promises';
|
|
3
3
|
import { dirname } from 'node:path';
|
|
4
|
-
import { World } from '@forgeax/engine-ecs';
|
|
4
|
+
import { Time, World } from '@forgeax/engine-ecs';
|
|
5
5
|
import { RenderGraphBuilder } from '@forgeax/engine-render-graph';
|
|
6
6
|
import type {
|
|
7
7
|
BindGroupLayoutDescriptor,
|
|
8
|
+
Buffer,
|
|
8
9
|
RenderPipelineDescriptor,
|
|
9
10
|
RhiAdapter,
|
|
10
11
|
RhiDevice,
|
|
@@ -33,6 +34,7 @@ import {
|
|
|
33
34
|
deriveVolumetricFogExtent,
|
|
34
35
|
deriveVolumetricFogResolvedExtent,
|
|
35
36
|
inspectVolumetricFogResources,
|
|
37
|
+
VOLUMETRIC_FOG_PARAMS_BYTES,
|
|
36
38
|
} from '../volume/resources';
|
|
37
39
|
import { resolveVolumeTemporalReset } from '../volume/temporal';
|
|
38
40
|
|
|
@@ -62,15 +64,12 @@ class RecoverableNullDevice extends RhiNullDevice {
|
|
|
62
64
|
private readonly resolveLost: (info: LostInfo) => void;
|
|
63
65
|
private readonly lostPromise: Promise<LostInfo>;
|
|
64
66
|
|
|
65
|
-
constructor() {
|
|
67
|
+
constructor(queue: RhiNullQueue = new RhiNullQueue()) {
|
|
66
68
|
let resolveLost!: (info: LostInfo) => void;
|
|
67
69
|
const lostPromise = new Promise<LostInfo>((resolve) => {
|
|
68
70
|
resolveLost = resolve;
|
|
69
71
|
});
|
|
70
|
-
super(
|
|
71
|
-
new RhiNullQueue(),
|
|
72
|
-
(bookkeeper, device) => new RhiNullCommandEncoder(bookkeeper, device),
|
|
73
|
-
);
|
|
72
|
+
super(queue, (bookkeeper, device) => new RhiNullCommandEncoder(bookkeeper, device));
|
|
74
73
|
this.resolveLost = resolveLost;
|
|
75
74
|
this.lostPromise = lostPromise;
|
|
76
75
|
}
|
|
@@ -104,13 +103,44 @@ class RecoverableNullAdapter implements RhiAdapter {
|
|
|
104
103
|
readonly limits: Readonly<Record<string, number>> = {};
|
|
105
104
|
readonly devices: RecoverableNullDevice[] = [];
|
|
106
105
|
|
|
106
|
+
constructor(private readonly queueFactory: () => RhiNullQueue = () => new RhiNullQueue()) {}
|
|
107
|
+
|
|
107
108
|
requestDevice(): Promise<Result<RhiDevice, RhiError>> {
|
|
108
|
-
const device = new RecoverableNullDevice();
|
|
109
|
+
const device = new RecoverableNullDevice(this.queueFactory());
|
|
109
110
|
this.devices.push(device);
|
|
110
111
|
return Promise.resolve(ok(device));
|
|
111
112
|
}
|
|
112
113
|
}
|
|
113
114
|
|
|
115
|
+
interface CapturedQueueWrite {
|
|
116
|
+
readonly buffer: Buffer;
|
|
117
|
+
readonly offset: number;
|
|
118
|
+
readonly bytes: Uint8Array;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/** Captures the real record-stage volume parameter writes without adding a
|
|
122
|
+
* second render implementation. */
|
|
123
|
+
class RecordingNullQueue extends RhiNullQueue {
|
|
124
|
+
readonly writes: CapturedQueueWrite[] = [];
|
|
125
|
+
|
|
126
|
+
override writeBuffer(
|
|
127
|
+
buffer: Buffer,
|
|
128
|
+
bufferOffset: number,
|
|
129
|
+
data: ArrayBufferView | ArrayBuffer,
|
|
130
|
+
dataOffset?: number,
|
|
131
|
+
size?: number,
|
|
132
|
+
) {
|
|
133
|
+
const source =
|
|
134
|
+
data instanceof ArrayBuffer
|
|
135
|
+
? new Uint8Array(data)
|
|
136
|
+
: new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
|
|
137
|
+
const start = dataOffset ?? 0;
|
|
138
|
+
const end = size === undefined ? source.byteLength : start + size;
|
|
139
|
+
this.writes.push({ buffer, offset: bufferOffset, bytes: source.slice(start, end) });
|
|
140
|
+
return super.writeBuffer(buffer, bufferOffset, data, dataOffset, size);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
114
144
|
function surfaceCanvas(width = 1920, height = 1080): HTMLCanvasElement {
|
|
115
145
|
return { width, height, getContext: () => null } as unknown as HTMLCanvasElement;
|
|
116
146
|
}
|
|
@@ -336,11 +366,11 @@ describe('volumetric fog budget and recovery contract', () => {
|
|
|
336
366
|
label: 'volume-params',
|
|
337
367
|
kind: 'buffer',
|
|
338
368
|
origin: 'imported',
|
|
339
|
-
descriptor: { kind: 'buffer', size:
|
|
369
|
+
descriptor: { kind: 'buffer', size: VOLUMETRIC_FOG_PARAMS_BYTES },
|
|
340
370
|
firstUse: 0,
|
|
341
371
|
lastUse: 3,
|
|
342
372
|
derivedUsage: 64,
|
|
343
|
-
byteSize:
|
|
373
|
+
byteSize: VOLUMETRIC_FOG_PARAMS_BYTES,
|
|
344
374
|
},
|
|
345
375
|
],
|
|
346
376
|
} as const;
|
|
@@ -349,21 +379,25 @@ describe('volumetric fog budget and recovery contract', () => {
|
|
|
349
379
|
expect(facts.sampleCount).toBe(960 * 540 * 64);
|
|
350
380
|
expect(facts.resolvedPixelCount).toBe(960 * 540);
|
|
351
381
|
expect(facts.currentBytes).toBe(960 * 540 * 8);
|
|
352
|
-
expect(facts.bufferBytes).toBe(
|
|
382
|
+
expect(facts.bufferBytes).toBe(VOLUMETRIC_FOG_PARAMS_BYTES);
|
|
353
383
|
expect(facts.liveResourceCount).toBe(5);
|
|
354
384
|
expect(facts.historyBytes).toBe(960 * 540 * 8 * 2);
|
|
355
385
|
expect(facts.physicalResourceCount).toBe(5);
|
|
356
|
-
expect(facts.totalBytes).toBe(
|
|
386
|
+
expect(facts.totalBytes).toBe(
|
|
387
|
+
960 * 540 * 16 * 4 + 960 * 540 * 8 * 3 + VOLUMETRIC_FOG_PARAMS_BYTES,
|
|
388
|
+
);
|
|
357
389
|
expect(facts.totalBytes).toBe(
|
|
358
390
|
facts.currentBytes + facts.historyBytes + facts.scratchBytes + facts.bufferBytes,
|
|
359
391
|
);
|
|
360
392
|
expect(facts.totalBytes).toBeLessThanOrEqual(MAX_MEMORY_BYTES);
|
|
361
393
|
|
|
362
394
|
const doubleBuffered = inspectVolumetricFogResources(graph, { parameterBufferCount: 2 });
|
|
363
|
-
expect(doubleBuffered.bufferBytes).toBe(
|
|
395
|
+
expect(doubleBuffered.bufferBytes).toBe(VOLUMETRIC_FOG_PARAMS_BYTES * 2);
|
|
364
396
|
expect(doubleBuffered.liveResourceCount).toBe(6);
|
|
365
397
|
expect(doubleBuffered.physicalResourceCount).toBe(6);
|
|
366
|
-
expect(doubleBuffered.totalBytes).toBe(
|
|
398
|
+
expect(doubleBuffered.totalBytes).toBe(
|
|
399
|
+
960 * 540 * 16 * 4 + 960 * 540 * 8 * 3 + VOLUMETRIC_FOG_PARAMS_BYTES * 2,
|
|
400
|
+
);
|
|
367
401
|
expect(doubleBuffered.totalBytes).toBe(
|
|
368
402
|
doubleBuffered.currentBytes +
|
|
369
403
|
doubleBuffered.historyBytes +
|
|
@@ -372,6 +406,136 @@ describe('volumetric fog budget and recovery contract', () => {
|
|
|
372
406
|
);
|
|
373
407
|
});
|
|
374
408
|
|
|
409
|
+
it('uses the canonical World clock to bound real volume history reuse', async () => {
|
|
410
|
+
const queue = new RecordingNullQueue();
|
|
411
|
+
const adapter = new RecoverableNullAdapter(() => queue);
|
|
412
|
+
const backend = {
|
|
413
|
+
...nullRhi,
|
|
414
|
+
requestAdapter: async () => ok(adapter),
|
|
415
|
+
};
|
|
416
|
+
const created = await constructRendererHost(
|
|
417
|
+
surfaceCanvas(640, 360),
|
|
418
|
+
{ rhi: backend },
|
|
419
|
+
{ shaderManifestUrl: VOLUME_MANIFEST },
|
|
420
|
+
);
|
|
421
|
+
expect(created.ok).toBe(true);
|
|
422
|
+
if (!created.ok) return;
|
|
423
|
+
const { renderer } = created.value;
|
|
424
|
+
const world = new World();
|
|
425
|
+
const density = world.allocSharedRef('TextureAsset', densityAsset());
|
|
426
|
+
world
|
|
427
|
+
.spawn(
|
|
428
|
+
{ component: Transform, data: { pos: [0, 0, 3] } },
|
|
429
|
+
{
|
|
430
|
+
component: Camera,
|
|
431
|
+
data: {
|
|
432
|
+
...perspective({ fov: Math.PI / 4, aspect: 16 / 9 }),
|
|
433
|
+
tonemap: TONEMAP_ACES_FILMIC,
|
|
434
|
+
},
|
|
435
|
+
},
|
|
436
|
+
)
|
|
437
|
+
.unwrap();
|
|
438
|
+
const sun = world
|
|
439
|
+
.spawn({
|
|
440
|
+
component: DirectionalLight,
|
|
441
|
+
data: { direction: [-0.4, -0.8, -0.3], castShadow: true },
|
|
442
|
+
})
|
|
443
|
+
.unwrap();
|
|
444
|
+
world
|
|
445
|
+
.spawn({
|
|
446
|
+
component: VolumetricFog,
|
|
447
|
+
data: {
|
|
448
|
+
light: sun,
|
|
449
|
+
density,
|
|
450
|
+
boundsMin: [-1, -1, -1],
|
|
451
|
+
boundsMax: [1, 1, 1],
|
|
452
|
+
extinction: [0.2, 0.2, 0.2],
|
|
453
|
+
albedo: [0.8, 0.8, 0.8],
|
|
454
|
+
emission: [0, 0, 0],
|
|
455
|
+
anisotropy: 0,
|
|
456
|
+
maxDistance: 50,
|
|
457
|
+
},
|
|
458
|
+
})
|
|
459
|
+
.unwrap();
|
|
460
|
+
|
|
461
|
+
const lease = renderer.attach(world);
|
|
462
|
+
expect(lease.ok).toBe(true);
|
|
463
|
+
if (!lease.ok) return;
|
|
464
|
+
const request = {
|
|
465
|
+
leases: [lease.value],
|
|
466
|
+
camera: { lease: lease.value },
|
|
467
|
+
environment: { lease: lease.value },
|
|
468
|
+
} as const;
|
|
469
|
+
const drawAndRead = async (): Promise<{
|
|
470
|
+
readonly history: number;
|
|
471
|
+
readonly worldTime: number;
|
|
472
|
+
readonly delta: number;
|
|
473
|
+
}> => {
|
|
474
|
+
queue.writes.length = 0;
|
|
475
|
+
const frame = renderer.draw(request);
|
|
476
|
+
expect(frame.ok).toBe(true);
|
|
477
|
+
if (!frame.ok) return { history: -1, worldTime: -1, delta: -1 };
|
|
478
|
+
expect((await frame.value.completed).ok).toBe(true);
|
|
479
|
+
const paramsWrite = queue.writes
|
|
480
|
+
.filter((write) => write.offset === 0 && write.bytes.byteLength === 144)
|
|
481
|
+
.at(-1);
|
|
482
|
+
expect(paramsWrite).toBeDefined();
|
|
483
|
+
if (paramsWrite === undefined) return { history: -1, worldTime: -1, delta: -1 };
|
|
484
|
+
const historyWrite = queue.writes
|
|
485
|
+
.filter(
|
|
486
|
+
(write) =>
|
|
487
|
+
write.buffer === paramsWrite.buffer &&
|
|
488
|
+
write.offset === 31 * Float32Array.BYTES_PER_ELEMENT &&
|
|
489
|
+
write.bytes.byteLength === 3 * Float32Array.BYTES_PER_ELEMENT,
|
|
490
|
+
)
|
|
491
|
+
.at(-1);
|
|
492
|
+
expect(historyWrite).toBeDefined();
|
|
493
|
+
if (historyWrite === undefined) return { history: -1, worldTime: -1, delta: -1 };
|
|
494
|
+
return {
|
|
495
|
+
history: new Float32Array(
|
|
496
|
+
historyWrite.bytes.buffer,
|
|
497
|
+
historyWrite.bytes.byteOffset,
|
|
498
|
+
1,
|
|
499
|
+
)[0] as number,
|
|
500
|
+
worldTime: new Float32Array(
|
|
501
|
+
historyWrite.bytes.buffer,
|
|
502
|
+
historyWrite.bytes.byteOffset,
|
|
503
|
+
3,
|
|
504
|
+
)[1] as number,
|
|
505
|
+
delta: new Float32Array(
|
|
506
|
+
historyWrite.bytes.buffer,
|
|
507
|
+
historyWrite.bytes.byteOffset,
|
|
508
|
+
3,
|
|
509
|
+
)[2] as number,
|
|
510
|
+
};
|
|
511
|
+
};
|
|
512
|
+
|
|
513
|
+
world.update(1 / 60).unwrap();
|
|
514
|
+
const firstTime = world.getResource(Time).elapsed;
|
|
515
|
+
const first = await drawAndRead();
|
|
516
|
+
expect(first.worldTime).toBeCloseTo(firstTime, 5);
|
|
517
|
+
expect(first.history).toBe(0);
|
|
518
|
+
|
|
519
|
+
const stable = await drawAndRead();
|
|
520
|
+
expect(world.getResource(Time).elapsed).toBe(firstTime);
|
|
521
|
+
expect(stable.worldTime).toBeCloseTo(firstTime, 5);
|
|
522
|
+
expect(stable.history).toBe(1);
|
|
523
|
+
|
|
524
|
+
world.update(1 / 60).unwrap();
|
|
525
|
+
const movedTime = world.getResource(Time).elapsed;
|
|
526
|
+
const moved = await drawAndRead();
|
|
527
|
+
expect(moved.worldTime).toBeCloseTo(movedTime, 5);
|
|
528
|
+
expect(moved.worldTime).toBeGreaterThan(first.worldTime);
|
|
529
|
+
expect(moved.history).toBe(1);
|
|
530
|
+
expect(moved.delta).toBeCloseTo(1 / 60, 6);
|
|
531
|
+
expect(stable.delta).toBe(0);
|
|
532
|
+
for (let index = 0; index < 12; index += 1) world.update(1 / 60).unwrap();
|
|
533
|
+
const jumped = await drawAndRead();
|
|
534
|
+
expect(jumped.history).toBe(0);
|
|
535
|
+
expect(jumped.delta).toBeGreaterThan(0.1);
|
|
536
|
+
await renderer.dispose();
|
|
537
|
+
}, 30_000);
|
|
538
|
+
|
|
375
539
|
it('derives a same-XY resolve descriptor when the packed raw extent is supplied alone', async () => {
|
|
376
540
|
const adapter = await nullRhi.requestAdapter();
|
|
377
541
|
expect(adapter.ok).toBe(true);
|