@forgeax/engine-render 0.1.23 → 0.1.25
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 +231 -10
- package/dist/assembly/bundler-contract.d.ts +9 -0
- package/dist/assembly/bundler-contract.d.ts.map +1 -0
- package/dist/assembly/device-feature-admission.d.ts +8 -0
- package/dist/assembly/device-feature-admission.d.ts.map +1 -1
- package/dist/assembly/extended-lighting-fallback.d.ts +13 -0
- package/dist/assembly/extended-lighting-fallback.d.ts.map +1 -0
- package/dist/assembly/factory.d.ts +7 -243
- package/dist/assembly/factory.d.ts.map +1 -1
- package/dist/assembly/material/assembly.d.ts +3 -2
- package/dist/assembly/material/assembly.d.ts.map +1 -1
- package/dist/assembly/material/standard-layer-projection.d.ts +10 -0
- package/dist/assembly/material/standard-layer-projection.d.ts.map +1 -0
- package/dist/assembly/material/surface-projection.d.ts +24 -0
- package/dist/assembly/material/surface-projection.d.ts.map +1 -0
- package/dist/assembly/material-shader-policy.d.ts +188 -0
- package/dist/assembly/material-shader-policy.d.ts.map +1 -0
- package/dist/assembly/material-shader-prewarm.d.ts +21 -0
- package/dist/assembly/material-shader-prewarm.d.ts.map +1 -0
- package/dist/assembly/mesh-ssbo-grow.d.ts +88 -0
- package/dist/assembly/mesh-ssbo-grow.d.ts.map +1 -0
- package/dist/assembly/recovery/device-loss-fanout.d.ts +14 -0
- package/dist/assembly/recovery/device-loss-fanout.d.ts.map +1 -0
- package/dist/assembly/recovery/generation.d.ts +46 -0
- package/dist/assembly/recovery/generation.d.ts.map +1 -0
- package/dist/assembly/recovery/recovery-attempt.d.ts +63 -0
- package/dist/assembly/recovery/recovery-attempt.d.ts.map +1 -0
- package/dist/assembly/recovery/renderer-recover.d.ts +115 -0
- package/dist/assembly/recovery/renderer-recover.d.ts.map +1 -0
- package/dist/assembly/renderer-facade.d.ts +10 -0
- package/dist/assembly/renderer-facade.d.ts.map +1 -0
- package/dist/assembly/renderer-frame-transaction.d.ts +17 -0
- package/dist/assembly/renderer-frame-transaction.d.ts.map +1 -1
- package/dist/assembly/renderer-helpers.d.ts +19 -0
- package/dist/assembly/renderer-helpers.d.ts.map +1 -0
- package/dist/assembly/renderer-lifecycle.d.ts +34 -0
- package/dist/assembly/renderer-lifecycle.d.ts.map +1 -1
- package/dist/assembly/shader-prewarm-policy.d.ts +15 -0
- package/dist/assembly/shader-prewarm-policy.d.ts.map +1 -0
- package/dist/assembly/webgpu-ready-contract.d.ts +9 -0
- package/dist/assembly/webgpu-ready-contract.d.ts.map +1 -0
- package/dist/assembly/webgpu-ready.d.ts +55 -0
- package/dist/assembly/webgpu-ready.d.ts.map +1 -0
- package/dist/assembly/webgpu-renderer.d.ts +152 -0
- package/dist/assembly/webgpu-renderer.d.ts.map +1 -0
- package/dist/assembly/webgpu-vertex-layouts.d.ts +89 -0
- package/dist/assembly/webgpu-vertex-layouts.d.ts.map +1 -0
- package/dist/assets/asset-decoders.d.ts.map +1 -1
- package/dist/authoring.mjs +1 -1
- package/dist/{chunk-FF7K3FSO.mjs → chunk-ADHHVYLW.mjs} +89 -89
- package/dist/chunk-ADHHVYLW.mjs.map +1 -0
- package/dist/{chunk-YALPS44A.mjs → chunk-E34VL5VI.mjs} +47 -47
- package/dist/chunk-E34VL5VI.mjs.map +1 -0
- package/dist/{chunk-4L3P6DT5.mjs → chunk-GE3SDD72.mjs} +37 -5
- package/dist/chunk-GE3SDD72.mjs.map +1 -0
- package/dist/{chunk-HZUPSYW7.mjs → chunk-HKXTW355.mjs} +105 -15
- package/dist/chunk-HKXTW355.mjs.map +1 -0
- package/dist/chunk-JSEDTZYS.mjs +413 -0
- package/dist/chunk-JSEDTZYS.mjs.map +1 -0
- package/dist/{chunk-FBC4R44J.mjs → chunk-KM2NOX2I.mjs} +57 -57
- package/dist/chunk-KM2NOX2I.mjs.map +1 -0
- package/dist/{chunk-DIYW3M5D.mjs → chunk-N3RT2EUR.mjs} +2288 -2238
- package/dist/chunk-N3RT2EUR.mjs.map +1 -0
- package/dist/{chunk-ZUWKAZ2I.mjs → chunk-TCLDX7SZ.mjs} +1167 -368
- package/dist/chunk-TCLDX7SZ.mjs.map +1 -0
- package/dist/{chunk-QODA5UKU.mjs → chunk-ZZ4YQ474.mjs} +2 -2
- package/dist/chunk-ZZ4YQ474.mjs.map +1 -0
- package/dist/components/instances.d.ts +13 -31
- package/dist/components/instances.d.ts.map +1 -1
- package/dist/construct-renderer.mjs +20688 -16314
- package/dist/construct-renderer.mjs.map +1 -1
- package/dist/device/device-scope.d.ts +2 -0
- package/dist/device/device-scope.d.ts.map +1 -1
- package/dist/device/gpu-residency.d.ts +24 -4
- package/dist/device/gpu-residency.d.ts.map +1 -1
- package/dist/environment/frame.d.ts +5 -0
- package/dist/environment/frame.d.ts.map +1 -1
- package/dist/environment/inspection.d.ts +7 -0
- package/dist/environment/inspection.d.ts.map +1 -1
- package/dist/environment/lifecycle.d.ts +20 -2
- package/dist/environment/lifecycle.d.ts.map +1 -1
- package/dist/errors/recover.d.ts +58 -2
- package/dist/errors/recover.d.ts.map +1 -1
- package/dist/errors/render.d.ts +13 -0
- package/dist/errors/render.d.ts.map +1 -1
- package/dist/extract/contracts.d.ts +899 -0
- package/dist/extract/contracts.d.ts.map +1 -0
- package/dist/features/host.d.ts +2 -0
- package/dist/features/host.d.ts.map +1 -1
- package/dist/features/prepared-gpu-work.d.ts +3 -0
- package/dist/features/prepared-gpu-work.d.ts.map +1 -1
- package/dist/features/prepared-graphics-store.d.ts +2 -0
- package/dist/features/prepared-graphics-store.d.ts.map +1 -1
- package/dist/gpu-driven/production-raster.d.ts +34 -1
- package/dist/gpu-driven/production-raster.d.ts.map +1 -1
- package/dist/gpu-scene.d.ts +5 -0
- package/dist/gpu-scene.d.ts.map +1 -1
- package/dist/ibl/IblPipelineCache.d.ts +7 -6
- package/dist/ibl/IblPipelineCache.d.ts.map +1 -1
- package/dist/ibl/skylight-bind-group.d.ts +7 -1
- package/dist/ibl/skylight-bind-group.d.ts.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.mjs +27 -9
- package/dist/index.mjs.map +1 -1
- package/dist/instance-buffer-cache.d.ts +7 -1
- package/dist/instance-buffer-cache.d.ts.map +1 -1
- package/dist/instances.d.ts +101 -0
- package/dist/instances.d.ts.map +1 -0
- package/dist/internal.mjs +6 -6
- package/dist/light-buffer-layout.d.ts +3 -0
- package/dist/light-buffer-layout.d.ts.map +1 -1
- package/dist/materials.d.ts +96 -11
- package/dist/materials.d.ts.map +1 -1
- package/dist/mesh-material-bindings.d.ts +56 -0
- package/dist/mesh-material-bindings.d.ts.map +1 -1
- package/dist/occlusion-proxy.d.ts +4 -0
- package/dist/occlusion-proxy.d.ts.map +1 -0
- package/dist/pbr-pipeline.d.ts +32 -9
- package/dist/pbr-pipeline.d.ts.map +1 -1
- package/dist/pipeline-builder.d.ts.map +1 -1
- package/dist/pipeline-spec.d.ts.map +1 -1
- package/dist/points-lines/prepare.d.ts +3 -0
- package/dist/points-lines/prepare.d.ts.map +1 -1
- package/dist/points-lines/standard-owner.d.ts +33 -0
- package/dist/points-lines/standard-owner.d.ts.map +1 -0
- package/dist/record/frame-snapshot.d.ts +18 -2
- 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 +14 -2
- package/dist/record/frame.d.ts.map +1 -1
- package/dist/record/main-pass-geometry.d.ts +36 -4
- package/dist/record/main-pass-geometry.d.ts.map +1 -1
- package/dist/record/main-pass-material.d.ts +7 -17
- package/dist/record/main-pass-material.d.ts.map +1 -1
- package/dist/record/main-pass.d.ts.map +1 -1
- package/dist/record/mesh-ssbo.d.ts +11 -3
- package/dist/record/mesh-ssbo.d.ts.map +1 -1
- package/dist/record/recovery-pipeline.d.ts +30 -0
- package/dist/record/recovery-pipeline.d.ts.map +1 -0
- package/dist/record/render-context.d.ts +28 -5
- package/dist/record/render-context.d.ts.map +1 -1
- package/dist/record/shadow-pass.d.ts +11 -1
- package/dist/record/shadow-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 +65 -0
- package/dist/recovery/render-system-candidate.d.ts.map +1 -0
- package/dist/render-contract.d.ts +68 -7
- package/dist/render-contract.d.ts.map +1 -1
- package/dist/render-system-extract-tail.d.ts +16 -0
- package/dist/render-system-extract-tail.d.ts.map +1 -0
- package/dist/render-system-extract.d.ts +180 -22
- package/dist/render-system-extract.d.ts.map +1 -1
- package/dist/render-system.d.ts +131 -4
- package/dist/render-system.d.ts.map +1 -1
- package/dist/scene/render-scene-types.d.ts +2 -0
- package/dist/scene/render-scene-types.d.ts.map +1 -1
- package/dist/scene/render-scene.d.ts +31 -1
- package/dist/scene/render-scene.d.ts.map +1 -1
- package/dist/systems/skin-palette-allocator.d.ts +6 -0
- package/dist/systems/skin-palette-allocator.d.ts.map +1 -1
- package/dist/temporal/frame-coordinator.d.ts.map +1 -1
- package/dist/temporal/index.mjs +6 -6
- package/dist/temporal/taa-history-store.d.ts +15 -1
- package/dist/temporal/taa-history-store.d.ts.map +1 -1
- package/dist/temporal/transaction.d.ts +5 -0
- package/dist/temporal/transaction.d.ts.map +1 -1
- package/package.json +20 -20
- package/src/__tests__/device-feature-admission.unit.test.ts +6 -0
- package/src/__tests__/device-loss-fanout.unit.test.ts +107 -0
- package/src/__tests__/device-scope-lifecycle.unit.test.ts +21 -0
- package/src/__tests__/environment-generation.integration.test.ts +23 -0
- package/src/__tests__/expose-renderer-errors.unit.test.ts +34 -0
- package/src/__tests__/factory-contract.integration.test.ts +122 -7
- package/src/__tests__/fallback-row-stride-surface.unit.test.ts +4 -1
- package/src/__tests__/gpu-scene.unit.test.ts +38 -2
- package/src/__tests__/ibl/face-uniforms.unit.test.ts +2 -0
- package/src/__tests__/ibl-residency-publication.unit.test.ts +113 -0
- package/src/__tests__/instances-store.unit.test.ts +46 -0
- package/src/__tests__/instances-world-ownership.integration.test.ts +62 -0
- package/src/__tests__/material-contract-inventory.unit.test.ts +29 -22
- package/src/__tests__/material-cooked-projection.unit.test.ts +19 -1
- package/src/__tests__/material-pass-policy.unit.test.ts +69 -0
- package/src/__tests__/material-snapshot-mutation.integration.test.ts +69 -0
- package/src/__tests__/material-static-dynamic-route.unit.test.ts +29 -0
- package/src/__tests__/material-stride-surface.unit.test.ts +7 -3
- package/src/__tests__/material-surface-authoring.test-d.ts +62 -0
- package/src/__tests__/materials-standard-contract.unit.test.ts +104 -0
- package/src/__tests__/materials-transmission-validation.unit.test.ts +24 -0
- package/src/__tests__/mesh-buffer-usage-surface.unit.test.ts +1 -5
- package/src/__tests__/physical-clearcoat.integration.test.ts +89 -0
- package/src/__tests__/prepared-gpu-driven-pbr.integration.test.ts +1 -1
- package/src/__tests__/prepared-graphics-pipeline-warmup.unit.test.ts +1 -1
- package/src/__tests__/recover-error-policy-owner.unit.test.ts +6 -3
- package/src/__tests__/recovery-candidate-prepare.contract.test.ts +140 -0
- package/src/__tests__/renderer-factory-material-contract.unit.test.ts +127 -18
- package/src/__tests__/renderer-frame-generation-fence.integration.test.ts +47 -0
- package/src/__tests__/renderer-generation-assembly.unit.test.ts +77 -0
- package/src/__tests__/renderer-generation-failure.unit.test.ts +108 -0
- package/src/__tests__/renderer-producer-root-matrix.integration.test.ts +33 -0
- package/src/__tests__/renderer-recovery-capability-matrix.unit.test.ts +59 -0
- package/src/__tests__/renderer-recovery-contract.unit.test.ts +73 -0
- package/src/__tests__/renderer-recovery-lifecycle.unit.test.ts +216 -0
- package/src/__tests__/renderer-target-history-recovery.integration.test.ts +80 -0
- package/src/__tests__/shader-manifest-fixture.ts +13 -16
- package/src/__tests__/shader-stage-surface.unit.test.ts +1 -1
- package/src/__tests__/skin-motion-regression.unit.test.ts +33 -0
- package/src/__tests__/skinned-shadow-caster.test.ts +30 -2
- package/src/__tests__/standard-layer-projection.unit.test.ts +23 -0
- package/src/__tests__/surface-adjacent-regressions.integration.test.ts +60 -0
- package/src/__tests__/surface-standard-pipeline.browser.test.ts +20 -0
- package/src/__tests__/surface-standard-pipeline.dawn.test.ts +20 -0
- package/src/__tests__/surface-standard-pipeline.fixture.ts +132 -0
- package/src/__tests__/surface-variant-provenance.integration.test.ts +33 -0
- package/src/__tests__/transmission-prewarm.unit.test.ts +95 -85
- package/src/__tests__/volumetric-fog-budget-recovery.integration.test.ts +1 -1
- package/src/__tests__/volumetric-fog-topology.unit.test.ts +3 -1
- package/src/assembly/bundler-contract.ts +9 -0
- package/src/assembly/device-feature-admission.ts +15 -5
- package/src/assembly/extended-lighting-fallback.ts +216 -0
- package/src/assembly/factory.ts +83 -10088
- package/src/assembly/material/__tests__/standard-layer-plan-projection.integration.test.ts +18 -0
- package/src/assembly/material/__tests__/surface-pass-projection.integration.test.ts +62 -0
- package/src/assembly/material/assembly.ts +18 -2
- package/src/assembly/material/standard-layer-projection.ts +16 -0
- package/src/assembly/material/surface-projection.ts +90 -0
- package/src/assembly/material-shader-policy.ts +932 -0
- package/src/assembly/material-shader-prewarm.ts +88 -0
- package/src/assembly/mesh-ssbo-grow.ts +270 -0
- package/src/assembly/recovery/device-loss-fanout.ts +89 -0
- package/src/assembly/recovery/generation.ts +141 -0
- package/src/assembly/recovery/recovery-attempt.ts +800 -0
- package/src/assembly/recovery/renderer-recover.ts +906 -0
- package/src/assembly/renderer-facade.ts +342 -0
- package/src/assembly/renderer-frame-transaction.ts +45 -0
- package/src/assembly/renderer-helpers.ts +99 -0
- package/src/assembly/renderer-lifecycle.ts +159 -0
- package/src/assembly/shader-prewarm-policy.ts +157 -0
- package/src/assembly/webgpu-ready-contract.ts +14 -0
- package/src/assembly/webgpu-ready.ts +4066 -0
- package/src/assembly/webgpu-renderer.ts +4027 -0
- package/src/assembly/webgpu-vertex-layouts.ts +132 -0
- package/src/assets/asset-decoders.ts +27 -4
- package/src/components/camera.ts +1 -1
- package/src/components/instances.ts +14 -197
- package/src/debug-draw-glue.ts +1 -1
- package/src/device/device-scope.ts +35 -6
- package/src/device/gpu-residency.ts +194 -26
- package/src/environment/frame.ts +6 -0
- package/src/environment/inspection.ts +10 -0
- package/src/environment/lifecycle.ts +114 -8
- package/src/errors/recover.ts +76 -5
- package/src/errors/render.ts +17 -0
- package/src/extract/contracts.ts +974 -0
- package/src/features/host.ts +16 -0
- package/src/features/prepared-gpu-work.ts +20 -2
- package/src/features/prepared-graphics-store.ts +17 -0
- package/src/gpu-driven/production-raster.ts +131 -3
- package/src/gpu-scene.ts +87 -31
- package/src/ibl/IblPipelineCache.ts +134 -50
- package/src/ibl/skylight-bind-group.ts +26 -0
- package/src/index.ts +10 -1
- package/src/instance-buffer-cache.ts +14 -1
- package/src/instances.ts +288 -0
- package/src/light-buffer-layout.ts +3 -0
- package/src/materials.ts +365 -53
- package/src/mesh-material-bindings.ts +59 -0
- package/src/occlusion-proxy.ts +64 -0
- package/src/pbr-pipeline.ts +139 -15
- package/src/pipeline-builder.ts +14 -10
- package/src/pipeline-spec.ts +6 -14
- package/src/points-lines/__tests__/cache-recovery.unit.test.ts +22 -0
- package/src/points-lines/prepare.ts +9 -0
- package/src/points-lines/standard-owner.ts +403 -0
- package/src/record/__tests__/frame-targets-recovery.unit.test.ts +60 -0
- package/src/record/__tests__/main-pass-geometry.unit.test.ts +26 -1
- package/src/record/__tests__/mesh-ssbo.unit.test.ts +38 -0
- package/src/record/__tests__/recovery-pipeline.unit.test.ts +124 -0
- package/src/record/__tests__/sprite-material-abi.unit.test.ts +28 -13
- package/src/record/__tests__/standard-pbr-ubo-layout.unit.test.ts +47 -4
- package/src/record/__tests__/temporal-payload.unit.test.ts +22 -43
- package/src/record/__tests__/typed-frame-graph-plan.unit.test.ts +1 -1
- package/src/record/frame-snapshot.ts +34 -2
- package/src/record/frame-targets.ts +11 -1
- package/src/record/frame.ts +37 -4
- package/src/record/helpers.ts +1 -1
- package/src/record/main-pass-geometry.ts +727 -63
- package/src/record/main-pass-material.ts +316 -209
- package/src/record/main-pass-sprite-draws.ts +7 -8
- package/src/record/main-pass.ts +94 -6
- package/src/record/mesh-ssbo.ts +32 -10
- package/src/record/recovery-pipeline.ts +695 -0
- package/src/record/render-context.ts +39 -4
- package/src/record/shadow-pass.ts +46 -99
- package/src/record/typed-frame-graph.ts +45 -1
- package/src/record/view-ubo.ts +3 -3
- package/src/recovery/render-system-candidate.ts +876 -0
- package/src/render-contract.ts +69 -7
- package/src/render-system-extract-tail.ts +3039 -0
- package/src/render-system-extract.ts +177 -3003
- package/src/render-system.ts +906 -662
- package/src/scene/render-scene-types.ts +2 -0
- package/src/scene/render-scene.ts +703 -37
- package/src/systems/skin-palette-allocator.ts +129 -7
- package/src/temporal/frame-coordinator.ts +4 -1
- package/src/temporal/taa-history-store.ts +46 -2
- package/src/temporal/temporal-view.ts +1 -1
- package/src/temporal/transaction.ts +9 -0
- package/src/tilemap-chunk-extract-system.ts +1 -1
- package/src/transmission/__tests__/standard-transmission.dawn.test.ts +19 -12
- package/src/transmission/__tests__/surface-compatibility.integration.test.ts +32 -0
- package/dist/chunk-4L3P6DT5.mjs.map +0 -1
- package/dist/chunk-4NPUASZR.mjs +0 -203
- package/dist/chunk-4NPUASZR.mjs.map +0 -1
- package/dist/chunk-DIYW3M5D.mjs.map +0 -1
- package/dist/chunk-FBC4R44J.mjs.map +0 -1
- package/dist/chunk-FF7K3FSO.mjs.map +0 -1
- package/dist/chunk-HZUPSYW7.mjs.map +0 -1
- package/dist/chunk-QODA5UKU.mjs.map +0 -1
- package/dist/chunk-YALPS44A.mjs.map +0 -1
- package/dist/chunk-ZUWKAZ2I.mjs.map +0 -1
|
@@ -1,10 +1,27 @@
|
|
|
1
1
|
import type { Buffer, Sampler, TextureView } from '@forgeax/engine-rhi';
|
|
2
2
|
import { describe, expect, it } from 'vitest';
|
|
3
3
|
import { assembleMaterialWithSkylightEntries } from '../../ibl/skylight-bind-group';
|
|
4
|
+
import { defaultViewForUserRegionField } from '../main-pass-material';
|
|
4
5
|
import { buildSpritePassBaseMaterialEntries } from '../main-pass-sprite-draws';
|
|
5
6
|
import type { PipelineState } from '../render-context';
|
|
6
7
|
|
|
7
8
|
describe('sprite Standard material ABI', () => {
|
|
9
|
+
it('uses the dedicated neutral anisotropy fallback instead of white', () => {
|
|
10
|
+
const white = {} as TextureView;
|
|
11
|
+
const anisotropy = {} as TextureView;
|
|
12
|
+
const pipelineState = {
|
|
13
|
+
defaultWhiteTextureView: white,
|
|
14
|
+
defaultAnisotropyTextureView: anisotropy,
|
|
15
|
+
defaultNormalTextureView: {} as TextureView,
|
|
16
|
+
fallbackTextureView: {} as TextureView,
|
|
17
|
+
} as PipelineState;
|
|
18
|
+
|
|
19
|
+
expect(defaultViewForUserRegionField('anisotropyTexture', pipelineState)).toBe(anisotropy);
|
|
20
|
+
expect(defaultViewForUserRegionField('baseColorTexture', pipelineState)).toBe(
|
|
21
|
+
pipelineState.fallbackTextureView,
|
|
22
|
+
);
|
|
23
|
+
});
|
|
24
|
+
|
|
8
25
|
it('covers transmission and thickness before IBL injection', () => {
|
|
9
26
|
const sampler = {} as Sampler;
|
|
10
27
|
const white = {} as TextureView;
|
|
@@ -21,14 +38,12 @@ describe('sprite Standard material ABI', () => {
|
|
|
21
38
|
const entries = buildSpritePassBaseMaterialEntries(pipelineState, spriteTexture);
|
|
22
39
|
|
|
23
40
|
expect(entries.map((entry) => entry.binding)).toEqual([
|
|
24
|
-
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
|
|
41
|
+
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
|
|
25
42
|
]);
|
|
26
43
|
expect(entries[13]).toMatchObject({ binding: 13, resource: { kind: 'sampler' } });
|
|
27
44
|
expect(entries[14]).toMatchObject({ binding: 14, resource: { kind: 'textureView' } });
|
|
28
|
-
expect(entries[15]).toMatchObject({ binding: 15, resource: { kind: 'sampler' } });
|
|
29
|
-
expect(entries[16]).toMatchObject({ binding: 16, resource: { kind: 'textureView' } });
|
|
30
45
|
expect(entries[2]?.resource).toMatchObject({ kind: 'textureView', value: spriteTexture });
|
|
31
|
-
expect(entries).toHaveLength(
|
|
46
|
+
expect(entries).toHaveLength(15);
|
|
32
47
|
|
|
33
48
|
const merged = assembleMaterialWithSkylightEntries(entries, {
|
|
34
49
|
irradianceView: {} as TextureView,
|
|
@@ -39,19 +54,19 @@ describe('sprite Standard material ABI', () => {
|
|
|
39
54
|
brdfLutSampler: sampler,
|
|
40
55
|
intensityBuffer: {} as Buffer,
|
|
41
56
|
});
|
|
42
|
-
expect(merged[
|
|
43
|
-
binding:
|
|
57
|
+
expect(merged[15]).toMatchObject({
|
|
58
|
+
binding: 15,
|
|
44
59
|
resource: { kind: 'textureView' },
|
|
45
60
|
});
|
|
46
|
-
expect(merged[
|
|
47
|
-
binding:
|
|
61
|
+
expect(merged[22]).toMatchObject({
|
|
62
|
+
binding: 22,
|
|
48
63
|
resource: { kind: 'sampler', value: sampler },
|
|
49
64
|
});
|
|
50
|
-
expect(merged[
|
|
51
|
-
binding:
|
|
65
|
+
expect(merged[23]).toMatchObject({
|
|
66
|
+
binding: 23,
|
|
52
67
|
resource: { kind: 'textureView' },
|
|
53
68
|
});
|
|
54
|
-
expect(merged).toHaveLength(
|
|
69
|
+
expect(merged).toHaveLength(24);
|
|
55
70
|
|
|
56
71
|
const backdrop = {} as TextureView;
|
|
57
72
|
const active = assembleMaterialWithSkylightEntries(
|
|
@@ -67,8 +82,8 @@ describe('sprite Standard material ABI', () => {
|
|
|
67
82
|
},
|
|
68
83
|
{ sampler, backdropView: backdrop },
|
|
69
84
|
);
|
|
70
|
-
expect(active[
|
|
71
|
-
binding:
|
|
85
|
+
expect(active[23]).toMatchObject({
|
|
86
|
+
binding: 23,
|
|
72
87
|
resource: { kind: 'textureView', value: backdrop },
|
|
73
88
|
});
|
|
74
89
|
});
|
|
@@ -14,7 +14,7 @@ describe('Standard PBR UBO layout', () => {
|
|
|
14
14
|
derived.coordinateRecords.map((record) => [record.parameter, record.offset]),
|
|
15
15
|
);
|
|
16
16
|
|
|
17
|
-
expect(derived.totalBytes).toBe(
|
|
17
|
+
expect(derived.totalBytes).toBe(736);
|
|
18
18
|
expect(numeric.get('normalScale')).toBe(92);
|
|
19
19
|
expect(numeric.get('transmission')).toBe(96);
|
|
20
20
|
expect(numeric.get('ior')).toBe(100);
|
|
@@ -26,6 +26,26 @@ describe('Standard PBR UBO layout', () => {
|
|
|
26
26
|
expect(coordinates.get('thicknessTexture')).toBe(352);
|
|
27
27
|
});
|
|
28
28
|
|
|
29
|
+
it('reserves the physical-layer tail required by the clearcoat shader ABI', () => {
|
|
30
|
+
const material = {
|
|
31
|
+
baseColor: vec3.create(0.7, 0.7, 0.7),
|
|
32
|
+
metallic: 0,
|
|
33
|
+
roughness: 0.4,
|
|
34
|
+
materialShaderId: 'forgeax::default-standard-pbr',
|
|
35
|
+
materialParamSchema: DEFAULT_STANDARD_PBR_PARAM_SCHEMA,
|
|
36
|
+
paramSnapshot: {
|
|
37
|
+
clearcoat: 0.8,
|
|
38
|
+
clearcoatRoughness: 0.2,
|
|
39
|
+
clearcoatNormalScale: 0.75,
|
|
40
|
+
},
|
|
41
|
+
} satisfies MaterialSnapshot;
|
|
42
|
+
const payload = buildPbrMaterialUboPayload(material);
|
|
43
|
+
const f32 = new Float32Array(payload.buffer);
|
|
44
|
+
|
|
45
|
+
expect(payload.byteLength).toBe(736);
|
|
46
|
+
expect(f32.slice(108, 111)).toEqual(new Float32Array([0.8, 0.2, 0.75]));
|
|
47
|
+
});
|
|
48
|
+
|
|
29
49
|
it('writes transmission scalars and defaults at the reflected offsets', () => {
|
|
30
50
|
const material = {
|
|
31
51
|
baseColor: vec3.create(0.7, 0.7, 0.7),
|
|
@@ -33,6 +53,7 @@ describe('Standard PBR UBO layout', () => {
|
|
|
33
53
|
roughness: 0.4,
|
|
34
54
|
normalScale: 0.25,
|
|
35
55
|
materialShaderId: 'forgeax::default-standard-pbr',
|
|
56
|
+
materialParamSchema: DEFAULT_STANDARD_PBR_PARAM_SCHEMA,
|
|
36
57
|
paramSnapshot: {
|
|
37
58
|
transmission: 0.75,
|
|
38
59
|
ior: 1.6,
|
|
@@ -48,7 +69,7 @@ describe('Standard PBR UBO layout', () => {
|
|
|
48
69
|
);
|
|
49
70
|
});
|
|
50
71
|
|
|
51
|
-
it('uses all
|
|
72
|
+
it('uses all seven user-region identity coordinate records in the no-snapshot fallback', () => {
|
|
52
73
|
const material = {
|
|
53
74
|
baseColor: vec3.create(0.7, 0.7, 0.7),
|
|
54
75
|
metallic: 0,
|
|
@@ -60,8 +81,30 @@ describe('Standard PBR UBO layout', () => {
|
|
|
60
81
|
applyMaterialTextureUvScales(payload, material, new World());
|
|
61
82
|
|
|
62
83
|
const f32 = new Float32Array(payload.buffer);
|
|
63
|
-
expect(f32.slice(32,
|
|
64
|
-
new Float32Array(Array(
|
|
84
|
+
expect(f32.slice(32, 88)).toEqual(
|
|
85
|
+
new Float32Array(Array(7).fill([0, 0, 1, 1, 0, 0, 1, 1]).flat()),
|
|
65
86
|
);
|
|
66
87
|
});
|
|
88
|
+
|
|
89
|
+
it('keeps the physical tail intact when standard coordinates are projected', () => {
|
|
90
|
+
const material = {
|
|
91
|
+
baseColor: vec3.create(0.7, 0.7, 0.7),
|
|
92
|
+
metallic: 0,
|
|
93
|
+
roughness: 0.4,
|
|
94
|
+
materialShaderId: 'forgeax::default-standard-pbr',
|
|
95
|
+
materialParamSchema: DEFAULT_STANDARD_PBR_PARAM_SCHEMA,
|
|
96
|
+
paramSnapshot: {
|
|
97
|
+
clearcoat: 1,
|
|
98
|
+
clearcoatRoughness: 0.18,
|
|
99
|
+
clearcoatNormalScale: 0.75,
|
|
100
|
+
},
|
|
101
|
+
} satisfies MaterialSnapshot;
|
|
102
|
+
const payload = buildPbrMaterialUboPayload(material);
|
|
103
|
+
|
|
104
|
+
applyMaterialTextureUvScales(payload, material, new World());
|
|
105
|
+
|
|
106
|
+
const f32 = new Float32Array(payload.buffer);
|
|
107
|
+
expect(f32.slice(108, 111)).toEqual(new Float32Array([1, 0.18, 0.75]));
|
|
108
|
+
expect(f32.slice(32, 40)).toEqual(new Float32Array([0, 0, 1, 1, 0, 0, 1, 1]));
|
|
109
|
+
});
|
|
67
110
|
});
|
|
@@ -2,7 +2,7 @@ import { vec3 } from '@forgeax/engine-math';
|
|
|
2
2
|
import type { Buffer, RhiQueue } from '@forgeax/engine-rhi';
|
|
3
3
|
import { describe, expect, it } from 'vitest';
|
|
4
4
|
import type { CameraSnapshot } from '../../render-contract';
|
|
5
|
-
import type { RenderableSnapshot
|
|
5
|
+
import type { RenderableSnapshot } from '../../render-system-extract';
|
|
6
6
|
import type { TemporalView } from '../../temporal/temporal-view';
|
|
7
7
|
import type { ValidatedRenderable } from '../frame-snapshot';
|
|
8
8
|
import { uploadMeshSsboBatch } from '../mesh-ssbo';
|
|
@@ -98,27 +98,8 @@ function temporalView(): TemporalView {
|
|
|
98
98
|
}
|
|
99
99
|
|
|
100
100
|
describe('temporal GPU payloads', () => {
|
|
101
|
-
it('
|
|
101
|
+
it('keeps the zero-directional fallback direction finite and unscaled', () => {
|
|
102
102
|
const { queue, uploads } = recordingQueue();
|
|
103
|
-
const projectorMatrix = translatedMatrix(9);
|
|
104
|
-
const projector: SpotLightSnapshot = {
|
|
105
|
-
kind: 'spot',
|
|
106
|
-
entity: 4,
|
|
107
|
-
position: vec3.create(0, 2, 0),
|
|
108
|
-
direction: vec3.create(0, -1, 0),
|
|
109
|
-
color: vec3.create(1, 1, 1),
|
|
110
|
-
intensity: 1,
|
|
111
|
-
invRangeSquared: 0.04,
|
|
112
|
-
cosInner: 0.95,
|
|
113
|
-
cosOuter: 0.8,
|
|
114
|
-
castShadow: false,
|
|
115
|
-
lightViewProj: projectorMatrix,
|
|
116
|
-
mapSize: 512,
|
|
117
|
-
nearPlane: 0.1,
|
|
118
|
-
farPlane: 25,
|
|
119
|
-
shadowAtlasTile: -1,
|
|
120
|
-
projectorAsset: { kind: 'texture' } as never,
|
|
121
|
-
};
|
|
122
103
|
writeViewUbo(
|
|
123
104
|
queue,
|
|
124
105
|
{} as Buffer,
|
|
@@ -126,19 +107,20 @@ describe('temporal GPU payloads', () => {
|
|
|
126
107
|
{
|
|
127
108
|
kind: 'directional',
|
|
128
109
|
direction: vec3.create(0, -1, 0),
|
|
129
|
-
color: vec3.create(
|
|
130
|
-
intensity:
|
|
110
|
+
color: vec3.create(0, 0, 0),
|
|
111
|
+
intensity: 0,
|
|
131
112
|
},
|
|
132
|
-
{ point: [], spot: [
|
|
133
|
-
[
|
|
134
|
-
undefined,
|
|
135
|
-
0,
|
|
113
|
+
{ point: [], spot: [] } as never,
|
|
114
|
+
[],
|
|
136
115
|
);
|
|
116
|
+
|
|
137
117
|
const payload = new Float32Array(uploads[0]?.buffer ?? new ArrayBuffer(0));
|
|
138
|
-
expect(payload[
|
|
118
|
+
expect(Array.from(payload.slice(16, 19))).toEqual([0, -1, 0]);
|
|
119
|
+
expect(Array.from(payload.slice(20, 23))).toEqual([0, 0, 0]);
|
|
120
|
+
expect(Array.from(payload.slice(16, 23)).every(Number.isFinite)).toBe(true);
|
|
139
121
|
});
|
|
140
122
|
|
|
141
|
-
it('
|
|
123
|
+
it('keeps directional orientation independent from light intensity', () => {
|
|
142
124
|
const { queue, uploads } = recordingQueue();
|
|
143
125
|
writeViewUbo(
|
|
144
126
|
queue,
|
|
@@ -146,28 +128,20 @@ describe('temporal GPU payloads', () => {
|
|
|
146
128
|
camera(),
|
|
147
129
|
{
|
|
148
130
|
kind: 'directional',
|
|
149
|
-
direction: vec3.create(0, -
|
|
131
|
+
direction: vec3.create(0.25, -0.5, 0.75),
|
|
150
132
|
color: vec3.create(1, 1, 1),
|
|
151
|
-
intensity:
|
|
133
|
+
intensity: 4,
|
|
152
134
|
},
|
|
153
135
|
{ point: [], spot: [] } as never,
|
|
154
136
|
[],
|
|
155
|
-
temporalView(),
|
|
156
137
|
);
|
|
157
138
|
|
|
158
139
|
const payload = new Float32Array(uploads[0]?.buffer ?? new ArrayBuffer(0));
|
|
159
|
-
expect(payload.
|
|
160
|
-
expect(payload[196]).toBeCloseTo(Math.sqrt(3));
|
|
161
|
-
expect(payload[212]).toBe(3);
|
|
162
|
-
expect(payload[228]).toBeCloseTo(0.1);
|
|
163
|
-
expect(payload[229]).toBe(100);
|
|
164
|
-
expect(payload[230]).toBe(0);
|
|
140
|
+
expect(Array.from(payload.slice(16, 19))).toEqual([0.25, -0.5, 0.75]);
|
|
165
141
|
});
|
|
166
142
|
|
|
167
|
-
it('
|
|
143
|
+
it('writes temporal current/previous projection after the spot-light lanes', () => {
|
|
168
144
|
const { queue, uploads } = recordingQueue();
|
|
169
|
-
const acceptedCamera = [7, 8, 9] as const;
|
|
170
|
-
const temporal = { ...temporalView(), previousCameraPosition: acceptedCamera };
|
|
171
145
|
writeViewUbo(
|
|
172
146
|
queue,
|
|
173
147
|
{} as Buffer,
|
|
@@ -180,11 +154,16 @@ describe('temporal GPU payloads', () => {
|
|
|
180
154
|
},
|
|
181
155
|
{ point: [], spot: [] } as never,
|
|
182
156
|
[],
|
|
183
|
-
|
|
157
|
+
temporalView(),
|
|
184
158
|
);
|
|
185
159
|
|
|
186
160
|
const payload = new Float32Array(uploads[0]?.buffer ?? new ArrayBuffer(0));
|
|
187
|
-
expect(
|
|
161
|
+
expect(payload.length).toBe(240);
|
|
162
|
+
expect(payload[196]).toBeCloseTo(Math.sqrt(3));
|
|
163
|
+
expect(payload[212]).toBe(3);
|
|
164
|
+
expect(payload[228]).toBeCloseTo(0.1);
|
|
165
|
+
expect(payload[229]).toBe(100);
|
|
166
|
+
expect(payload[230]).toBe(0);
|
|
188
167
|
});
|
|
189
168
|
|
|
190
169
|
it('seeds previousWorld on the first frame and uses the submitted snapshot later', () => {
|
|
@@ -18,6 +18,8 @@ import type { DirectionalShadowQuality } from '../components/directional-shadow-
|
|
|
18
18
|
import type { EnvironmentGeneration } from '../environment/generation';
|
|
19
19
|
import type { EnvironmentLifecycle } from '../environment/lifecycle';
|
|
20
20
|
import type { GpuBuffer } from '../gpu-resource';
|
|
21
|
+
import type { InstanceCollectionId, InstanceResidency } from '../instances';
|
|
22
|
+
import type { IblBindingInspection } from '../mesh-material-bindings';
|
|
21
23
|
import type { StandardLightingInspection } from '../pipeline/standard-lighting/inspection';
|
|
22
24
|
import type { PointShadowInspection } from '../point-shadow-inspection';
|
|
23
25
|
import type { TemporalGpuState } from '../temporal/gpu';
|
|
@@ -51,6 +53,17 @@ export function worldEntityKey(worldId: number, entityKey: number): number {
|
|
|
51
53
|
return worldId * 4294967296 + entityKey; // 2^32 = 4294967296
|
|
52
54
|
}
|
|
53
55
|
|
|
56
|
+
/** Per-renderer projection identity, with entity keys for sprite/fold snapshots. */
|
|
57
|
+
export function instanceCollectionCacheKey(
|
|
58
|
+
worldId: number,
|
|
59
|
+
instance: { readonly cacheKey: number; readonly collectionId?: number },
|
|
60
|
+
): number {
|
|
61
|
+
// Keep collection entries in a disjoint numeric namespace from the shared
|
|
62
|
+
// legacy sprite/fold cache. Fold keys occupy -1..-(2^32), while ordinary
|
|
63
|
+
// world/entity keys are non-negative; this range starts below both.
|
|
64
|
+
return -(0x1_0000_0000 + worldEntityKey(worldId, instance.collectionId ?? instance.cacheKey));
|
|
65
|
+
}
|
|
66
|
+
|
|
54
67
|
/**
|
|
55
68
|
* Cross-frame cache entry for a material bind group whose source material and
|
|
56
69
|
* all resolved GPU resources are stable. The material snapshot identity is
|
|
@@ -138,6 +151,18 @@ export interface CurrentGraphTarget {
|
|
|
138
151
|
const textureIdentities = new WeakMap<object, number>();
|
|
139
152
|
let nextTextureIdentity = 1;
|
|
140
153
|
|
|
154
|
+
const opaqueResourceIdentities = new WeakMap<object, number>();
|
|
155
|
+
let nextOpaqueResourceIdentity = 1;
|
|
156
|
+
|
|
157
|
+
/** Stable detached identity for a renderer-owned opaque resource handle. */
|
|
158
|
+
export function getOpaqueResourceIdentity(resource: object): number {
|
|
159
|
+
const existing = opaqueResourceIdentities.get(resource);
|
|
160
|
+
if (existing !== undefined) return existing;
|
|
161
|
+
const identity = nextOpaqueResourceIdentity++;
|
|
162
|
+
opaqueResourceIdentities.set(resource, identity);
|
|
163
|
+
return identity;
|
|
164
|
+
}
|
|
165
|
+
|
|
141
166
|
/**
|
|
142
167
|
* Project an opaque RHI texture handle to a stable diagnostic identity.
|
|
143
168
|
* RHI handles intentionally expose no serializable fields; object identity is
|
|
@@ -276,8 +301,9 @@ export function makeZeroCameraFallbackSnapshot(): CameraSnapshot {
|
|
|
276
301
|
* Owned by the `createRenderSystem` closure; advanced once per
|
|
277
302
|
* `recordFrame` invocation. The `instanceBuffers` map holds the per-entity
|
|
278
303
|
* GPU storage buffers for Instances-bearing entities (cache key = the
|
|
279
|
-
* packed Entity u32
|
|
280
|
-
* are recreated when the `archVersion` bumps or
|
|
304
|
+
* renderer-owned collection id, with the packed Entity u32 retained only for
|
|
305
|
+
* legacy snapshots); entries are recreated when the `archVersion` bumps or
|
|
306
|
+
* `byteLength` changes.
|
|
281
307
|
*
|
|
282
308
|
* feat-20260518-pbr-direct-lighting-mvp M3 / w14 (AC-17 a): the
|
|
283
309
|
* `warnedZeroLightStandard` flag latches the first-frame warning that
|
|
@@ -289,6 +315,8 @@ export function makeZeroCameraFallbackSnapshot(): CameraSnapshot {
|
|
|
289
315
|
*/
|
|
290
316
|
export interface RenderFrameState {
|
|
291
317
|
frameNumber: number;
|
|
318
|
+
/** Final-submit Standard IBL binding-chain receipt for this frame. */
|
|
319
|
+
iblBindingInspection?: IblBindingInspection;
|
|
292
320
|
/** Demand for the frame-local Standard fallback MRT. */
|
|
293
321
|
reflectionFallbackDemand?: boolean;
|
|
294
322
|
/** Monotonic compiled-graph identity used by diagnostic readbacks. */
|
|
@@ -375,6 +403,10 @@ export interface RenderFrameState {
|
|
|
375
403
|
currentDirectionalShadowView: TextureView | null;
|
|
376
404
|
currentSpotShadowView: TextureView | null;
|
|
377
405
|
readonly instanceBuffers: Map<number, InstanceBufferCacheEntry>;
|
|
406
|
+
/** Renderer-owned collection owner used for record-stage residency facts. */
|
|
407
|
+
readonly instanceResidency?: Map<InstanceCollectionId, InstanceResidency>;
|
|
408
|
+
/** Stable buffers for renderer-owned collections split by device cap. */
|
|
409
|
+
readonly instanceBufferChunks?: Map<string, InstanceBufferCacheEntry>;
|
|
378
410
|
/** Per-object ProbeBlendRecord buffers; upload is one atomic 160B write. */
|
|
379
411
|
readonly probeBlendBuffers: Map<number, ProbeBlendBufferCacheEntry>;
|
|
380
412
|
/** One renderer-owned record array; each object selects its 256B-aligned lane. */
|
|
@@ -75,9 +75,19 @@ export function acquireSwapChainTarget(
|
|
|
75
75
|
|
|
76
76
|
let currentTextureResult = canvasContext.getCurrentTexture();
|
|
77
77
|
if (!currentTextureResult.ok) {
|
|
78
|
+
const configuredDevice = internals.resolveSurfaceDevice?.(internals.device);
|
|
79
|
+
if (configuredDevice !== undefined && !configuredDevice.ok) {
|
|
80
|
+
internals.errorRegistry.fire(configuredDevice.error);
|
|
81
|
+
internals.healthRegistry.fire({
|
|
82
|
+
reason: 'internal-fault',
|
|
83
|
+
detail: { message: 'surface device resolution failed; current frame skipped' },
|
|
84
|
+
recoverable: true,
|
|
85
|
+
});
|
|
86
|
+
return null;
|
|
87
|
+
}
|
|
78
88
|
const configured = configureSurface(
|
|
79
89
|
canvasContext,
|
|
80
|
-
internals.device,
|
|
90
|
+
configuredDevice?.value ?? internals.device,
|
|
81
91
|
pipelineState.format,
|
|
82
92
|
pipelineState.colorAttachmentFormat,
|
|
83
93
|
);
|
package/src/record/frame.ts
CHANGED
|
@@ -86,6 +86,7 @@ import {
|
|
|
86
86
|
type DispatchCounts,
|
|
87
87
|
type FrameObservationSource,
|
|
88
88
|
getTextureIdentity,
|
|
89
|
+
instanceCollectionCacheKey,
|
|
89
90
|
makeZeroCameraFallbackSnapshot,
|
|
90
91
|
type ReflectionFallbackReadbackRequest,
|
|
91
92
|
type RenderFrameState,
|
|
@@ -2484,7 +2485,7 @@ function prepareDirectionalShadowCache(
|
|
|
2484
2485
|
*
|
|
2485
2486
|
* @internal
|
|
2486
2487
|
*/
|
|
2487
|
-
function validateRenderables(
|
|
2488
|
+
export function validateRenderables(
|
|
2488
2489
|
internals: RenderSystemInternals,
|
|
2489
2490
|
world: World,
|
|
2490
2491
|
// feat-20260709-editor-world-partition ENGINE-fix-round2 (defect 2): the full
|
|
@@ -2714,8 +2715,12 @@ function prepareMorphMesh(
|
|
|
2714
2715
|
frameState.morphBuffers.delete(cacheKey);
|
|
2715
2716
|
return undefined;
|
|
2716
2717
|
}
|
|
2718
|
+
const buffer = new GpuBuffer(internals.device, created.value);
|
|
2719
|
+
internals.deviceScope._adopt('buffer', buffer, (owned) => {
|
|
2720
|
+
if (!owned.isDestroyed) owned.destroy();
|
|
2721
|
+
});
|
|
2717
2722
|
cached = {
|
|
2718
|
-
buffer
|
|
2723
|
+
buffer,
|
|
2719
2724
|
byteLength: vertices.byteLength,
|
|
2720
2725
|
};
|
|
2721
2726
|
frameState.morphBuffers.set(cacheKey, cached);
|
|
@@ -2989,8 +2994,14 @@ function cleanPerFrameCaches(
|
|
|
2989
2994
|
// composites matching the write-side keys of #1-#3 — cross-world false eviction
|
|
2990
2995
|
// is prevented because worldEntityKey(0, k) !== worldEntityKey(1, k).
|
|
2991
2996
|
const validatedEntityKeys = new Set<number>(retainedEntityKeys);
|
|
2997
|
+
const validatedInstanceKeys = new Set<number>(retainedEntityKeys);
|
|
2992
2998
|
for (const v of validated) {
|
|
2993
|
-
|
|
2999
|
+
const entityKey = worldEntityKey(v.source.worldId, v.source.entityKey);
|
|
3000
|
+
validatedEntityKeys.add(entityKey);
|
|
3001
|
+
validatedInstanceKeys.add(entityKey);
|
|
3002
|
+
if (v.source.instances !== undefined) {
|
|
3003
|
+
validatedInstanceKeys.add(instanceCollectionCacheKey(v.source.worldId, v.source.instances));
|
|
3004
|
+
}
|
|
2994
3005
|
}
|
|
2995
3006
|
|
|
2996
3007
|
// Clean per-entity material BG cache: drop outer-Map entries whose
|
|
@@ -3014,7 +3025,7 @@ function cleanPerFrameCaches(
|
|
|
3014
3025
|
// material-handle-based and cross-world collision is semantically
|
|
3015
3026
|
// correct (same material renders in same fold bucket).
|
|
3016
3027
|
for (const [key, entry] of frameState.instanceBuffers.entries()) {
|
|
3017
|
-
if (!
|
|
3028
|
+
if (!validatedInstanceKeys.has(key)) {
|
|
3018
3029
|
if (!entry.buffer.isDestroyed) {
|
|
3019
3030
|
const r = entry.buffer.destroy();
|
|
3020
3031
|
if (!r.ok) internals.errorRegistry.fire(r.error);
|
|
@@ -3023,6 +3034,28 @@ function cleanPerFrameCaches(
|
|
|
3023
3034
|
}
|
|
3024
3035
|
}
|
|
3025
3036
|
|
|
3037
|
+
if (frameState.instanceResidency !== undefined) {
|
|
3038
|
+
const liveCollections = new Set(validated.map((entry) => entry.source.instances?.collectionId));
|
|
3039
|
+
for (const id of frameState.instanceResidency.keys()) {
|
|
3040
|
+
if (!liveCollections.has(id)) frameState.instanceResidency.delete(id);
|
|
3041
|
+
}
|
|
3042
|
+
}
|
|
3043
|
+
|
|
3044
|
+
// Chunk keys are `${worldEntityKey}:${chunkStart}`. Keep the key opaque to
|
|
3045
|
+
// the authoring API, but retain the numeric owner prefix for eviction.
|
|
3046
|
+
if (frameState.instanceBufferChunks !== undefined) {
|
|
3047
|
+
for (const [key, entry] of frameState.instanceBufferChunks.entries()) {
|
|
3048
|
+
const separator = key.indexOf(':');
|
|
3049
|
+
const ownerKey = separator < 0 ? Number.NaN : Number(key.slice(0, separator));
|
|
3050
|
+
if (validatedInstanceKeys.has(ownerKey)) continue;
|
|
3051
|
+
if (!entry.buffer.isDestroyed) {
|
|
3052
|
+
const r = entry.buffer.destroy();
|
|
3053
|
+
if (!r.ok) internals.errorRegistry.fire(r.error);
|
|
3054
|
+
}
|
|
3055
|
+
frameState.instanceBufferChunks.delete(key);
|
|
3056
|
+
}
|
|
3057
|
+
}
|
|
3058
|
+
|
|
3026
3059
|
if (frameState.morphBuffers !== undefined) {
|
|
3027
3060
|
for (const [key, entry] of frameState.morphBuffers.entries()) {
|
|
3028
3061
|
if (validatedEntityKeys.has(key)) continue;
|
package/src/record/helpers.ts
CHANGED