@forgeax/engine-render 0.1.23 → 0.1.24
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 +131 -9
- 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-shader-policy.d.ts +168 -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/authoring.mjs +1 -1
- package/dist/{chunk-4L3P6DT5.mjs → chunk-GE3SDD72.mjs} +37 -5
- package/dist/chunk-GE3SDD72.mjs.map +1 -0
- package/dist/{chunk-HZUPSYW7.mjs → chunk-KZFTK6DO.mjs} +102 -15
- package/dist/chunk-KZFTK6DO.mjs.map +1 -0
- package/dist/{chunk-FF7K3FSO.mjs → chunk-Q752SHI5.mjs} +89 -89
- package/dist/{chunk-FF7K3FSO.mjs.map → chunk-Q752SHI5.mjs.map} +1 -1
- package/dist/{chunk-QODA5UKU.mjs → chunk-RR5L4SRS.mjs} +2 -2
- package/dist/chunk-RR5L4SRS.mjs.map +1 -0
- package/dist/{chunk-YALPS44A.mjs → chunk-TFH5I7JJ.mjs} +47 -47
- package/dist/chunk-TFH5I7JJ.mjs.map +1 -0
- package/dist/{chunk-FBC4R44J.mjs → chunk-UQYS7FRM.mjs} +57 -57
- package/dist/chunk-UQYS7FRM.mjs.map +1 -0
- package/dist/{chunk-4NPUASZR.mjs → chunk-YKB5DQV7.mjs} +161 -19
- package/dist/chunk-YKB5DQV7.mjs.map +1 -0
- package/dist/{chunk-ZUWKAZ2I.mjs → chunk-YRUYGA4A.mjs} +615 -237
- package/dist/chunk-YRUYGA4A.mjs.map +1 -0
- package/dist/{chunk-DIYW3M5D.mjs → chunk-Z3YYH2MB.mjs} +2210 -2213
- package/dist/chunk-Z3YYH2MB.mjs.map +1 -0
- package/dist/construct-renderer.mjs +19841 -16190
- 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 +28 -0
- package/dist/gpu-driven/production-raster.d.ts.map +1 -1
- package/dist/gpu-scene.d.ts +1 -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 +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.mjs +6 -6
- 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 +34 -10
- 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/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 +5 -0
- package/dist/record/frame-snapshot.d.ts.map +1 -1
- package/dist/record/frame-targets.d.ts.map +1 -1
- package/dist/record/frame.d.ts +14 -2
- package/dist/record/frame.d.ts.map +1 -1
- package/dist/record/main-pass-geometry.d.ts +14 -1
- 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 +26 -4
- package/dist/record/render-context.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 +64 -7
- package/dist/render-contract.d.ts.map +1 -1
- package/dist/render-system-extract-tail.d.ts +12 -0
- package/dist/render-system-extract-tail.d.ts.map +1 -0
- package/dist/render-system-extract.d.ts +156 -22
- package/dist/render-system-extract.d.ts.map +1 -1
- package/dist/render-system.d.ts +128 -4
- package/dist/render-system.d.ts.map +1 -1
- package/dist/scene/render-scene.d.ts +19 -0
- package/dist/scene/render-scene.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__/ibl/face-uniforms.unit.test.ts +2 -0
- package/src/__tests__/ibl-residency-publication.unit.test.ts +113 -0
- package/src/__tests__/material-contract-inventory.unit.test.ts +24 -9
- package/src/__tests__/material-cooked-projection.unit.test.ts +19 -1
- 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__/materials-standard-contract.unit.test.ts +104 -0
- package/src/__tests__/mesh-buffer-usage-surface.unit.test.ts +1 -1
- 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 +85 -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__/standard-layer-projection.unit.test.ts +23 -0
- package/src/__tests__/transmission-prewarm.unit.test.ts +95 -85
- 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 +81 -10088
- package/src/assembly/material/assembly.ts +18 -2
- package/src/assembly/material/standard-layer-projection.ts +16 -0
- package/src/assembly/material-shader-policy.ts +854 -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 +4079 -0
- package/src/assembly/webgpu-renderer.ts +4095 -0
- package/src/components/camera.ts +1 -1
- 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 +97 -2
- package/src/gpu-scene.ts +3 -2
- package/src/ibl/IblPipelineCache.ts +134 -50
- package/src/ibl/skylight-bind-group.ts +26 -0
- package/src/index.ts +9 -1
- package/src/light-buffer-layout.ts +3 -0
- package/src/materials.ts +262 -45
- package/src/mesh-material-bindings.ts +59 -0
- package/src/occlusion-proxy.ts +64 -0
- package/src/pbr-pipeline.ts +139 -15
- 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 +15 -0
- package/src/record/frame-targets.ts +11 -1
- package/src/record/frame.ts +6 -2
- package/src/record/helpers.ts +1 -1
- package/src/record/main-pass-geometry.ts +230 -5
- package/src/record/main-pass-material.ts +316 -209
- package/src/record/main-pass-sprite-draws.ts +6 -7
- 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 +35 -4
- package/src/record/typed-frame-graph.ts +45 -1
- package/src/record/view-ubo.ts +3 -3
- package/src/recovery/render-system-candidate.ts +839 -0
- package/src/render-contract.ts +65 -7
- package/src/render-system-extract-tail.ts +2983 -0
- package/src/render-system-extract.ts +124 -2977
- package/src/render-system.ts +868 -659
- package/src/scene/render-scene.ts +124 -1
- 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/dist/chunk-4L3P6DT5.mjs.map +0 -1
- 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-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
package/src/features/host.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { EntityHandle } from '@forgeax/engine-ecs';
|
|
2
2
|
import type { RhiCaps, TextureFormat } from '@forgeax/engine-rhi';
|
|
3
3
|
import { err, ok, type Result } from '@forgeax/engine-types';
|
|
4
|
+
import type { DeviceScope, LifecycleResourceSpec } from '../device/device-scope';
|
|
4
5
|
import {
|
|
5
6
|
type RenderError,
|
|
6
7
|
RenderFeatureCapabilityMissingError,
|
|
@@ -175,6 +176,7 @@ export interface RenderFeatureHost {
|
|
|
175
176
|
batches: readonly RenderFeaturePreparedResourceBatch[],
|
|
176
177
|
): Result<void, RenderError>;
|
|
177
178
|
recover(input: RenderFeatureRecoverInput): Result<void, RenderError>;
|
|
179
|
+
createRecoveryRoot(scope: DeviceScope): LifecycleResourceSpec<unknown>;
|
|
178
180
|
diagnostics(): readonly RenderFeatureDiagnostics[];
|
|
179
181
|
/** Subscribe to lifecycle projection changes; unchanged active frames are silent. */
|
|
180
182
|
subscribeDiagnostics(listener: () => void): () => void;
|
|
@@ -915,6 +917,20 @@ class FeatureHostImpl implements RenderFeatureHost {
|
|
|
915
917
|
return this.slots.map((slot) => slot.feature);
|
|
916
918
|
}
|
|
917
919
|
|
|
920
|
+
createRecoveryRoot(scope: DeviceScope): LifecycleResourceSpec<unknown> {
|
|
921
|
+
return {
|
|
922
|
+
kind: 'feature',
|
|
923
|
+
create: () => {
|
|
924
|
+
if (!scope.isAlive()) throw new Error('Feature candidate scope is not active.');
|
|
925
|
+
// The root carries the detached host owner itself. A scalar marker is
|
|
926
|
+
// not evidence that feature planning/preparation actually ran; the
|
|
927
|
+
// candidate graph and host own the prepared resources.
|
|
928
|
+
return this;
|
|
929
|
+
},
|
|
930
|
+
cleanup: () => undefined,
|
|
931
|
+
};
|
|
932
|
+
}
|
|
933
|
+
|
|
918
934
|
private publishDiagnosticsChanged(): void {
|
|
919
935
|
for (const listener of this.diagnosticsListeners) {
|
|
920
936
|
try {
|
|
@@ -11,6 +11,7 @@ import type {
|
|
|
11
11
|
ShaderModule,
|
|
12
12
|
} from '@forgeax/engine-rhi';
|
|
13
13
|
import { type BindGroupLayoutDescriptor, err, ok, type Result } from '@forgeax/engine-types';
|
|
14
|
+
import type { DeviceScope, LifecycleResourceSpec } from '../device/device-scope';
|
|
14
15
|
import { type RenderError, RenderFeaturePreparationFailedError } from '../errors/render';
|
|
15
16
|
import type { PipelineBuilderShaderModuleFactory } from '../pipeline-builder';
|
|
16
17
|
import type { RenderFeatureShaderModuleMode } from './types';
|
|
@@ -910,6 +911,8 @@ function createRenderFeatureGpuWorkSession(input: {
|
|
|
910
911
|
* retains the per-feature prepared GPU state and recreates it after recovery.
|
|
911
912
|
*/
|
|
912
913
|
export interface RenderFeatureGpuWorkOwner {
|
|
914
|
+
/** Candidate root carries this detached GPU-work owner itself. */
|
|
915
|
+
createRecoveryRoot(scope: DeviceScope): LifecycleResourceSpec<unknown>;
|
|
913
916
|
beginFeature(
|
|
914
917
|
featureIdentity: string,
|
|
915
918
|
generation: number,
|
|
@@ -935,9 +938,21 @@ export function createRenderFeatureGpuWorkOwner(input: {
|
|
|
935
938
|
session: RenderFeatureGpuPrepareSession;
|
|
936
939
|
}
|
|
937
940
|
>();
|
|
938
|
-
|
|
939
|
-
|
|
941
|
+
let disposed = false;
|
|
942
|
+
|
|
943
|
+
const owner: RenderFeatureGpuWorkOwner = {
|
|
944
|
+
createRecoveryRoot: (scope) => ({
|
|
945
|
+
kind: 'feature',
|
|
946
|
+
create: () => {
|
|
947
|
+
if (!scope.isAlive()) throw new Error('Feature GPU candidate scope is not active.');
|
|
948
|
+
return owner;
|
|
949
|
+
},
|
|
950
|
+
cleanup: () => undefined,
|
|
951
|
+
}),
|
|
940
952
|
beginFeature: (featureIdentity, generation, requestedShaderModuleMode = 'validated') => {
|
|
953
|
+
if (disposed) {
|
|
954
|
+
throw new Error('Render feature GPU work owner is disposed.');
|
|
955
|
+
}
|
|
941
956
|
const shaderModuleMode = requestedShaderModuleMode;
|
|
942
957
|
const existing = sessions.get(featureIdentity);
|
|
943
958
|
if (existing?.generation === generation && existing.shaderModuleMode === shaderModuleMode) {
|
|
@@ -962,6 +977,8 @@ export function createRenderFeatureGpuWorkOwner(input: {
|
|
|
962
977
|
resolveBuffer: (featureIdentity, reference) =>
|
|
963
978
|
sessions.get(featureIdentity)?.session.resolveBuffer(reference),
|
|
964
979
|
dispose: () => {
|
|
980
|
+
if (disposed) return ok(undefined);
|
|
981
|
+
disposed = true;
|
|
965
982
|
let first: RenderError | undefined;
|
|
966
983
|
for (const { session } of sessions.values()) {
|
|
967
984
|
const disposed = session.dispose();
|
|
@@ -971,4 +988,5 @@ export function createRenderFeatureGpuWorkOwner(input: {
|
|
|
971
988
|
return first === undefined ? ok(undefined) : err(first);
|
|
972
989
|
},
|
|
973
990
|
};
|
|
991
|
+
return owner;
|
|
974
992
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { TextureFormat } from '@forgeax/engine-rhi';
|
|
2
2
|
import { err, ok, type Result } from '@forgeax/engine-types';
|
|
3
|
+
import type { DeviceScope, LifecycleResourceSpec } from '../device/device-scope';
|
|
3
4
|
import { type RenderError, RenderFeaturePreparationFailedError } from '../errors/render';
|
|
4
5
|
import type {
|
|
5
6
|
PreparedKind,
|
|
@@ -81,6 +82,7 @@ export interface PreparedGraphicsStore {
|
|
|
81
82
|
beginFrame(featureIdentity: string, generation: number): PreparedGraphicsTransaction;
|
|
82
83
|
snapshot(featureIdentity: string): PreparedGraphicsStoreSnapshot;
|
|
83
84
|
invalidate(featureIdentity: string, generation: number): void;
|
|
85
|
+
createRecoveryRoot(scope: DeviceScope): LifecycleResourceSpec<unknown>;
|
|
84
86
|
}
|
|
85
87
|
|
|
86
88
|
interface Slot {
|
|
@@ -418,6 +420,21 @@ class PreparedGraphicsStoreImpl implements PreparedGraphicsStore {
|
|
|
418
420
|
}
|
|
419
421
|
}
|
|
420
422
|
|
|
423
|
+
createRecoveryRoot(scope: DeviceScope): LifecycleResourceSpec<unknown> {
|
|
424
|
+
return {
|
|
425
|
+
kind: 'buffer',
|
|
426
|
+
create: () => {
|
|
427
|
+
if (!scope.isAlive()) throw new Error('Prepared graphics candidate scope is not active.');
|
|
428
|
+
const itemCount = [...this.slots.values()].reduce(
|
|
429
|
+
(count, slot) => count + slot.items.size,
|
|
430
|
+
0,
|
|
431
|
+
);
|
|
432
|
+
return Object.freeze({ generation: scope.generation, itemCount });
|
|
433
|
+
},
|
|
434
|
+
cleanup: () => undefined,
|
|
435
|
+
};
|
|
436
|
+
}
|
|
437
|
+
|
|
421
438
|
registerReference(reference: object, item: PreparedGraphicsItem): void {
|
|
422
439
|
this.references.set(reference, item);
|
|
423
440
|
}
|
|
@@ -20,6 +20,7 @@ import type {
|
|
|
20
20
|
import { err, ok, RhiError } from '@forgeax/engine-rhi';
|
|
21
21
|
import type { MaterialShaderArtifact } from '@forgeax/engine-shader';
|
|
22
22
|
import type { MaterialRenderState } from '@forgeax/engine-types';
|
|
23
|
+
import type { DeviceScope, LifecycleResourceSpec } from '../device/device-scope';
|
|
23
24
|
import type { MeshGpuHandles } from '../device/gpu-residency';
|
|
24
25
|
import { GPU_SCENE_WGSL } from '../gpu-scene-schema';
|
|
25
26
|
import {
|
|
@@ -261,8 +262,8 @@ function activeFrustum(camera: CameraSnapshot): Float32Array {
|
|
|
261
262
|
projection,
|
|
262
263
|
camera.orthoLeft,
|
|
263
264
|
camera.orthoRight,
|
|
264
|
-
camera.orthoBottom,
|
|
265
265
|
camera.orthoTop,
|
|
266
|
+
camera.orthoBottom,
|
|
266
267
|
camera.near,
|
|
267
268
|
camera.far,
|
|
268
269
|
);
|
|
@@ -297,6 +298,9 @@ function productionEligible(snapshot: RenderableSnapshot, batch: GpuDrivenBatch)
|
|
|
297
298
|
const shader = material.materialShaderId ?? 'forgeax::default-unlit';
|
|
298
299
|
return (
|
|
299
300
|
shader === 'forgeax::default-unlit' &&
|
|
301
|
+
// The production rigid shader owns triangle-list raster only. Lines and
|
|
302
|
+
// points stay with their CPU/specialized topology owners.
|
|
303
|
+
batch.key.topology === 'triangle-list' &&
|
|
300
304
|
batch.key.materialResourceClass === EMPTY_RESOURCE_CLASS &&
|
|
301
305
|
material.baseColorTexture === undefined &&
|
|
302
306
|
material.transparent !== true
|
|
@@ -928,7 +932,62 @@ export interface PreparedGpuDrivenFrame {
|
|
|
928
932
|
): Result<RenderPipelineGpuDrivenProjection, RenderGraphError | RhiError>;
|
|
929
933
|
}
|
|
930
934
|
|
|
935
|
+
export interface RecoveryCapabilityFacts {
|
|
936
|
+
readonly generation: number;
|
|
937
|
+
readonly shaderCompilation: boolean;
|
|
938
|
+
readonly compute: boolean;
|
|
939
|
+
readonly storageBuffer: boolean;
|
|
940
|
+
readonly indirectDrawing: boolean;
|
|
941
|
+
readonly multisample: boolean;
|
|
942
|
+
}
|
|
943
|
+
|
|
944
|
+
export type RecoveryCapabilityOutcome =
|
|
945
|
+
| {
|
|
946
|
+
readonly status: 'ready' | 'fallback';
|
|
947
|
+
readonly generation: number;
|
|
948
|
+
readonly disabled: readonly string[];
|
|
949
|
+
}
|
|
950
|
+
| {
|
|
951
|
+
readonly status: 'disabled';
|
|
952
|
+
readonly generation: number;
|
|
953
|
+
readonly disabled: readonly string[];
|
|
954
|
+
readonly allocations: 0;
|
|
955
|
+
}
|
|
956
|
+
| {
|
|
957
|
+
readonly status: 'refused';
|
|
958
|
+
readonly generation: number;
|
|
959
|
+
readonly failedOwner: 'shader-material-pipeline';
|
|
960
|
+
readonly resourceKind: 'pipeline';
|
|
961
|
+
};
|
|
962
|
+
|
|
963
|
+
export function classifyRecoveryCapability(
|
|
964
|
+
facts: RecoveryCapabilityFacts,
|
|
965
|
+
): RecoveryCapabilityOutcome {
|
|
966
|
+
if (!facts.shaderCompilation) {
|
|
967
|
+
return {
|
|
968
|
+
status: 'refused',
|
|
969
|
+
generation: facts.generation,
|
|
970
|
+
failedOwner: 'shader-material-pipeline',
|
|
971
|
+
resourceKind: 'pipeline',
|
|
972
|
+
};
|
|
973
|
+
}
|
|
974
|
+
if (!facts.compute || !facts.storageBuffer || !facts.indirectDrawing) {
|
|
975
|
+
return {
|
|
976
|
+
status: 'disabled',
|
|
977
|
+
generation: facts.generation,
|
|
978
|
+
disabled: ['gpu-driven'],
|
|
979
|
+
allocations: 0,
|
|
980
|
+
};
|
|
981
|
+
}
|
|
982
|
+
return {
|
|
983
|
+
status: facts.multisample ? 'ready' : 'fallback',
|
|
984
|
+
generation: facts.generation,
|
|
985
|
+
disabled: [],
|
|
986
|
+
};
|
|
987
|
+
}
|
|
988
|
+
|
|
931
989
|
export class GpuDrivenProduction {
|
|
990
|
+
private disposed = false;
|
|
932
991
|
private view: GpuDrivenView | undefined;
|
|
933
992
|
private raster: GpuDrivenRigidRaster | undefined;
|
|
934
993
|
private standardRaster: StandardPbrRasterAdapter | undefined;
|
|
@@ -972,6 +1031,27 @@ export class GpuDrivenProduction {
|
|
|
972
1031
|
private readonly shaderModuleFactory: PipelineBuilderShaderModuleFactory,
|
|
973
1032
|
) {}
|
|
974
1033
|
|
|
1034
|
+
static forDevice(
|
|
1035
|
+
device: RhiDevice,
|
|
1036
|
+
shaderModuleFactory: PipelineBuilderShaderModuleFactory,
|
|
1037
|
+
): GpuDrivenProduction {
|
|
1038
|
+
return new GpuDrivenProduction(device, shaderModuleFactory);
|
|
1039
|
+
}
|
|
1040
|
+
|
|
1041
|
+
createRecoveryRoot(scope: DeviceScope): LifecycleResourceSpec<unknown> {
|
|
1042
|
+
return {
|
|
1043
|
+
kind: 'scene-table',
|
|
1044
|
+
create: () => {
|
|
1045
|
+
if (!scope.isAlive()) throw new Error('GPU-driven candidate scope is not active.');
|
|
1046
|
+
// Keep the actual detached production owner in the generation
|
|
1047
|
+
// aggregate. The recovery transaction, not a marker object, is the
|
|
1048
|
+
// owner that is published or discarded exactly once.
|
|
1049
|
+
return this;
|
|
1050
|
+
},
|
|
1051
|
+
cleanup: () => undefined,
|
|
1052
|
+
};
|
|
1053
|
+
}
|
|
1054
|
+
|
|
975
1055
|
prepare(input: {
|
|
976
1056
|
readonly scene: PersistentGpuDrivenState | undefined;
|
|
977
1057
|
readonly camera: CameraSnapshot;
|
|
@@ -1000,7 +1080,20 @@ export class GpuDrivenProduction {
|
|
|
1000
1080
|
this.telemetryGeometryWork = 0;
|
|
1001
1081
|
this.telemetryRootGeometryWork = 0;
|
|
1002
1082
|
this.indirectDrawCount = 0;
|
|
1003
|
-
|
|
1083
|
+
const capability = classifyRecoveryCapability({
|
|
1084
|
+
generation: 0,
|
|
1085
|
+
shaderCompilation: true,
|
|
1086
|
+
compute: this.device.caps.compute,
|
|
1087
|
+
storageBuffer: this.device.caps.storageBuffer,
|
|
1088
|
+
indirectDrawing: this.device.caps.indirectDrawing,
|
|
1089
|
+
multisample: true,
|
|
1090
|
+
});
|
|
1091
|
+
if (
|
|
1092
|
+
input.hdrp ||
|
|
1093
|
+
input.scene === undefined ||
|
|
1094
|
+
capability.status === 'disabled' ||
|
|
1095
|
+
selectGpuLodLane(this.device.caps) === 'cpu'
|
|
1096
|
+
) {
|
|
1004
1097
|
this.gpuOwnedEntityCount = 0;
|
|
1005
1098
|
this.sceneRowsRequired = false;
|
|
1006
1099
|
return ok(undefined);
|
|
@@ -1457,6 +1550,8 @@ export class GpuDrivenProduction {
|
|
|
1457
1550
|
}
|
|
1458
1551
|
|
|
1459
1552
|
dispose(): void {
|
|
1553
|
+
if (this.disposed) return;
|
|
1554
|
+
this.disposed = true;
|
|
1460
1555
|
this.view?.dispose();
|
|
1461
1556
|
this.view = undefined;
|
|
1462
1557
|
this.raster = undefined;
|
package/src/gpu-scene.ts
CHANGED
|
@@ -201,6 +201,7 @@ function coalesceSlots(
|
|
|
201
201
|
|
|
202
202
|
/** Persistent GPU tables derived only from renderer projection slots. */
|
|
203
203
|
export class GpuScene {
|
|
204
|
+
private disposed = false;
|
|
204
205
|
private tableBytes: Record<GpuSceneTableName, ArrayBuffer>;
|
|
205
206
|
private transformBytes: Uint8Array;
|
|
206
207
|
private transformView: DataView;
|
|
@@ -432,6 +433,8 @@ export class GpuScene {
|
|
|
432
433
|
}
|
|
433
434
|
|
|
434
435
|
dispose(): void {
|
|
436
|
+
if (this.disposed) return;
|
|
437
|
+
this.disposed = true;
|
|
435
438
|
for (const buffer of Object.values(this.buffers)) this.device.destroyBuffer(buffer);
|
|
436
439
|
}
|
|
437
440
|
|
|
@@ -583,8 +586,6 @@ export class GpuScene {
|
|
|
583
586
|
writeVec4(material, materialOffset + offset(MATERIAL, 'params1'), [
|
|
584
587
|
snapshot.metallic ?? 0,
|
|
585
588
|
snapshot.roughness ?? 1,
|
|
586
|
-
snapshot.clearcoat ?? 0,
|
|
587
|
-
snapshot.clearcoatRoughness ?? 0,
|
|
588
589
|
]);
|
|
589
590
|
writeVec4(material, materialOffset + offset(MATERIAL, 'params2'), [
|
|
590
591
|
snapshot.emissive?.[0] ?? 0,
|