@forgeax/engine-render 0.1.34 → 0.1.35
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 +52 -3
- package/dist/assembly/device-feature-admission.d.ts +2 -2
- package/dist/assembly/host-contract.d.ts +3 -2
- package/dist/assembly/host-contract.d.ts.map +1 -1
- package/dist/assembly/recovery/renderer-recover.d.ts.map +1 -1
- package/dist/assembly/render-target-host.d.ts +5 -0
- package/dist/assembly/render-target-host.d.ts.map +1 -1
- package/dist/assembly/renderer-facade.d.ts.map +1 -1
- package/dist/assembly/webgpu-renderer.d.ts +1 -0
- package/dist/assembly/webgpu-renderer.d.ts.map +1 -1
- package/dist/authoring.mjs +2 -4
- package/dist/authoring.mjs.map +1 -1
- package/dist/chunk-3XUBWRY2.mjs +1842 -0
- package/dist/chunk-3XUBWRY2.mjs.map +1 -0
- package/dist/{chunk-UI5SFODX.mjs → chunk-G6HDNGY7.mjs} +2329 -1776
- package/dist/chunk-G6HDNGY7.mjs.map +1 -0
- package/dist/{chunk-HEB564WF.mjs → chunk-LM5IE7GF.mjs} +4 -4
- package/dist/{chunk-HEB564WF.mjs.map → chunk-LM5IE7GF.mjs.map} +1 -1
- package/dist/{chunk-MKDIT2EM.mjs → chunk-LNIUIKQ7.mjs} +143 -246
- package/dist/chunk-LNIUIKQ7.mjs.map +1 -0
- package/dist/chunk-MXTWKZO4.mjs +3268 -0
- package/dist/chunk-MXTWKZO4.mjs.map +1 -0
- package/dist/{chunk-ODZWR6JQ.mjs → chunk-MZ4C7EHF.mjs} +2042 -27
- package/dist/chunk-MZ4C7EHF.mjs.map +1 -0
- package/dist/chunk-RIPAEGI6.mjs +48 -0
- package/dist/chunk-RIPAEGI6.mjs.map +1 -0
- package/dist/{chunk-OCDLEI6I.mjs → chunk-SGPUJW3F.mjs} +117 -5
- package/dist/chunk-SGPUJW3F.mjs.map +1 -0
- package/dist/{chunk-ELJFJ2BU.mjs → chunk-X2KA6WHM.mjs} +29 -4
- package/dist/chunk-X2KA6WHM.mjs.map +1 -0
- package/dist/{chunk-BLXGONR2.mjs → chunk-XSFB7XXQ.mjs} +51 -4
- package/dist/chunk-XSFB7XXQ.mjs.map +1 -0
- package/dist/cloud/frame-context.d.ts +2 -2
- package/dist/cloud/frame-context.d.ts.map +1 -1
- package/dist/construct-renderer.mjs +810 -2073
- package/dist/construct-renderer.mjs.map +1 -1
- package/dist/device/gpu-residency.d.ts +19 -19
- package/dist/device/gpu-residency.d.ts.map +1 -1
- package/dist/errors/render.d.ts +3 -2
- package/dist/errors/render.d.ts.map +1 -1
- package/dist/extract/material-context.d.ts +7 -0
- package/dist/extract/material-context.d.ts.map +1 -0
- package/dist/features/host.d.ts +5 -0
- package/dist/features/host.d.ts.map +1 -1
- package/dist/features/plan.d.ts +2 -0
- package/dist/features/plan.d.ts.map +1 -1
- package/dist/features/types.d.ts +4 -0
- package/dist/features/types.d.ts.map +1 -1
- package/dist/glyph-text-layout-system.d.ts +1 -1
- package/dist/glyph-text-layout-system.d.ts.map +1 -1
- package/dist/gpu-driven/shadow-ownership.d.ts +3 -3
- package/dist/gpu-driven/shadow-ownership.d.ts.map +1 -1
- package/dist/ibl/frame-resources.d.ts.map +1 -1
- package/dist/ibl/skylight-bind-group.d.ts +4 -4
- package/dist/ibl/skylight-bind-group.d.ts.map +1 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.mjs +530 -9
- package/dist/index.mjs.map +1 -1
- package/dist/instances.d.ts +3 -4
- package/dist/instances.d.ts.map +1 -1
- package/dist/internal.mjs +7 -8
- package/dist/internal.mjs.map +1 -1
- package/dist/pbr-pipeline.d.ts +3 -3
- package/dist/pbr-pipeline.d.ts.map +1 -1
- package/dist/pipeline/standard-output/lut-gpu.d.ts +2 -2
- package/dist/pipeline/standard-output/lut-gpu.d.ts.map +1 -1
- package/dist/pipeline/standard-output/resources.d.ts +2 -2
- package/dist/pipeline/standard-output/resources.d.ts.map +1 -1
- package/dist/publication/contract.d.ts +77 -0
- package/dist/publication/contract.d.ts.map +1 -0
- package/dist/publication/dependencies.d.ts +7 -0
- package/dist/publication/dependencies.d.ts.map +1 -0
- package/dist/publication/prepare-geometry.d.ts +9 -0
- package/dist/publication/prepare-geometry.d.ts.map +1 -0
- package/dist/publication/programs.d.ts +5 -0
- package/dist/publication/programs.d.ts.map +1 -0
- package/dist/publication/publisher.d.ts +33 -0
- package/dist/publication/publisher.d.ts.map +1 -0
- package/dist/publication/receiver.d.ts +29 -0
- package/dist/publication/receiver.d.ts.map +1 -0
- package/dist/publication/resource-scope.d.ts +18 -0
- package/dist/publication/resource-scope.d.ts.map +1 -0
- package/dist/publication/targets.d.ts +33 -0
- package/dist/publication/targets.d.ts.map +1 -0
- package/dist/publication/video.d.ts +5 -0
- package/dist/publication/video.d.ts.map +1 -0
- package/dist/record/fold-buckets.d.ts +3 -3
- package/dist/record/fold-buckets.d.ts.map +1 -1
- package/dist/record/frame-snapshot.d.ts +6 -6
- package/dist/record/frame-snapshot.d.ts.map +1 -1
- package/dist/record/frame.d.ts +5 -4
- package/dist/record/frame.d.ts.map +1 -1
- package/dist/record/helpers.d.ts +2 -2
- package/dist/record/helpers.d.ts.map +1 -1
- package/dist/record/main-pass-geometry.d.ts +2 -2
- package/dist/record/main-pass-geometry.d.ts.map +1 -1
- package/dist/record/main-pass-material.d.ts +7 -9
- package/dist/record/main-pass-material.d.ts.map +1 -1
- package/dist/record/main-pass-sprite-draws.d.ts +3 -16
- package/dist/record/main-pass-sprite-draws.d.ts.map +1 -1
- package/dist/record/main-pass.d.ts.map +1 -1
- package/dist/record/prepared-material-bindings.d.ts +3 -3
- package/dist/record/prepared-material-bindings.d.ts.map +1 -1
- package/dist/record/render-context.d.ts +2 -2
- package/dist/record/render-context.d.ts.map +1 -1
- package/dist/record/sprite-instance-buffer.d.ts +31 -0
- package/dist/record/sprite-instance-buffer.d.ts.map +1 -0
- package/dist/record/target-capture-graph.d.ts +19 -0
- package/dist/record/target-capture-graph.d.ts.map +1 -0
- package/dist/record/typed-frame-graph.d.ts +2 -13
- package/dist/record/typed-frame-graph.d.ts.map +1 -1
- package/dist/record/view-ubo.d.ts.map +1 -1
- package/dist/record/volume-params.d.ts +2 -2
- package/dist/record/volume-params.d.ts.map +1 -1
- package/dist/recovery/render-system-candidate.d.ts +5 -5
- package/dist/recovery/render-system-candidate.d.ts.map +1 -1
- package/dist/render-contract.d.ts +4 -1
- package/dist/render-contract.d.ts.map +1 -1
- package/dist/render-system-extract-tail.d.ts.map +1 -1
- package/dist/render-system-extract.d.ts +2 -0
- package/dist/render-system-extract.d.ts.map +1 -1
- package/dist/render-system-presentation.d.ts +2 -2
- package/dist/render-system-presentation.d.ts.map +1 -1
- package/dist/render-system-projections.d.ts +3 -2
- package/dist/render-system-projections.d.ts.map +1 -1
- package/dist/render-system-residency.d.ts +2 -2
- package/dist/render-system-residency.d.ts.map +1 -1
- package/dist/render-system.d.ts +3 -7
- package/dist/render-system.d.ts.map +1 -1
- package/dist/scene/render-scene.d.ts +8 -4
- package/dist/scene/render-scene.d.ts.map +1 -1
- package/dist/scene/render-source.d.ts +42 -0
- package/dist/scene/render-source.d.ts.map +1 -0
- package/dist/scene/source-systems.d.ts +6 -0
- package/dist/scene/source-systems.d.ts.map +1 -0
- package/dist/systems/skin-palette-allocator.d.ts.map +1 -1
- package/dist/systems/skin-palette-types.d.ts +10 -0
- package/dist/systems/skin-palette-types.d.ts.map +1 -1
- package/dist/systems/transparent-dispatch.d.ts +2 -2
- package/dist/systems/transparent-dispatch.d.ts.map +1 -1
- package/dist/systems/transparent-sort-config.d.ts +2 -1
- package/dist/systems/transparent-sort-config.d.ts.map +1 -1
- package/dist/temporal/index.mjs +6 -7
- package/package.json +21 -21
- package/src/__tests__/auto-exposure-transaction.integration.test.ts +4 -9
- package/src/__tests__/device-feature-admission.unit.test.ts +3 -2
- package/src/__tests__/gpu-driven-pbr.dawn.test.ts +3 -4
- package/src/__tests__/ktx2-basis-gpu-consumer.dawn.test.ts +4 -1
- package/src/__tests__/main-pass-material-medium-selection.unit.test.ts +0 -1
- package/src/__tests__/materials-standard-contract.unit.test.ts +0 -1
- package/src/__tests__/physical-clearcoat.integration.test.ts +23 -23
- package/src/__tests__/physical-material-budget.unit.test.ts +40 -0
- package/src/__tests__/render-error-code-owner.test-d.ts +1 -0
- package/src/__tests__/renderer-factory-material-contract.unit.test.ts +1 -1
- package/src/assembly/device-feature-admission.ts +2 -2
- package/src/assembly/host-contract.ts +5 -2
- package/src/assembly/recovery/renderer-recover.ts +9 -0
- package/src/assembly/render-target-host.ts +57 -47
- package/src/assembly/renderer-facade.ts +3 -1
- package/src/assembly/webgpu-ready.ts +1 -1
- package/src/assembly/webgpu-renderer.ts +89 -61
- package/src/cloud/frame-context.ts +2 -2
- package/src/device/gpu-residency.ts +26 -25
- package/src/errors/render.ts +3 -1
- package/src/extract/material-context.ts +21 -0
- package/src/features/host.ts +13 -5
- package/src/features/plan.ts +2 -0
- package/src/features/types.ts +4 -0
- package/src/glyph-text-layout-system.ts +2 -2
- package/src/gpu-driven/shadow-ownership.ts +3 -3
- package/src/ibl/frame-resources.ts +0 -1
- package/src/ibl/skylight-bind-group.ts +13 -25
- package/src/index.ts +9 -0
- package/src/instances.ts +9 -6
- package/src/pbr-pipeline.ts +11 -17
- package/src/pipeline/standard-output/lut-gpu.ts +3 -3
- package/src/pipeline/standard-output/resources.ts +2 -2
- package/src/publication/__tests__/derived-geometry.integration.test.ts +177 -0
- package/src/publication/__tests__/features.integration.test.ts +122 -0
- package/src/publication/__tests__/programs.unit.test.ts +25 -0
- package/src/publication/__tests__/publication.integration.test.ts +370 -0
- package/src/publication/__tests__/targets.integration.test.ts +120 -0
- package/src/publication/__tests__/video.browser.test.ts +50 -0
- package/src/publication/contract.ts +104 -0
- package/src/publication/dependencies.ts +54 -0
- package/src/publication/prepare-geometry.ts +94 -0
- package/src/publication/programs.ts +45 -0
- package/src/publication/publisher.ts +618 -0
- package/src/publication/receiver.ts +297 -0
- package/src/publication/resource-scope.ts +31 -0
- package/src/publication/targets.ts +182 -0
- package/src/publication/video.ts +33 -0
- package/src/record/__tests__/material-bg-cache.unit.test.ts +15 -1
- package/src/record/__tests__/sprite-material-abi.unit.test.ts +8 -10
- package/src/record/__tests__/video-texture-view.unit.test.ts +9 -9
- package/src/record/fold-buckets.ts +8 -5
- package/src/record/frame-snapshot.ts +6 -6
- package/src/record/frame.ts +42 -22
- package/src/record/helpers.ts +2 -2
- package/src/record/main-pass-geometry.ts +21 -2
- package/src/record/main-pass-material.ts +37 -33
- package/src/record/main-pass-sprite-draws.ts +6 -152
- package/src/record/main-pass.ts +8 -7
- package/src/record/prepared-material-bindings.ts +11 -6
- package/src/record/render-context.ts +2 -2
- package/src/record/shadow-pass.ts +0 -3
- package/src/record/sprite-instance-buffer.ts +155 -0
- package/src/record/target-capture-graph.ts +258 -0
- package/src/record/typed-frame-graph.ts +6 -206
- package/src/record/view-ubo.ts +1 -1
- package/src/record/volume-params.ts +6 -6
- package/src/recovery/render-system-candidate.ts +10 -10
- package/src/render-contract.ts +6 -1
- package/src/render-system-extract-tail.ts +33 -17
- package/src/render-system-extract.ts +2 -0
- package/src/render-system-presentation.ts +2 -2
- package/src/render-system-projections.ts +3 -2
- package/src/render-system-residency.ts +2 -2
- package/src/render-system.ts +82 -53
- package/src/scene/render-scene.ts +110 -100
- package/src/scene/render-source.ts +90 -0
- package/src/scene/source-systems.ts +33 -0
- package/src/systems/skin-palette-allocator.ts +1 -0
- package/src/systems/skin-palette-types.ts +11 -0
- package/src/systems/transparent-dispatch.ts +2 -2
- package/src/systems/transparent-sort-config.ts +3 -1
- package/dist/chunk-BLXGONR2.mjs.map +0 -1
- package/dist/chunk-ELJFJ2BU.mjs.map +0 -1
- package/dist/chunk-ILQ5MEZF.mjs +0 -32
- package/dist/chunk-ILQ5MEZF.mjs.map +0 -1
- package/dist/chunk-MKDIT2EM.mjs.map +0 -1
- package/dist/chunk-OCDLEI6I.mjs.map +0 -1
- package/dist/chunk-ODZWR6JQ.mjs.map +0 -1
- package/dist/chunk-RXZ3RGOU.mjs +0 -53
- package/dist/chunk-RXZ3RGOU.mjs.map +0 -1
- package/dist/chunk-SHFUFJ5N.mjs +0 -1781
- package/dist/chunk-SHFUFJ5N.mjs.map +0 -1
- package/dist/chunk-UI5SFODX.mjs.map +0 -1
- package/dist/chunk-UINHLCZA.mjs +0 -2389
- package/dist/chunk-UINHLCZA.mjs.map +0 -1
- package/dist/chunk-WEX45HKH.mjs +0 -1524
- package/dist/chunk-WEX45HKH.mjs.map +0 -1
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { type DynamicTextureDevice, DynamicTextureStore } from '@forgeax/engine-assets-runtime';
|
|
2
2
|
import { World } from '@forgeax/engine-ecs';
|
|
3
3
|
import {
|
|
4
|
-
|
|
5
|
-
type
|
|
4
|
+
VIDEO_SOURCE_PROVIDER_KEY,
|
|
5
|
+
type VideoSourceProvider,
|
|
6
6
|
} from '@forgeax/engine-graphics-extras';
|
|
7
7
|
import type { Result, RhiError, Texture, TextureView } from '@forgeax/engine-rhi';
|
|
8
8
|
import { ok } from '@forgeax/engine-rhi';
|
|
@@ -53,16 +53,16 @@ describe('videoTextureView provider-loss recovery', () => {
|
|
|
53
53
|
const store = makeStore(probe);
|
|
54
54
|
const errors: { readonly code: string }[] = [];
|
|
55
55
|
const runtime = runtimeWithErrors((error) => errors.push(error));
|
|
56
|
-
const provider:
|
|
57
|
-
|
|
56
|
+
const provider: VideoSourceProvider = {
|
|
57
|
+
getSource: vi.fn(() => VIDEO),
|
|
58
58
|
};
|
|
59
|
-
world.insertResource(
|
|
59
|
+
world.insertResource(VIDEO_SOURCE_PROVIDER_KEY, provider);
|
|
60
60
|
|
|
61
61
|
const lkg = videoTextureView(world, store, runtime, ENTITY, CLIP, false);
|
|
62
62
|
expect(lkg).toBeDefined();
|
|
63
63
|
expect(probe.copies).toBe(1);
|
|
64
64
|
|
|
65
|
-
world.removeResource(
|
|
65
|
+
world.removeResource(VIDEO_SOURCE_PROVIDER_KEY);
|
|
66
66
|
expect(videoTextureView(world, store, runtime, ENTITY, CLIP, false)).toBe(lkg);
|
|
67
67
|
expect(videoTextureView(world, store, runtime, ENTITY, CLIP, false)).toBe(lkg);
|
|
68
68
|
expect(videoTextureView(world, store, runtime, ENTITY, CLIP, false)).toBe(lkg);
|
|
@@ -70,19 +70,19 @@ describe('videoTextureView provider-loss recovery', () => {
|
|
|
70
70
|
expect(errors[0]?.code).toBe('video-upload-unsupported');
|
|
71
71
|
expect(probe.copies).toBe(1);
|
|
72
72
|
|
|
73
|
-
world.insertResource(
|
|
73
|
+
world.insertResource(VIDEO_SOURCE_PROVIDER_KEY, provider);
|
|
74
74
|
expect(videoTextureView(world, store, runtime, ENTITY, CLIP, false)).toBe(lkg);
|
|
75
75
|
expect(videoTextureView(world, store, runtime, ENTITY, CLIP, false)).toBe(lkg);
|
|
76
76
|
expect(errors).toHaveLength(1);
|
|
77
77
|
expect(probe.copies).toBe(3);
|
|
78
78
|
|
|
79
|
-
world.removeResource(
|
|
79
|
+
world.removeResource(VIDEO_SOURCE_PROVIDER_KEY);
|
|
80
80
|
expect(videoTextureView(world, store, runtime, ENTITY, CLIP, false)).toBe(lkg);
|
|
81
81
|
expect(videoTextureView(world, store, runtime, ENTITY, CLIP, false)).toBe(lkg);
|
|
82
82
|
expect(errors).toHaveLength(2);
|
|
83
83
|
expect(probe.copies).toBe(3);
|
|
84
84
|
|
|
85
|
-
world.insertResource(
|
|
85
|
+
world.insertResource(VIDEO_SOURCE_PROVIDER_KEY, provider);
|
|
86
86
|
expect(videoTextureView(world, store, runtime, ENTITY, CLIP, false)).toBe(lkg);
|
|
87
87
|
expect(errors).toHaveLength(2);
|
|
88
88
|
expect(probe.copies).toBe(4);
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { HANDLE_NINESLICE_QUAD, resolveAssetHandle } from '@forgeax/engine-assets-runtime';
|
|
2
|
-
import type { World } from '@forgeax/engine-ecs';
|
|
3
2
|
import { deriveVertexCount } from '@forgeax/engine-geometry';
|
|
4
3
|
import { RhiError } from '@forgeax/engine-rhi';
|
|
5
4
|
import type { MaterialRenderState, MeshAsset } from '@forgeax/engine-types';
|
|
@@ -9,6 +8,8 @@ import { materialBindingKey } from '../gpu-driven/material-bindings';
|
|
|
9
8
|
import { GpuBuffer } from '../gpu-resource';
|
|
10
9
|
import { GPU_BUFFER_USAGE_COPY_DST, GPU_BUFFER_USAGE_VERTEX } from '../gpu-usage';
|
|
11
10
|
import { disposeTransientInstanceBuffers } from '../instance-buffer-cache';
|
|
11
|
+
import type { RenderResourceScope } from '../publication/resource-scope';
|
|
12
|
+
import { renderAssetByGuid } from '../publication/resource-scope';
|
|
12
13
|
import type { DispatchEntry, MaterialSnapshot, RenderableSnapshot } from '../render-system-extract';
|
|
13
14
|
import {
|
|
14
15
|
getTransparentSortConfig,
|
|
@@ -151,14 +152,14 @@ function limitRowsToMeshSsboCapacity<T>(rows: readonly T[], availableSlots: numb
|
|
|
151
152
|
*/
|
|
152
153
|
export function validateRenderables(
|
|
153
154
|
internals: RenderSystemInternals,
|
|
154
|
-
world:
|
|
155
|
+
world: RenderResourceScope,
|
|
155
156
|
// feat-20260709-editor-world-partition ENGINE-fix-round2 (defect 2): the full
|
|
156
157
|
// worlds[] list. Each renderable's mesh handle is a user-tier slot in its OWN
|
|
157
158
|
// world's sharedRefs; resolving against a foreign world either misses
|
|
158
159
|
// (asset-not-registered) or resolves the wrong slot payload. `world` (the
|
|
159
160
|
// resource-owner) is retained as the fallback for renderables whose worldId
|
|
160
161
|
// is out of range (defensive; extractFrames always stamps a valid index).
|
|
161
|
-
worlds: readonly
|
|
162
|
+
worlds: readonly RenderResourceScope[],
|
|
162
163
|
pipelineState: PipelineState,
|
|
163
164
|
frameState: RenderFrameState,
|
|
164
165
|
renderables: readonly RenderableSnapshot[],
|
|
@@ -226,7 +227,9 @@ export function validateRenderables(
|
|
|
226
227
|
// frames hit the O(1) cache.
|
|
227
228
|
const meshAssetHandle = toShared<'MeshAsset'>(r.assetHandle);
|
|
228
229
|
let meshHandles = internals.gpuStore.getMeshGpuHandles(meshAssetHandle, renderableWorld);
|
|
229
|
-
const lodMeshes = r.lods?.map((lod) =>
|
|
230
|
+
const lodMeshes = r.lods?.map((lod) =>
|
|
231
|
+
renderAssetByGuid<MeshAsset>(renderableWorld, internals.assets, lod.mesh),
|
|
232
|
+
);
|
|
230
233
|
const resolvedLodMeshes =
|
|
231
234
|
lodMeshes?.every((lod): lod is MeshAsset => lod?.kind === 'mesh') === true
|
|
232
235
|
? lodMeshes
|
|
@@ -793,7 +796,7 @@ export function cleanPerFrameCaches(
|
|
|
793
796
|
* @internal
|
|
794
797
|
*/
|
|
795
798
|
export function computeFoldBuckets(
|
|
796
|
-
world:
|
|
799
|
+
world: RenderResourceScope,
|
|
797
800
|
frameState: RenderFrameState,
|
|
798
801
|
transparentDispatch: readonly DispatchEntry[],
|
|
799
802
|
renderables: readonly RenderableSnapshot[],
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
+
import type { RenderResourceScope } from '../publication/resource-scope';
|
|
1
2
|
// @forgeax/engine-runtime - RenderSystem record stage: frame-snapshot.
|
|
2
3
|
// Extracted from render-system-record.ts (feat-20260704 M3/w17, pure move).
|
|
3
4
|
|
|
4
|
-
import type { World } from '@forgeax/engine-ecs';
|
|
5
5
|
import type { RenderReadVersion } from '@forgeax/engine-ecs/projection';
|
|
6
6
|
import { vec3 } from '@forgeax/engine-math';
|
|
7
7
|
import type {
|
|
@@ -867,8 +867,8 @@ export interface BloomFrameReceipts {
|
|
|
867
867
|
*/
|
|
868
868
|
export interface ValidatedRenderable {
|
|
869
869
|
readonly source: RenderableSnapshot;
|
|
870
|
-
/**
|
|
871
|
-
readonly world?:
|
|
870
|
+
/** RenderResourceScope that owns the renderable's asset handles and material snapshots. */
|
|
871
|
+
readonly world?: RenderResourceScope;
|
|
872
872
|
readonly mesh: MeshGpuHandles;
|
|
873
873
|
readonly renderableIndex: number;
|
|
874
874
|
readonly renderState: MaterialRenderState | undefined;
|
|
@@ -900,7 +900,7 @@ export interface ValidatedRenderable {
|
|
|
900
900
|
* @internal
|
|
901
901
|
*/
|
|
902
902
|
export interface DirectionalShadowCache {
|
|
903
|
-
readonly worlds: readonly
|
|
903
|
+
readonly worlds: readonly RenderResourceScope[];
|
|
904
904
|
readonly worldStateTokens: readonly DirectionalShadowWorldState[];
|
|
905
905
|
readonly assetCatalogEpoch: number;
|
|
906
906
|
readonly pipelineHandle: number;
|
|
@@ -916,8 +916,8 @@ export interface DirectionalShadowCache {
|
|
|
916
916
|
* ECS state that can change the contents of a directional shadow map.
|
|
917
917
|
*
|
|
918
918
|
* The ECS-owned RenderReadLease is the only render-facing mutation boundary.
|
|
919
|
-
* Its version is intentionally conservative: any published
|
|
920
|
-
* invalidates the cached atlas, while render never reaches through
|
|
919
|
+
* Its version is intentionally conservative: any published RenderResourceScope change
|
|
920
|
+
* invalidates the cached atlas, while render never reaches through RenderResourceScope for
|
|
921
921
|
* component-clock storage.
|
|
922
922
|
*/
|
|
923
923
|
export interface DirectionalShadowWorldState {
|
package/src/record/frame.ts
CHANGED
|
@@ -5,6 +5,8 @@ import {
|
|
|
5
5
|
requiresProbeBlendRecord,
|
|
6
6
|
} from '../gpu-driven/material-artifacts';
|
|
7
7
|
import { projectMaterialBindingClasses } from '../gpu-driven/material-bindings';
|
|
8
|
+
import type { RenderResourceScope } from '../publication/resource-scope';
|
|
9
|
+
import { renderAssetByGuid, renderTime } from '../publication/resource-scope';
|
|
8
10
|
import {
|
|
9
11
|
buildDispatchPlan,
|
|
10
12
|
cleanPerFrameCaches,
|
|
@@ -16,7 +18,6 @@ import { uploadMaterialUniforms } from './material-uniforms';
|
|
|
16
18
|
// Extracted from render-system-record.ts (feat-20260704 M3/w17, pure move).
|
|
17
19
|
|
|
18
20
|
import { resolveAssetHandle } from '@forgeax/engine-assets-runtime';
|
|
19
|
-
import { Time, type World } from '@forgeax/engine-ecs';
|
|
20
21
|
import type { RenderReadLease } from '@forgeax/engine-ecs/projection';
|
|
21
22
|
import { frustum, mat4, vec3 } from '@forgeax/engine-math';
|
|
22
23
|
import {
|
|
@@ -144,11 +145,14 @@ export type FrameObservationReadback = (
|
|
|
144
145
|
) => Promise<Result<Uint8Array, Error>>;
|
|
145
146
|
|
|
146
147
|
/**
|
|
147
|
-
* Fold
|
|
148
|
+
* Fold RenderResourceScope identity into the renderer-owned validation token. The GPU
|
|
148
149
|
* production owner receives only this opaque key; ECS identity and ordering
|
|
149
|
-
* stay in the record owner where the
|
|
150
|
+
* stay in the record owner where the RenderResourceScope list is authoritative.
|
|
150
151
|
*/
|
|
151
|
-
function residencyValidationCacheKey(
|
|
152
|
+
function residencyValidationCacheKey(
|
|
153
|
+
world: RenderResourceScope,
|
|
154
|
+
worlds: readonly RenderResourceScope[],
|
|
155
|
+
): string {
|
|
152
156
|
return [world.identity, ...worlds.map((candidate) => candidate.identity)].join('\u001f');
|
|
153
157
|
}
|
|
154
158
|
function renderableIdentity(snapshot: Pick<RenderableSnapshot, 'worldId' | 'entityKey'>): string {
|
|
@@ -327,7 +331,7 @@ import {
|
|
|
327
331
|
/**
|
|
328
332
|
* Resolve the GPU mesh view used by the optional production raster before its
|
|
329
333
|
* filtering pass runs. The result is keyed by the retained RenderScene slot,
|
|
330
|
-
* which preserves the
|
|
334
|
+
* which preserves the RenderResourceScope namespace already used by gpuStore. User meshes
|
|
331
335
|
* are pull-resident during record; relying only on the boot-time builtin map
|
|
332
336
|
* would make the first frame classify every imported mesh as a CPU fallback
|
|
333
337
|
* and would hide its LOD ranges from the GPU cull. Builtins are the only
|
|
@@ -336,7 +340,7 @@ import {
|
|
|
336
340
|
export function gpuDrivenMeshesForFrame(
|
|
337
341
|
internals: RenderSystemInternals,
|
|
338
342
|
pipelineState: PipelineState,
|
|
339
|
-
worlds: readonly
|
|
343
|
+
worlds: readonly RenderResourceScope[],
|
|
340
344
|
scene: PersistentGpuDrivenState | undefined,
|
|
341
345
|
): ReadonlyMap<number, MeshGpuHandles> {
|
|
342
346
|
const meshes = new Map<number, MeshGpuHandles>();
|
|
@@ -357,7 +361,7 @@ export function gpuDrivenMeshesForFrame(
|
|
|
357
361
|
const asset = resolveAssetHandle<MeshAsset>(world, sharedHandle);
|
|
358
362
|
if (asset.ok) {
|
|
359
363
|
const lodMeshes = slot.snapshot.lods?.map((lod) =>
|
|
360
|
-
|
|
364
|
+
renderAssetByGuid<MeshAsset>(world, internals.assets, lod.mesh),
|
|
361
365
|
);
|
|
362
366
|
const resolvedLodMeshes =
|
|
363
367
|
lodMeshes?.every((lod): lod is MeshAsset => lod?.kind === 'mesh') === true
|
|
@@ -382,6 +386,7 @@ export type RecordProfileRunner = <T>(phase: RenderRecordPhase, action: () => T)
|
|
|
382
386
|
export interface CubeCaptureFrameInput {
|
|
383
387
|
readonly captureDispatch?: readonly DispatchEntry[];
|
|
384
388
|
readonly snapshots: readonly CubeCameraSnapshot[];
|
|
389
|
+
readonly auxiliaryCameras: readonly CameraSnapshot[];
|
|
385
390
|
readonly scheduler: import('../capture/scheduler').CubeCaptureScheduler;
|
|
386
391
|
readonly state: CubeCaptureGraphState;
|
|
387
392
|
readonly reflectionProbes?: import('./render-context').ReflectionProbeRecordState;
|
|
@@ -437,6 +442,18 @@ function prepareCubeCapture(
|
|
|
437
442
|
(CUBE_CAPTURE_VIEW_SLOT_BASE + physicalWork.length) * VIEW_UNIFORM_SLOT_STRIDE,
|
|
438
443
|
});
|
|
439
444
|
}
|
|
445
|
+
for (const camera of input.auxiliaryCameras) {
|
|
446
|
+
if (camera.target === undefined) continue;
|
|
447
|
+
const physical = internals.getRenderTargetPhysical?.(camera.target);
|
|
448
|
+
if (physical?.descriptor.shape !== '2d') continue;
|
|
449
|
+
physicalWork.push({
|
|
450
|
+
target: camera.target,
|
|
451
|
+
faceIndex: 0,
|
|
452
|
+
physical,
|
|
453
|
+
faceCamera: camera,
|
|
454
|
+
viewBindGroupDynamicOffset: (CUBE_CAPTURE_VIEW_SLOT_BASE + 6) * VIEW_UNIFORM_SLOT_STRIDE,
|
|
455
|
+
});
|
|
456
|
+
}
|
|
440
457
|
input.state.work = physicalWork;
|
|
441
458
|
return physicalWork;
|
|
442
459
|
}
|
|
@@ -840,8 +857,8 @@ function resolveVolumetricFogHistoryContext(
|
|
|
840
857
|
*/
|
|
841
858
|
function prepareSpotLightProjectorFrame(
|
|
842
859
|
internals: RenderSystemInternals,
|
|
843
|
-
world:
|
|
844
|
-
worlds: readonly
|
|
860
|
+
world: RenderResourceScope,
|
|
861
|
+
worlds: readonly RenderResourceScope[],
|
|
845
862
|
lights: ExtractedLights,
|
|
846
863
|
fog: ExtractedVolumetricFog | undefined,
|
|
847
864
|
): SpotLightProjectorFrameContext | undefined {
|
|
@@ -982,15 +999,15 @@ interface FrameClockSample {
|
|
|
982
999
|
|
|
983
1000
|
/** Read the render sample clock from the camera's composition world once per frame. */
|
|
984
1001
|
function frameClockSample(
|
|
985
|
-
world:
|
|
986
|
-
worlds: readonly
|
|
1002
|
+
world: RenderResourceScope,
|
|
1003
|
+
worlds: readonly RenderResourceScope[],
|
|
987
1004
|
camera: CameraSnapshot,
|
|
988
1005
|
sampleTimeSeconds?: number,
|
|
989
1006
|
): FrameClockSample {
|
|
990
1007
|
const owner = worlds[camera.worldId ?? 0] ?? world;
|
|
991
1008
|
const invalidSampleTime = sampleTimeSeconds !== undefined && !Number.isFinite(sampleTimeSeconds);
|
|
992
1009
|
try {
|
|
993
|
-
const clock = owner
|
|
1010
|
+
const clock = renderTime(owner);
|
|
994
1011
|
return {
|
|
995
1012
|
deltaSeconds: Number.isFinite(clock.delta) ? Math.max(0, clock.delta) : 0,
|
|
996
1013
|
// Keep the raw host sample even when ECS accepted only a clamped
|
|
@@ -1007,7 +1024,7 @@ function frameClockSample(
|
|
|
1007
1024
|
invalidSampleTime,
|
|
1008
1025
|
};
|
|
1009
1026
|
} catch {
|
|
1010
|
-
// Test and recovery callers may provide a minimal
|
|
1027
|
+
// Test and recovery callers may provide a minimal RenderResourceScope-shaped owner. An
|
|
1011
1028
|
// absent clock is an invalid temporal pair and therefore safely resets.
|
|
1012
1029
|
return {
|
|
1013
1030
|
deltaSeconds: 0,
|
|
@@ -1372,7 +1389,7 @@ function updateVolumetricFogInspection(
|
|
|
1372
1389
|
|
|
1373
1390
|
export function recordFrame(
|
|
1374
1391
|
internals: RenderSystemInternals,
|
|
1375
|
-
world:
|
|
1392
|
+
world: RenderResourceScope,
|
|
1376
1393
|
cameras: CameraSnapshot[],
|
|
1377
1394
|
lights: ExtractedLights,
|
|
1378
1395
|
renderables: readonly RenderableSnapshot[],
|
|
@@ -1392,7 +1409,7 @@ export function recordFrame(
|
|
|
1392
1409
|
// the per-world extract stage). Optional + defaulting to `[world]` keeps the
|
|
1393
1410
|
// pre-split single-world identity path (worldId always 0) byte-for-byte and
|
|
1394
1411
|
// the existing unit-test callers (which pass a single mock world) valid.
|
|
1395
|
-
worlds: readonly
|
|
1412
|
+
worlds: readonly RenderResourceScope[] = [world],
|
|
1396
1413
|
profilePhase?: RecordProfileRunner,
|
|
1397
1414
|
gpuDriven?: {
|
|
1398
1415
|
readonly owner: GpuDrivenProduction;
|
|
@@ -2270,7 +2287,7 @@ export function recordFrame(
|
|
|
2270
2287
|
activeVolumetricFogSignature = resolvedHistory.signature;
|
|
2271
2288
|
const previousTime = frameState.volumetricFogHistorySignature?.worldTimeSeconds;
|
|
2272
2289
|
const currentTime = resolvedHistory.signature.worldTimeSeconds;
|
|
2273
|
-
// Adjacent UBO lanes: validity,
|
|
2290
|
+
// Adjacent UBO lanes: validity, RenderResourceScope time, elapsed time since accepted history.
|
|
2274
2291
|
const historyParams = new Float32Array([
|
|
2275
2292
|
activeVolumetricFogContext.historyValid ? 1 : 0,
|
|
2276
2293
|
currentTime ?? 0,
|
|
@@ -2842,7 +2859,7 @@ export function recordFrame(
|
|
|
2842
2859
|
// the picture authority: an identity frame publishes an identity
|
|
2843
2860
|
// mapping, while a failed enable/disable candidate retains the previous
|
|
2844
2861
|
// mapping together with its old picture. Never pair an LKG graph with
|
|
2845
|
-
// the live
|
|
2862
|
+
// the live RenderResourceScope's newer camera component.
|
|
2846
2863
|
// The exact mapping used to populate the accepted graph's UBO is the
|
|
2847
2864
|
// only mapping promoted with its receipt. This keeps an identity frame,
|
|
2848
2865
|
// a retained barrel LKG and a normal nonzero frame on one context.
|
|
@@ -2855,7 +2872,10 @@ export function recordFrame(
|
|
|
2855
2872
|
// prior tick into the next topology.
|
|
2856
2873
|
acknowledgeRenderFeatureSubmission(getRenderFeatureGraphState(internals).plans);
|
|
2857
2874
|
}
|
|
2858
|
-
if (
|
|
2875
|
+
if (
|
|
2876
|
+
cubeCapture !== undefined &&
|
|
2877
|
+
cubeCaptureWork.some((work) => work.physical.descriptor.shape === 'cube')
|
|
2878
|
+
) {
|
|
2859
2879
|
const completed = cubeCapture.scheduler.completeSubmission(submitted, completion);
|
|
2860
2880
|
if (!completed.ok) internals.errorRegistry.fire(completed.error);
|
|
2861
2881
|
}
|
|
@@ -2980,7 +3000,7 @@ function readWorldState(lease: RenderReadLease): DirectionalShadowWorldState {
|
|
|
2980
3000
|
|
|
2981
3001
|
function sameWorldState(
|
|
2982
3002
|
cached: DirectionalShadowCache,
|
|
2983
|
-
worlds: readonly
|
|
3003
|
+
worlds: readonly RenderResourceScope[],
|
|
2984
3004
|
leases: readonly RenderReadLease[] | undefined,
|
|
2985
3005
|
): boolean {
|
|
2986
3006
|
if (leases === undefined || leases.length !== worlds.length) return false;
|
|
@@ -2999,7 +3019,7 @@ function sameWorldState(
|
|
|
2999
3019
|
changes = lease.readChanges(cachedState.version);
|
|
3000
3020
|
} catch {
|
|
3001
3021
|
// Treat malformed or foreign version evidence as stale and rebuild the
|
|
3002
|
-
// atlas rather than reaching through
|
|
3022
|
+
// atlas rather than reaching through RenderResourceScope for a second mutation clock.
|
|
3003
3023
|
return false;
|
|
3004
3024
|
}
|
|
3005
3025
|
if (
|
|
@@ -3047,7 +3067,7 @@ function sameDirectionalShadowQuality(
|
|
|
3047
3067
|
function prepareDirectionalShadowCache(
|
|
3048
3068
|
internals: RenderSystemInternals,
|
|
3049
3069
|
frameState: RenderFrameState,
|
|
3050
|
-
worlds: readonly
|
|
3070
|
+
worlds: readonly RenderResourceScope[],
|
|
3051
3071
|
leases: readonly RenderReadLease[] | undefined,
|
|
3052
3072
|
lights: ExtractedLights,
|
|
3053
3073
|
shadowMapSize: number | undefined,
|
|
@@ -3102,7 +3122,7 @@ function prepareDirectionalShadowCache(
|
|
|
3102
3122
|
if (leases === undefined || leases.length !== worlds.length) {
|
|
3103
3123
|
// Direct record-stage test harnesses may omit the host-owned leases. They
|
|
3104
3124
|
// still exercise the real shadow encoder, but without the ECS read owner
|
|
3105
|
-
// they must conservatively rebuild rather than inspect
|
|
3125
|
+
// they must conservatively rebuild rather than inspect RenderResourceScope internals.
|
|
3106
3126
|
return { reuse: false, next: null };
|
|
3107
3127
|
}
|
|
3108
3128
|
const worldStateTokens = leases.map(readWorldState);
|
package/src/record/helpers.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
+
import type { RenderResourceScope } from '../publication/resource-scope';
|
|
1
2
|
// @forgeax/engine-runtime - RenderSystem record stage: helpers.
|
|
2
3
|
// Extracted from render-system-record.ts (feat-20260704 M3/w17, pure move).
|
|
3
4
|
|
|
4
5
|
import { resolveAssetHandle } from '@forgeax/engine-assets-runtime';
|
|
5
|
-
import type { World } from '@forgeax/engine-ecs';
|
|
6
6
|
import { type Mat4, mat4 } from '@forgeax/engine-math';
|
|
7
7
|
import type { EquirectAsset } from '@forgeax/engine-types';
|
|
8
8
|
import { toShared } from '@forgeax/engine-types';
|
|
@@ -140,7 +140,7 @@ export function warnMultiSkybox(
|
|
|
140
140
|
*/
|
|
141
141
|
export function driveLazyEquirectProjection(
|
|
142
142
|
internals: RenderSystemInternals,
|
|
143
|
-
world:
|
|
143
|
+
world: RenderResourceScope,
|
|
144
144
|
frameState: Pick<RenderFrameState, 'firedEquirectProjectionFailedHandles'>,
|
|
145
145
|
equirectHandle: number,
|
|
146
146
|
): void {
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
+
import type { RenderResourceScope } from '../publication/resource-scope';
|
|
2
|
+
import { resolveSpriteInstancesBuffer } from './sprite-instance-buffer';
|
|
1
3
|
// @forgeax/engine-runtime - RenderSystem record stage: main-pass geometry draws.
|
|
2
4
|
// feat-20260704 M5/w31: further-split from main-pass.ts (AC-05 <=1500 lines/file).
|
|
3
5
|
// recordGeometryDraws + resolveGeometryInstanceBuffer, moved verbatim.
|
|
4
6
|
|
|
5
|
-
import type { World } from '@forgeax/engine-ecs';
|
|
6
7
|
import {
|
|
7
8
|
type BindGroup,
|
|
8
9
|
type Buffer,
|
|
@@ -495,7 +496,7 @@ export function recordGeometryDraws(
|
|
|
495
496
|
materialSlot: number,
|
|
496
497
|
submeshMaterial: MaterialSnapshot,
|
|
497
498
|
entityKey: number,
|
|
498
|
-
materialWorld:
|
|
499
|
+
materialWorld: RenderResourceScope,
|
|
499
500
|
materialShaderId?: string,
|
|
500
501
|
) => BindGroup,
|
|
501
502
|
passKind: PassKind = 'forward',
|
|
@@ -1916,6 +1917,24 @@ export function resolveGeometryInstanceBuffer(
|
|
|
1916
1917
|
): readonly GeometryInstanceDraw[] | null {
|
|
1917
1918
|
const { runtime, pipelineState, frameState } = c;
|
|
1918
1919
|
const inst = entry.source.instances;
|
|
1920
|
+
if (entry.source.spriteInstances !== undefined) {
|
|
1921
|
+
const { buffer, count } = resolveSpriteInstancesBuffer(
|
|
1922
|
+
c,
|
|
1923
|
+
entry,
|
|
1924
|
+
pipelineState.identityInstanceBuffer,
|
|
1925
|
+
0,
|
|
1926
|
+
);
|
|
1927
|
+
return count === 0
|
|
1928
|
+
? []
|
|
1929
|
+
: [
|
|
1930
|
+
{
|
|
1931
|
+
instanceBuffer: buffer,
|
|
1932
|
+
instanceBindGroup: resolveGeometryInstancesBindGroup(c, buffer, undefined),
|
|
1933
|
+
probeOffset: -1,
|
|
1934
|
+
instanceCount: count,
|
|
1935
|
+
},
|
|
1936
|
+
];
|
|
1937
|
+
}
|
|
1919
1938
|
const probeBinding =
|
|
1920
1939
|
!useProbeBlend ||
|
|
1921
1940
|
!runtime.device.caps.storageBuffer ||
|
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
import { transmissionBackdropAvailable } from '../assembly/device-feature-admission';
|
|
2
2
|
import { getOrCreateIblCache } from '../ibl/IblPipelineCache';
|
|
3
|
+
import type { RenderResourceScope } from '../publication/resource-scope';
|
|
3
4
|
import type { _InternalRenderPipelineContext } from './render-context';
|
|
4
5
|
// @forgeax/engine-runtime - RenderSystem record stage: main-pass-material.
|
|
5
6
|
// Extracted from render-system-record.ts (feat-20260704 M3/w17, pure move).
|
|
6
7
|
|
|
7
8
|
import { resolveAssetHandle } from '@forgeax/engine-assets-runtime';
|
|
8
|
-
import type { EntityHandle
|
|
9
|
+
import type { EntityHandle } from '@forgeax/engine-ecs';
|
|
9
10
|
import {
|
|
10
|
-
|
|
11
|
-
type
|
|
11
|
+
VIDEO_SOURCE_PROVIDER_KEY,
|
|
12
|
+
type VideoSourceProvider,
|
|
13
|
+
videoSourceExtent,
|
|
12
14
|
} from '@forgeax/engine-graphics-extras';
|
|
13
15
|
import {
|
|
14
16
|
type BindGroup,
|
|
@@ -261,11 +263,11 @@ function materialDiagnosticsEnabled(): boolean {
|
|
|
261
263
|
}
|
|
262
264
|
|
|
263
265
|
export function residentTextureView(
|
|
264
|
-
world:
|
|
266
|
+
world: RenderResourceScope,
|
|
265
267
|
store: GpuResidencyCache,
|
|
266
268
|
runtime: RenderSystemRuntime,
|
|
267
269
|
handle: Handle<'TextureAsset', 'shared'>,
|
|
268
|
-
worldId:
|
|
270
|
+
worldId: RenderResourceScope | number = world,
|
|
269
271
|
): TextureView | undefined {
|
|
270
272
|
const podRes = resolveAssetHandle<TextureAsset>(world, handle);
|
|
271
273
|
const diagnosticsEnabled = materialDiagnosticsEnabled();
|
|
@@ -323,11 +325,11 @@ export function residentTextureView(
|
|
|
323
325
|
}
|
|
324
326
|
|
|
325
327
|
function residentSampler(
|
|
326
|
-
world:
|
|
328
|
+
world: RenderResourceScope,
|
|
327
329
|
store: GpuResidencyCache,
|
|
328
330
|
runtime: RenderSystemRuntime,
|
|
329
331
|
handle: Handle<'SamplerAsset', 'shared'>,
|
|
330
|
-
worldId:
|
|
332
|
+
worldId: RenderResourceScope | number = world,
|
|
331
333
|
): Sampler | undefined {
|
|
332
334
|
const podRes = resolveAssetHandle<SamplerAsset>(world, handle);
|
|
333
335
|
if (!podRes.ok) return undefined;
|
|
@@ -344,7 +346,7 @@ function residentSampler(
|
|
|
344
346
|
// transient DynamicTextureStore, NOT the static `residentTextureView` /
|
|
345
347
|
// `ensureResident` cache (video never enters that switch; AC-08).
|
|
346
348
|
//
|
|
347
|
-
// Per frame: ask the host-registered
|
|
349
|
+
// Per frame: ask the host-registered VideoSourceProvider (RenderResourceScope Resource,
|
|
348
350
|
// D-1) for this entity's HTMLVideoElement, upload its current frame via
|
|
349
351
|
// `store.uploadFrame` (copyExternalImageToTexture), and return the resulting
|
|
350
352
|
// view. When the provider is absent / returns no element / the element has no
|
|
@@ -404,7 +406,7 @@ function clearVideoUploadFailureEpisode(
|
|
|
404
406
|
}
|
|
405
407
|
|
|
406
408
|
export function videoTextureView(
|
|
407
|
-
world:
|
|
409
|
+
world: RenderResourceScope,
|
|
408
410
|
store: DynamicTextureStore | undefined,
|
|
409
411
|
runtime: RenderSystemRuntime,
|
|
410
412
|
entityKey: number,
|
|
@@ -412,10 +414,14 @@ export function videoTextureView(
|
|
|
412
414
|
highPerfAvailable: boolean,
|
|
413
415
|
): TextureView | undefined {
|
|
414
416
|
if (store === undefined) return undefined;
|
|
415
|
-
const provider =
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
417
|
+
const provider =
|
|
418
|
+
!('resolveAsset' in world) && world.hasResource(VIDEO_SOURCE_PROVIDER_KEY)
|
|
419
|
+
? world.getResource<VideoSourceProvider>(VIDEO_SOURCE_PROVIDER_KEY)
|
|
420
|
+
: undefined;
|
|
421
|
+
const element =
|
|
422
|
+
'resolveAsset' in world
|
|
423
|
+
? world.videoFrame(entityKey, clip)
|
|
424
|
+
: provider?.getSource(entityKey as EntityHandle, clip);
|
|
419
425
|
// AC-10 double-miss: a VideoPlayer entity can reach NEITHER upload path this
|
|
420
426
|
// frame — no host HTMLVideoElement (general copyExternalImageToTexture path)
|
|
421
427
|
// AND no high-perf GPUExternalTexture path. This is the genuine "this backend
|
|
@@ -441,13 +447,9 @@ export function videoTextureView(
|
|
|
441
447
|
clearVideoUploadFailureEpisode(store, entityKey, clip);
|
|
442
448
|
return store.getView(clip);
|
|
443
449
|
}
|
|
444
|
-
const
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
// current frame. WebGPU rejects copyExternalImageToTexture in that window
|
|
448
|
-
// because the video element has no back resource yet; keep the previous
|
|
449
|
-
// frame/default view until HAVE_CURRENT_DATA (2) is reached.
|
|
450
|
-
if (width <= 0 || height <= 0 || element.readyState < 2) return store.getView(clip);
|
|
450
|
+
const extent = videoSourceExtent(element);
|
|
451
|
+
if (extent === undefined) return store.getView(clip);
|
|
452
|
+
const { width, height } = extent;
|
|
451
453
|
const uploaded = store.uploadFrame(clip, element, width, height);
|
|
452
454
|
if (uploaded === undefined) return store.getView(clip);
|
|
453
455
|
if (!uploaded.ok) {
|
|
@@ -592,7 +594,7 @@ function writeNumericParamValue(
|
|
|
592
594
|
export function applyMaterialTextureUvScales(
|
|
593
595
|
payload: MaterialUboPayload,
|
|
594
596
|
material: MaterialSnapshot,
|
|
595
|
-
world:
|
|
597
|
+
world: RenderResourceScope,
|
|
596
598
|
): void {
|
|
597
599
|
const f32 = materialUboFloatView(payload);
|
|
598
600
|
const coordinateSchema = materialCoordinateSchema(material);
|
|
@@ -940,14 +942,14 @@ export function applyParamSchemaDefaultsToUbo(
|
|
|
940
942
|
export interface PerSubmeshMaterialBgDeps {
|
|
941
943
|
readonly runtime: RenderSystemRuntime;
|
|
942
944
|
readonly pipelineState: PipelineState;
|
|
943
|
-
readonly world:
|
|
945
|
+
readonly world: RenderResourceScope;
|
|
944
946
|
readonly store: GpuResidencyCache;
|
|
945
947
|
readonly materialSlice: number;
|
|
946
948
|
readonly videoHighPerfAvailable: boolean;
|
|
947
949
|
readonly skylightResources: SkylightBindGroupResources;
|
|
948
950
|
readonly resolveRenderTargetTextureSource?: RenderSystemRuntime['resolveRenderTargetTextureSource'];
|
|
949
951
|
readonly resolveReflectionProbeResources?: (
|
|
950
|
-
materialWorld:
|
|
952
|
+
materialWorld: RenderResourceScope,
|
|
951
953
|
entityKey: number,
|
|
952
954
|
) => { readonly resources: SkylightBindGroupResources; readonly probeIndex: number } | undefined;
|
|
953
955
|
readonly materialBgShared: Map<string, WeakMap<object, unknown>>;
|
|
@@ -979,7 +981,7 @@ function recordIblMaterialBinding(
|
|
|
979
981
|
if (receipt === undefined) return;
|
|
980
982
|
const skylightBindingStart = entries.findIndex((entry) => entry.binding === iblStart);
|
|
981
983
|
if (skylightBindingStart < 0) return;
|
|
982
|
-
const iblEntries = entries.slice(skylightBindingStart, skylightBindingStart +
|
|
984
|
+
const iblEntries = entries.slice(skylightBindingStart, skylightBindingStart + 6);
|
|
983
985
|
const projected: IblBindingEntryInspection[] = [];
|
|
984
986
|
for (const entry of iblEntries) {
|
|
985
987
|
if (entry.resource.kind === 'externalTexture') continue;
|
|
@@ -1018,7 +1020,15 @@ export function isMaterialBgAssemblyCacheHit(
|
|
|
1018
1020
|
sceneMaterialBuffer?: Buffer,
|
|
1019
1021
|
surfaceRawDepthView?: TextureView | null,
|
|
1020
1022
|
): cached is MaterialBgAssemblyCacheEntry {
|
|
1021
|
-
|
|
1023
|
+
// Logical target sources keep their identity when a resize promotes a new
|
|
1024
|
+
// physical view. Resolve those views each frame; the lower binding cache is
|
|
1025
|
+
// keyed by the actual GPU resources and still reuses unchanged bindings.
|
|
1026
|
+
if (
|
|
1027
|
+
transmissionBackdropView != null ||
|
|
1028
|
+
surfaceRawDepthView != null ||
|
|
1029
|
+
(material.textureSources?.size ?? 0) > 0
|
|
1030
|
+
)
|
|
1031
|
+
return false;
|
|
1022
1032
|
return (
|
|
1023
1033
|
cached?.material === material &&
|
|
1024
1034
|
cached.materialResourceEpoch === materialResourceEpoch &&
|
|
@@ -1031,7 +1041,6 @@ export function isMaterialBgAssemblyCacheHit(
|
|
|
1031
1041
|
cached.skylightResources.skylightPrefilterView === skylightResources.skylightPrefilterView &&
|
|
1032
1042
|
cached.skylightResources.prefilterSampler === skylightResources.prefilterSampler &&
|
|
1033
1043
|
cached.skylightResources.brdfLutView === skylightResources.brdfLutView &&
|
|
1034
|
-
cached.skylightResources.brdfLutSampler === skylightResources.brdfLutSampler &&
|
|
1035
1044
|
cached.skylightResources.intensityBuffer === skylightResources.intensityBuffer
|
|
1036
1045
|
);
|
|
1037
1046
|
}
|
|
@@ -1040,7 +1049,7 @@ export function buildPerSubmeshMaterialBg(
|
|
|
1040
1049
|
deps: PerSubmeshMaterialBgDeps,
|
|
1041
1050
|
submeshMaterial: MaterialSnapshot,
|
|
1042
1051
|
entityKey: number,
|
|
1043
|
-
materialWorld:
|
|
1052
|
+
materialWorld: RenderResourceScope = deps.world,
|
|
1044
1053
|
materialShaderId: string | undefined = submeshMaterial.materialShaderId,
|
|
1045
1054
|
): BindGroup {
|
|
1046
1055
|
const {
|
|
@@ -1175,10 +1184,6 @@ export function buildPerSubmeshMaterialBg(
|
|
|
1175
1184
|
},
|
|
1176
1185
|
{
|
|
1177
1186
|
binding: 6 + smUserRegionFields.length * 2,
|
|
1178
|
-
resource: { kind: 'sampler', value: effectiveSkylightResources.brdfLutSampler },
|
|
1179
|
-
},
|
|
1180
|
-
{
|
|
1181
|
-
binding: 7 + smUserRegionFields.length * 2,
|
|
1182
1187
|
resource: {
|
|
1183
1188
|
kind: 'buffer',
|
|
1184
1189
|
value: { buffer: effectiveSkylightResources.intensityBuffer },
|
|
@@ -1429,6 +1434,7 @@ export function buildPerSubmeshMaterialBg(
|
|
|
1429
1434
|
if (
|
|
1430
1435
|
smMaterialHandle !== undefined &&
|
|
1431
1436
|
!smHasVideoFields &&
|
|
1437
|
+
(submeshMaterial.textureSources?.size ?? 0) === 0 &&
|
|
1432
1438
|
materialResourcesResident &&
|
|
1433
1439
|
!hasActiveTransmissionBackdrop
|
|
1434
1440
|
) {
|
|
@@ -1532,7 +1538,6 @@ export function resolveMaterialSkylight(
|
|
|
1532
1538
|
prefilterView: activeViews.pref,
|
|
1533
1539
|
prefilterSampler: skylightFallback.sampler,
|
|
1534
1540
|
brdfLutView: activeViews.brdf,
|
|
1535
|
-
brdfLutSampler: skylightFallback.sampler,
|
|
1536
1541
|
intensityBuffer: skylightFallback.intensityBuffer,
|
|
1537
1542
|
}
|
|
1538
1543
|
: {
|
|
@@ -1541,7 +1546,6 @@ export function resolveMaterialSkylight(
|
|
|
1541
1546
|
prefilterView: skylightFallback.prefilterView,
|
|
1542
1547
|
prefilterSampler: skylightFallback.sampler,
|
|
1543
1548
|
brdfLutView: skylightFallback.brdfLutView,
|
|
1544
|
-
brdfLutSampler: skylightFallback.sampler,
|
|
1545
1549
|
intensityBuffer: skylightFallback.intensityBuffer,
|
|
1546
1550
|
};
|
|
1547
1551
|
return { skylightResources, activeViews };
|