@forgeax/engine-render 0.1.24 → 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 +100 -1
- package/dist/assembly/factory.d.ts +1 -1
- package/dist/assembly/factory.d.ts.map +1 -1
- 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 +20 -0
- package/dist/assembly/material-shader-policy.d.ts.map +1 -1
- package/dist/assembly/webgpu-ready.d.ts.map +1 -1
- package/dist/assembly/webgpu-renderer.d.ts +1 -1
- package/dist/assembly/webgpu-renderer.d.ts.map +1 -1
- 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-Q752SHI5.mjs → chunk-ADHHVYLW.mjs} +3 -3
- package/dist/chunk-ADHHVYLW.mjs.map +1 -0
- package/dist/{chunk-TFH5I7JJ.mjs → chunk-E34VL5VI.mjs} +3 -3
- package/dist/{chunk-TFH5I7JJ.mjs.map → chunk-E34VL5VI.mjs.map} +1 -1
- package/dist/{chunk-KZFTK6DO.mjs → chunk-HKXTW355.mjs} +7 -4
- package/dist/chunk-HKXTW355.mjs.map +1 -0
- package/dist/{chunk-YKB5DQV7.mjs → chunk-JSEDTZYS.mjs} +87 -19
- package/dist/chunk-JSEDTZYS.mjs.map +1 -0
- package/dist/{chunk-UQYS7FRM.mjs → chunk-KM2NOX2I.mjs} +4 -4
- package/dist/{chunk-UQYS7FRM.mjs.map → chunk-KM2NOX2I.mjs.map} +1 -1
- package/dist/{chunk-Z3YYH2MB.mjs → chunk-N3RT2EUR.mjs} +94 -41
- package/dist/chunk-N3RT2EUR.mjs.map +1 -0
- package/dist/{chunk-YRUYGA4A.mjs → chunk-TCLDX7SZ.mjs} +559 -138
- package/dist/chunk-TCLDX7SZ.mjs.map +1 -0
- package/dist/{chunk-RR5L4SRS.mjs → chunk-ZZ4YQ474.mjs} +2 -2
- package/dist/{chunk-RR5L4SRS.mjs.map → chunk-ZZ4YQ474.mjs.map} +1 -1
- package/dist/components/instances.d.ts +13 -31
- package/dist/components/instances.d.ts.map +1 -1
- package/dist/construct-renderer.mjs +865 -142
- package/dist/construct-renderer.mjs.map +1 -1
- package/dist/gpu-driven/production-raster.d.ts +6 -1
- package/dist/gpu-driven/production-raster.d.ts.map +1 -1
- package/dist/gpu-scene.d.ts +4 -0
- package/dist/gpu-scene.d.ts.map +1 -1
- package/dist/index.d.ts +1 -0
- 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 +5 -5
- package/dist/materials.d.ts +63 -2
- package/dist/materials.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/record/frame-snapshot.d.ts +13 -2
- package/dist/record/frame-snapshot.d.ts.map +1 -1
- package/dist/record/frame.d.ts.map +1 -1
- package/dist/record/main-pass-geometry.d.ts +22 -3
- package/dist/record/main-pass-geometry.d.ts.map +1 -1
- package/dist/record/render-context.d.ts +2 -1
- 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/recovery/render-system-candidate.d.ts +1 -1
- package/dist/recovery/render-system-candidate.d.ts.map +1 -1
- package/dist/render-contract.d.ts +4 -0
- package/dist/render-contract.d.ts.map +1 -1
- package/dist/render-system-extract-tail.d.ts +4 -0
- package/dist/render-system-extract-tail.d.ts.map +1 -1
- package/dist/render-system-extract.d.ts +25 -1
- package/dist/render-system-extract.d.ts.map +1 -1
- package/dist/render-system.d.ts +4 -1
- 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 +12 -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/index.mjs +5 -5
- package/package.json +20 -20
- package/src/__tests__/gpu-scene.unit.test.ts +38 -2
- 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 +5 -13
- 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-surface-authoring.test-d.ts +62 -0
- package/src/__tests__/materials-transmission-validation.unit.test.ts +24 -0
- package/src/__tests__/mesh-buffer-usage-surface.unit.test.ts +0 -4
- package/src/__tests__/renderer-factory-material-contract.unit.test.ts +42 -0
- package/src/__tests__/skin-motion-regression.unit.test.ts +33 -0
- package/src/__tests__/skinned-shadow-caster.test.ts +30 -2
- 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__/volumetric-fog-budget-recovery.integration.test.ts +1 -1
- package/src/assembly/factory.ts +2 -0
- 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/surface-projection.ts +90 -0
- package/src/assembly/material-shader-policy.ts +88 -10
- package/src/assembly/recovery/renderer-recover.ts +1 -1
- package/src/assembly/webgpu-ready.ts +3 -16
- package/src/assembly/webgpu-renderer.ts +90 -158
- package/src/assembly/webgpu-vertex-layouts.ts +132 -0
- package/src/assets/asset-decoders.ts +27 -4
- package/src/components/instances.ts +14 -197
- package/src/gpu-driven/production-raster.ts +34 -1
- package/src/gpu-scene.ts +84 -29
- package/src/index.ts +1 -0
- package/src/instance-buffer-cache.ts +14 -1
- package/src/instances.ts +288 -0
- package/src/materials.ts +107 -12
- package/src/pipeline-builder.ts +14 -10
- package/src/pipeline-spec.ts +6 -14
- package/src/record/frame-snapshot.ts +19 -2
- package/src/record/frame.ts +31 -2
- package/src/record/main-pass-geometry.ts +498 -59
- package/src/record/main-pass-sprite-draws.ts +1 -1
- package/src/record/render-context.ts +4 -0
- package/src/record/shadow-pass.ts +46 -99
- package/src/recovery/render-system-candidate.ts +41 -4
- package/src/render-contract.ts +4 -0
- package/src/render-system-extract-tail.ts +107 -51
- package/src/render-system-extract.ts +53 -26
- package/src/render-system.ts +40 -5
- package/src/scene/render-scene-types.ts +2 -0
- package/src/scene/render-scene.ts +579 -36
- package/src/systems/skin-palette-allocator.ts +129 -7
- package/src/transmission/__tests__/surface-compatibility.integration.test.ts +32 -0
- package/dist/chunk-KZFTK6DO.mjs.map +0 -1
- package/dist/chunk-Q752SHI5.mjs.map +0 -1
- package/dist/chunk-YKB5DQV7.mjs.map +0 -1
- package/dist/chunk-YRUYGA4A.mjs.map +0 -1
- package/dist/chunk-Z3YYH2MB.mjs.map +0 -1
|
@@ -75,27 +75,9 @@
|
|
|
75
75
|
// `MeshFilter.assetHandle` dangling path
|
|
76
76
|
// (charter proposition 5; AC-11).
|
|
77
77
|
//
|
|
78
|
-
//
|
|
79
|
-
//
|
|
80
|
-
//
|
|
81
|
-
// `InstancedBufferAsset` POD) is gone. Per-entity instance transforms now
|
|
82
|
-
// live inside the ECS `Instances { transforms: 'array<f32>' }` column;
|
|
83
|
-
// extract materialises a `Float32Array` snapshot per Instances-bearing
|
|
84
|
-
// entity (via `world.get(e, Instances).transforms`) so the record stage
|
|
85
|
-
// can upload to a per-entity GPU storage buffer cached by entity packed
|
|
86
|
-
// u32.
|
|
87
|
-
//
|
|
88
|
-
// feat-20260515-buffer-array-vocab-collapse M3 / w15: the component-level
|
|
89
|
-
// `arrayStride` hook on `Instances.transforms` was retired (decision section
|
|
90
|
-
// 2.3 stride responsibility migration -- AI users gate at the set / push
|
|
91
|
-
// call sites + RenderSystem extract entry holds a defensive fail-fast).
|
|
92
|
-
// The extract entry checks `transforms.length % 16 === 0` directly after
|
|
93
|
-
// the `world.get(entity, Instances)` snapshot is taken; violations route
|
|
94
|
-
// `InstanceTransformsStrideMismatchError`
|
|
95
|
-
// (`code: 'instance-transforms-stride-mismatch'`,
|
|
96
|
-
// `detail: { actualLength, expectedStride: 16 }`) through the World
|
|
97
|
-
// Layer-3 ErrorHandler and the renderable is skipped. The record stage
|
|
98
|
-
// trusts the invariant and does not re-check.
|
|
78
|
+
// World owns explicit Instances transforms. Extraction makes a detached
|
|
79
|
+
// per-renderer projection; GPU residents acknowledge complete snapshots only
|
|
80
|
+
// after successful uploads. Reading a snapshot never changes author state.
|
|
99
81
|
|
|
100
82
|
import type { AssetRegistry } from '@forgeax/engine-assets-runtime';
|
|
101
83
|
import {
|
|
@@ -166,6 +148,7 @@ import type {
|
|
|
166
148
|
RenderFeatureHiddenEntityReport,
|
|
167
149
|
RenderFeatureWorldVisibilitySnapshot,
|
|
168
150
|
} from './features/types';
|
|
151
|
+
import type { InstanceCollectionId, InstanceProjectionStore } from './instances';
|
|
169
152
|
import type {
|
|
170
153
|
MeshMaterialBindingDiagnostic,
|
|
171
154
|
MeshMaterialBindingSource,
|
|
@@ -696,6 +679,8 @@ export interface RenderableSnapshot {
|
|
|
696
679
|
readonly materialBindingSources: readonly MeshMaterialBindingSource[];
|
|
697
680
|
/** Active structured override diagnostics for this renderable. */
|
|
698
681
|
readonly materialBindingDiagnostics?: readonly MeshMaterialBindingDiagnostic[];
|
|
682
|
+
/** Effective authored visibility retained by the persistent scene owner. */
|
|
683
|
+
readonly authorVisible?: boolean;
|
|
699
684
|
/**
|
|
700
685
|
* feat-20260708-composited-multi-world-rendering M1 / D-1: the worldId
|
|
701
686
|
* of the world this renderable was extracted from. Defaults to 0 in
|
|
@@ -761,6 +746,8 @@ export interface RenderableSnapshot {
|
|
|
761
746
|
* Absent (`undefined`) means the entity is not skinned.
|
|
762
747
|
*/
|
|
763
748
|
readonly skin?: SkinPaletteSlice;
|
|
749
|
+
/** Joint entity identities used by the persistent skin dependency index. */
|
|
750
|
+
readonly skinJointEntities?: readonly number[];
|
|
764
751
|
/**
|
|
765
752
|
* ECS-owned morph weights. Presence selects the Standard Pipeline CPU
|
|
766
753
|
* specialized deformation lane; the asset remains the source of target
|
|
@@ -822,10 +809,14 @@ export interface GpuDrivenDrawSnapshot {
|
|
|
822
809
|
}
|
|
823
810
|
|
|
824
811
|
export interface InstancesSnapshot {
|
|
812
|
+
/** Renderer-owned collection identity. */
|
|
813
|
+
readonly collectionId?: InstanceCollectionId;
|
|
825
814
|
/** Packed column-major mat4 transforms (16 f32 per instance). */
|
|
826
815
|
readonly transforms: Float32Array;
|
|
827
816
|
/** Number of instances (transforms.length / 16). */
|
|
828
817
|
readonly instanceCount: number;
|
|
818
|
+
/** Collection revision captured by this detached frame snapshot. */
|
|
819
|
+
readonly revision?: number;
|
|
829
820
|
/** Stable per-entity GPU buffer cache key (the packed Entity u32). */
|
|
830
821
|
readonly cacheKey: number;
|
|
831
822
|
/**
|
|
@@ -1134,6 +1125,7 @@ export function appendMaterialDispatchEntries(
|
|
|
1134
1125
|
layer: number,
|
|
1135
1126
|
paramSnapshot: Readonly<Record<string, number | number[] | string>> | undefined,
|
|
1136
1127
|
passIndexOffset = 0,
|
|
1128
|
+
materialShaderIdOverride?: string,
|
|
1137
1129
|
): void {
|
|
1138
1130
|
const matchedPasses = selectPasses(passes, {});
|
|
1139
1131
|
for (let pIdx = 0; pIdx < matchedPasses.length; pIdx++) {
|
|
@@ -1144,6 +1136,11 @@ export function appendMaterialDispatchEntries(
|
|
|
1144
1136
|
readonly queue?: number;
|
|
1145
1137
|
readonly stencilReference?: number;
|
|
1146
1138
|
};
|
|
1139
|
+
const authoredShaderId = runtimeMaterialShaderId(pass.program.module, pass.name);
|
|
1140
|
+
const dispatchShaderId =
|
|
1141
|
+
authoredShaderId === 'forgeax::default-shadow-caster'
|
|
1142
|
+
? authoredShaderId
|
|
1143
|
+
: (materialShaderIdOverride ?? authoredShaderId);
|
|
1147
1144
|
pendingDispatch.push({
|
|
1148
1145
|
entityIndex: entity,
|
|
1149
1146
|
materialHandle,
|
|
@@ -1158,7 +1155,14 @@ export function appendMaterialDispatchEntries(
|
|
|
1158
1155
|
defines: undefined,
|
|
1159
1156
|
vertexEntry: pass.program.vertexEntry,
|
|
1160
1157
|
fragmentEntry: pass.program.fragmentEntry,
|
|
1161
|
-
|
|
1158
|
+
// A cooked Standard publication supplies one specialization key for its
|
|
1159
|
+
// forward/deferred artifact, but its ShadowCaster pass still owns the
|
|
1160
|
+
// engine depth-only shader. Keep the pass-local canonical identity so a
|
|
1161
|
+
// specialized Standard source (which only declares fs_main/fs_gbuffer)
|
|
1162
|
+
// is never asked to build an fs_shadow pipeline. Authored non-Standard
|
|
1163
|
+
// ShadowCaster modules retain the publication override and continue to
|
|
1164
|
+
// use their producer-owned source.
|
|
1165
|
+
materialShaderId: dispatchShaderId,
|
|
1162
1166
|
paramSnapshot,
|
|
1163
1167
|
...(passState.stencilReference !== undefined && {
|
|
1164
1168
|
stencilReference: passState.stencilReference,
|
|
@@ -1410,6 +1414,20 @@ export function runtimeMaterialShaderId(
|
|
|
1410
1414
|
}
|
|
1411
1415
|
}
|
|
1412
1416
|
|
|
1417
|
+
/**
|
|
1418
|
+
* Select the runtime identity for one resolved material. A cooked publication
|
|
1419
|
+
* owns the composed material artifact identity; the authored pass module is
|
|
1420
|
+
* the built-in fallback used before that publication is ready.
|
|
1421
|
+
*/
|
|
1422
|
+
export function runtimeMaterialShaderIdForMaterial(
|
|
1423
|
+
material: MaterialAsset,
|
|
1424
|
+
passes: readonly MaterialPass[],
|
|
1425
|
+
assets: AssetRegistry,
|
|
1426
|
+
): string | undefined {
|
|
1427
|
+
const authored = runtimeMaterialShaderId(passes[0]?.program.module, passes[0]?.name);
|
|
1428
|
+
return assets.getMaterialProjectionForPayload(material)?.specializationKey ?? authored;
|
|
1429
|
+
}
|
|
1430
|
+
|
|
1413
1431
|
export function pipelineRenderState(
|
|
1414
1432
|
renderState:
|
|
1415
1433
|
| (MaterialRenderState & {
|
|
@@ -1934,10 +1952,7 @@ export function resolveMaterialSnapshot(
|
|
|
1934
1952
|
if (!resolvedResult.ok) return defaultMaterialSnapshot(handleRaw);
|
|
1935
1953
|
const resolved = resolvedResult.value;
|
|
1936
1954
|
const allPasses = resolved.passes;
|
|
1937
|
-
const firstPassShader =
|
|
1938
|
-
allPasses.length > 0
|
|
1939
|
-
? runtimeMaterialShaderId(allPasses[0]?.program.module, allPasses[0]?.name)
|
|
1940
|
-
: undefined;
|
|
1955
|
+
const firstPassShader = runtimeMaterialShaderIdForMaterial(asset, allPasses, assetsRef);
|
|
1941
1956
|
const pv = materialValuesToLinearRuntime(
|
|
1942
1957
|
resolved.values,
|
|
1943
1958
|
materialColorParameterSchema(resolved.parameters ?? [], firstPassShader, assetsRef),
|
|
@@ -2542,11 +2557,17 @@ export interface PreparedExtractContext {
|
|
|
2542
2557
|
readonly cull: 'self' | 'none' | 'external';
|
|
2543
2558
|
readonly cullCameras: readonly CameraSnapshot[] | undefined;
|
|
2544
2559
|
readonly renderables: 'full' | 'none';
|
|
2560
|
+
/** Restrict renderable extraction to these entities while still reading frame resources. */
|
|
2561
|
+
readonly renderableEntities: ReadonlySet<number> | undefined;
|
|
2562
|
+
/** Keep authored-hidden renderables in the persistent source projection. */
|
|
2563
|
+
readonly retainHidden: boolean;
|
|
2545
2564
|
readonly visibility: VisibilitySnapshot;
|
|
2546
2565
|
/** Producer-owned artifact lookup; extraction only, never record-time asset reads. */
|
|
2547
2566
|
readonly getMaterialShaderArtifact:
|
|
2548
2567
|
| ((materialShaderId: string) => MaterialShaderArtifact | undefined)
|
|
2549
2568
|
| undefined;
|
|
2569
|
+
/** Renderer-owned canonical source for explicit large instance collections. */
|
|
2570
|
+
readonly instanceCollections: InstanceProjectionStore | undefined;
|
|
2550
2571
|
}
|
|
2551
2572
|
|
|
2552
2573
|
const ALL_VISIBLE: VisibilitySnapshot = {
|
|
@@ -2734,9 +2755,12 @@ export function prepareExtractContext(
|
|
|
2734
2755
|
readonly cull?: 'self' | 'none' | 'external';
|
|
2735
2756
|
readonly cullCameras?: readonly CameraSnapshot[];
|
|
2736
2757
|
readonly renderables?: 'full' | 'none';
|
|
2758
|
+
readonly renderableEntities?: ReadonlySet<number>;
|
|
2759
|
+
readonly retainHidden?: boolean;
|
|
2737
2760
|
readonly getMaterialShaderArtifact?: (
|
|
2738
2761
|
materialShaderId: string,
|
|
2739
2762
|
) => MaterialShaderArtifact | undefined;
|
|
2763
|
+
readonly instanceCollections?: InstanceProjectionStore;
|
|
2740
2764
|
} = {},
|
|
2741
2765
|
): PreparedExtractContext {
|
|
2742
2766
|
const renderables = options.renderables ?? 'full';
|
|
@@ -2748,8 +2772,11 @@ export function prepareExtractContext(
|
|
|
2748
2772
|
cull: options.cull ?? 'self',
|
|
2749
2773
|
cullCameras: options.cullCameras,
|
|
2750
2774
|
renderables,
|
|
2775
|
+
renderableEntities: options.renderableEntities,
|
|
2776
|
+
retainHidden: options.retainHidden ?? false,
|
|
2751
2777
|
visibility: renderables === 'none' ? ALL_VISIBLE : resolveVisibility(world),
|
|
2752
2778
|
getMaterialShaderArtifact: options.getMaterialShaderArtifact,
|
|
2779
|
+
instanceCollections: options.instanceCollections,
|
|
2753
2780
|
};
|
|
2754
2781
|
}
|
|
2755
2782
|
|
package/src/render-system.ts
CHANGED
|
@@ -118,7 +118,13 @@ import type { EnvironmentInspection } from './environment/inspection';
|
|
|
118
118
|
import { GPU_BUFFER_USAGE_COPY_DST, GPU_BUFFER_USAGE_UNIFORM } from './gpu-usage';
|
|
119
119
|
import { resetHdrpBuffers } from './hdrp-buffers';
|
|
120
120
|
import { assembleMaterialWithSkylightEntries } from './ibl/skylight-bind-group';
|
|
121
|
-
import {
|
|
121
|
+
import {
|
|
122
|
+
disposeInstanceBufferChunks,
|
|
123
|
+
disposeInstanceBuffers,
|
|
124
|
+
disposeTransientInstanceBuffers,
|
|
125
|
+
} from './instance-buffer-cache';
|
|
126
|
+
import type { InstanceCollectionInspection } from './instances';
|
|
127
|
+
import { InstanceProjectionStore } from './instances';
|
|
122
128
|
import {
|
|
123
129
|
type MeshMaterialBindingObservation,
|
|
124
130
|
type MeshMaterialBindingPreparationFailure,
|
|
@@ -182,7 +188,11 @@ import type {
|
|
|
182
188
|
RenderableSnapshot,
|
|
183
189
|
} from './render-system-extract';
|
|
184
190
|
import { extractFrames } from './render-system-extract';
|
|
185
|
-
import {
|
|
191
|
+
import {
|
|
192
|
+
type PersistentGpuDrivenCandidate,
|
|
193
|
+
type PersistentRenderCandidateRequest,
|
|
194
|
+
PersistentRenderScene,
|
|
195
|
+
} from './scene/render-scene';
|
|
186
196
|
import { inspectLodOcclusion } from './scene/visibility/inspection';
|
|
187
197
|
import { resolveSsaoParameters } from './ssao-config';
|
|
188
198
|
import { projectSsrDependencies, resolveSsrAdmissionGeneration } from './ssr/admission';
|
|
@@ -660,7 +670,7 @@ export interface RenderSystem {
|
|
|
660
670
|
/** Prepare a detached graph candidate without entering the frame record path. */
|
|
661
671
|
prepareRecoveryGraphCandidate(
|
|
662
672
|
runtime: RecoveryGraphCandidateRuntime,
|
|
663
|
-
): RecoveryGraphCandidatePreparation
|
|
673
|
+
): Promise<RecoveryGraphCandidatePreparation>;
|
|
664
674
|
/** Finish and submit detached candidate setup, never a frame receipt. */
|
|
665
675
|
submitCandidateSetup(
|
|
666
676
|
candidate: RecoveryGraphCandidate,
|
|
@@ -686,6 +696,8 @@ export interface RenderSystem {
|
|
|
686
696
|
readonly pipelineDispatchCounts: {
|
|
687
697
|
readonly unlit: number;
|
|
688
698
|
};
|
|
699
|
+
/** Detached residency and upload facts for explicit instance collections. */
|
|
700
|
+
readonly instanceCollectionsInspection: readonly InstanceCollectionInspection[];
|
|
689
701
|
/**
|
|
690
702
|
* feat-20260528-frustum-culling M5 / w14: per-frame frustum-culling counters.
|
|
691
703
|
* Updated by `draw([world], { cameraOwner: 0, resourceOwner: 0 })` on every call from the Extract stage.
|
|
@@ -1071,6 +1083,7 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
1071
1083
|
let preparedWorlds: readonly World[] = [];
|
|
1072
1084
|
let latestCamera: CameraSnapshot | undefined;
|
|
1073
1085
|
const pointsLinesOwner = new StandardPointsLinesOwner(internals);
|
|
1086
|
+
const instanceCollections = new InstanceProjectionStore();
|
|
1074
1087
|
const reflectionProbeOwner = new ReflectionProbeRecordOwner(internals);
|
|
1075
1088
|
let ssrFormatReceipt: import('@forgeax/engine-rhi').RhiTextureFormatCapabilityReceipt | undefined;
|
|
1076
1089
|
let ssrFormatProbeGeneration = -1;
|
|
@@ -1112,6 +1125,8 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
1112
1125
|
onSharedRefMutation: (worldId, handle) => {
|
|
1113
1126
|
internals.gpuStore.invalidateMesh(handle, preparedWorlds[worldId] ?? worldId);
|
|
1114
1127
|
},
|
|
1128
|
+
instanceCollections,
|
|
1129
|
+
getSkinPaletteAllocator: () => internals.getPipelineState()?.skinPaletteAllocator ?? null,
|
|
1115
1130
|
});
|
|
1116
1131
|
let environmentLifecycle = new EnvironmentLifecycle(internals.deviceScope);
|
|
1117
1132
|
const transmissionAdmission = new TransmissionCandidateAdmission();
|
|
@@ -1362,6 +1377,8 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
1362
1377
|
currentDirectionalShadowView: null,
|
|
1363
1378
|
currentSpotShadowView: null,
|
|
1364
1379
|
instanceBuffers: new Map(),
|
|
1380
|
+
instanceResidency: new Map(),
|
|
1381
|
+
instanceBufferChunks: new Map(),
|
|
1365
1382
|
probeBlendBuffers: new Map(),
|
|
1366
1383
|
probeBlendRecordBufferCapacity: 0,
|
|
1367
1384
|
morphBuffers: new Map(),
|
|
@@ -2294,6 +2311,12 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
2294
2311
|
createPreparedResolverCaches,
|
|
2295
2312
|
});
|
|
2296
2313
|
return {
|
|
2314
|
+
get instanceCollectionsInspection(): readonly InstanceCollectionInspection[] {
|
|
2315
|
+
return instanceCollections._inspections(
|
|
2316
|
+
frameState.instanceResidency,
|
|
2317
|
+
frameState.frameNumber - 1,
|
|
2318
|
+
);
|
|
2319
|
+
},
|
|
2297
2320
|
releaseProfilerCatalog(): void {
|
|
2298
2321
|
releaseProfilerCatalog?.();
|
|
2299
2322
|
releaseProfilerCatalog = undefined;
|
|
@@ -2555,7 +2578,7 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
2555
2578
|
compositionWorlds,
|
|
2556
2579
|
{ cameraOwner, resourceOwner },
|
|
2557
2580
|
internals.assets.catalogEpoch,
|
|
2558
|
-
(
|
|
2581
|
+
(request: PersistentRenderCandidateRequest) =>
|
|
2559
2582
|
extractFrames(
|
|
2560
2583
|
compositionWorlds,
|
|
2561
2584
|
{ cameraOwner, resourceOwner },
|
|
@@ -2564,7 +2587,12 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
2564
2587
|
persistentRenderScene.materialSnapshotCacheStore(),
|
|
2565
2588
|
{
|
|
2566
2589
|
cull: 'none',
|
|
2567
|
-
renderables,
|
|
2590
|
+
renderables: request === 'none' ? 'none' : 'full',
|
|
2591
|
+
...(request === 'none' || request === 'full'
|
|
2592
|
+
? {}
|
|
2593
|
+
: { renderableEntitiesByWorld: request.entitiesByWorld }),
|
|
2594
|
+
retainHidden: true,
|
|
2595
|
+
instanceCollections,
|
|
2568
2596
|
...(internals.getMaterialShaderArtifact === undefined
|
|
2569
2597
|
? {}
|
|
2570
2598
|
: { getMaterialShaderArtifact: internals.getMaterialShaderArtifact }),
|
|
@@ -3496,6 +3524,7 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
3496
3524
|
(internals as TimingSessionHost).gpuPassTimingBeginReason = undefined;
|
|
3497
3525
|
pointsLinesOwner.dispose();
|
|
3498
3526
|
persistentRenderScene.dispose();
|
|
3527
|
+
instanceCollections.dispose();
|
|
3499
3528
|
gpuDrivenProduction.dispose();
|
|
3500
3529
|
occlusionRuntime?.dispose();
|
|
3501
3530
|
disposeFeatureGpuWork();
|
|
@@ -3565,6 +3594,10 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
3565
3594
|
// so destroy failures fire structured errors (unified per-frame +
|
|
3566
3595
|
// dispose error strategy).
|
|
3567
3596
|
disposeInstanceBuffers(frameState.instanceBuffers, internals.errorRegistry);
|
|
3597
|
+
frameState.instanceResidency?.clear();
|
|
3598
|
+
if (frameState.instanceBufferChunks !== undefined) {
|
|
3599
|
+
disposeInstanceBufferChunks(frameState.instanceBufferChunks, internals.errorRegistry);
|
|
3600
|
+
}
|
|
3568
3601
|
disposeTransientInstanceBuffers(frameState.transientInstanceBuffers, internals.errorRegistry);
|
|
3569
3602
|
if (frameState.probeBlendRecordBuffer !== undefined) {
|
|
3570
3603
|
if (!frameState.probeBlendRecordBuffer.isDestroyed) {
|
|
@@ -3706,6 +3739,8 @@ export function createRenderSystem(internals: RenderSystemInternals): RenderSyst
|
|
|
3706
3739
|
}
|
|
3707
3740
|
frameState.retiredCompiledFrameGraphs.clear();
|
|
3708
3741
|
frameState.instanceBuffers.clear();
|
|
3742
|
+
frameState.instanceBufferChunks?.clear();
|
|
3743
|
+
frameState.instanceResidency?.clear();
|
|
3709
3744
|
delete frameState.probeBlendRecordBuffer;
|
|
3710
3745
|
frameState.probeBlendRecordBufferCapacity = 0;
|
|
3711
3746
|
frameState.probeBlendBuffers.clear();
|
|
@@ -36,6 +36,8 @@ export interface RenderSceneApplyResult {
|
|
|
36
36
|
readonly ignoredLateUpdates: number;
|
|
37
37
|
readonly createdSlots: readonly RenderSceneSlot[];
|
|
38
38
|
readonly updatedSlots: readonly RenderSceneSlot[];
|
|
39
|
+
/** Full retained-snapshot updates; transform spans stay in updatedSlots only. */
|
|
40
|
+
readonly contentUpdatedSlots?: readonly RenderSceneSlot[];
|
|
39
41
|
readonly removedSlots: readonly RenderSceneRecord[];
|
|
40
42
|
readonly recreatedSlots: readonly RenderSceneSlot[];
|
|
41
43
|
readonly resynced: number;
|