@forgeax/engine-render 0.1.34 → 0.1.36
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 +69 -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/assembly/webgpu-vertex-layouts.d.ts.map +1 -1
- package/dist/authoring.mjs +2 -4
- package/dist/authoring.mjs.map +1 -1
- package/dist/chunk-2OZAS3WU.mjs +3489 -0
- package/dist/chunk-2OZAS3WU.mjs.map +1 -0
- package/dist/{chunk-UI5SFODX.mjs → chunk-BZQ4CDRF.mjs} +2338 -1991
- package/dist/chunk-BZQ4CDRF.mjs.map +1 -0
- package/dist/{chunk-MKDIT2EM.mjs → chunk-CJOV2XLO.mjs} +216 -261
- package/dist/chunk-CJOV2XLO.mjs.map +1 -0
- package/dist/chunk-D6WSBXJ2.mjs +1842 -0
- package/dist/chunk-D6WSBXJ2.mjs.map +1 -0
- package/dist/{chunk-HEB564WF.mjs → chunk-DRF6OULX.mjs} +4 -4
- package/dist/{chunk-HEB564WF.mjs.map → chunk-DRF6OULX.mjs.map} +1 -1
- package/dist/{chunk-OCDLEI6I.mjs → chunk-OB5WAFYH.mjs} +117 -5
- package/dist/chunk-OB5WAFYH.mjs.map +1 -0
- package/dist/{chunk-ODZWR6JQ.mjs → chunk-OEYKKMXG.mjs} +2042 -27
- package/dist/chunk-OEYKKMXG.mjs.map +1 -0
- package/dist/chunk-RIPAEGI6.mjs +48 -0
- package/dist/chunk-RIPAEGI6.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 +936 -2140
- package/dist/construct-renderer.mjs.map +1 -1
- package/dist/device/device-scope.d.ts.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/particle-mesh-layout.d.ts +19 -0
- package/dist/features/particle-mesh-layout.d.ts.map +1 -0
- package/dist/features/plan.d.ts +2 -0
- package/dist/features/plan.d.ts.map +1 -1
- package/dist/features/types.d.ts +8 -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/production-raster.d.ts +1 -1
- package/dist/gpu-driven/production-raster.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/gpu-driven/shadow-views.d.ts +1 -1
- package/dist/gpu-driven/shadow-views.d.ts.map +1 -1
- package/dist/gpu-driven/view-gpu.d.ts +1 -1
- package/dist/gpu-driven/view-gpu.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 +542 -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 +34 -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 +2 -3
- package/dist/record/prepared-material-bindings.d.ts.map +1 -1
- package/dist/record/render-context.d.ts +4 -2
- package/dist/record/render-context.d.ts.map +1 -1
- package/dist/record/shadow-pass.d.ts +2 -2
- package/dist/record/shadow-pass.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 -12
- 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/dist/typed-shadow-passes.d.ts.map +1 -1
- 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__/device-scope-lifecycle.unit.test.ts +26 -0
- package/src/__tests__/gpu-driven-pbr.dawn.test.ts +3 -4
- package/src/__tests__/gpu-driven-production.integration.test.ts +18 -1
- package/src/__tests__/gpu-driven-shadow-views.unit.test.ts +23 -0
- 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__/material-vertex-texture.browser.test.ts +7 -0
- package/src/__tests__/material-vertex-texture.dawn.test.ts +7 -0
- package/src/__tests__/material-vertex-texture.fixture.ts +31 -0
- 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__/recovery-candidate-prepare.contract.test.ts +5 -0
- package/src/__tests__/render-error-code-owner.test-d.ts +1 -0
- package/src/__tests__/renderer-factory-material-contract.unit.test.ts +107 -5
- package/src/__tests__/runtime-material-program.integration.test.ts +79 -0
- package/src/__tests__/vertex-layouts-ssot.unit.test.ts +23 -3
- 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 +101 -70
- package/src/assembly/webgpu-vertex-layouts.ts +2 -9
- package/src/cloud/frame-context.ts +2 -2
- package/src/device/device-scope.ts +3 -0
- 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/particle-mesh-layout.ts +25 -0
- package/src/features/plan.ts +2 -0
- package/src/features/types.ts +8 -0
- package/src/glyph-text-layout-system.ts +2 -2
- package/src/gpu-driven/production-raster.ts +9 -3
- package/src/gpu-driven/shadow-ownership.ts +3 -3
- package/src/gpu-driven/shadow-views.ts +27 -2
- package/src/gpu-driven/view-gpu.ts +5 -0
- 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 +15 -18
- 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 +173 -0
- package/src/publication/__tests__/programs.unit.test.ts +25 -0
- package/src/publication/__tests__/publication.integration.test.ts +415 -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 +645 -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__/prepared-runtime-material.integration.test.ts +134 -0
- 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 +87 -28
- 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 +16 -37
- package/src/record/render-context.ts +4 -2
- package/src/record/shadow-pass.ts +65 -7
- 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 +11 -207
- package/src/record/view-ubo.ts +1 -1
- package/src/record/volume-params.ts +6 -6
- package/src/recovery/render-system-candidate.ts +10 -18
- package/src/render-contract.ts +6 -1
- package/src/render-system-extract-tail.ts +48 -23
- package/src/render-system-extract.ts +11 -2
- 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 -54
- 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/src/typed-shadow-passes.ts +36 -5
- 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,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 };
|
|
@@ -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 sprite draws.
|
|
2
4
|
// feat-20260704 M5/w31: further-split from main-pass.ts (AC-05 <=1500 lines/file).
|
|
3
5
|
// recordSpritePass + sprite entity/transparent/instance-buffer helpers, moved verbatim.
|
|
4
6
|
|
|
5
|
-
import type { World } from '@forgeax/engine-ecs';
|
|
6
7
|
import {
|
|
7
8
|
type BindGroup,
|
|
8
9
|
type Buffer,
|
|
@@ -21,11 +22,7 @@ import type { InstanceBufferCacheEntry } from '../instance-buffer-cache';
|
|
|
21
22
|
import { SPRITE_PREMULTIPLIED_ALPHA_BLEND } from '../materials';
|
|
22
23
|
import { SPRITE_PASS_PER_INSTANCE_REGION_VARIANT_SET } from '../pbr-pipeline';
|
|
23
24
|
import { buildBeginRenderPassDescriptor, standardTopologyVariantSet } from '../pipeline-spec';
|
|
24
|
-
import type {
|
|
25
|
-
DispatchEntry,
|
|
26
|
-
MaterialSnapshot,
|
|
27
|
-
SpriteInstancesSnapshot,
|
|
28
|
-
} from '../render-system-extract';
|
|
25
|
+
import type { DispatchEntry, MaterialSnapshot } from '../render-system-extract';
|
|
29
26
|
import { resolveFoldInstanceBuffer } from './fold-instance-buffer';
|
|
30
27
|
import { worldEntityKey } from './frame-snapshot';
|
|
31
28
|
import { recordGeometryDraws, resolveGeometryInstancesBindGroup } from './main-pass-geometry';
|
|
@@ -37,55 +34,6 @@ import {
|
|
|
37
34
|
import type { _InternalRenderPipelineContext } from './render-context';
|
|
38
35
|
import { MATERIAL_PER_ENTITY_STRIDE } from './render-context';
|
|
39
36
|
|
|
40
|
-
export type { SpriteInstancesSnapshot };
|
|
41
|
-
|
|
42
|
-
/**
|
|
43
|
-
* Build the interleaved sprite instance payload consumed by this record owner.
|
|
44
|
-
* The extract stage validates the two packed arrays before they reach this
|
|
45
|
-
* function, so the record path has one source of count-mismatch errors.
|
|
46
|
-
*/
|
|
47
|
-
export function interleaveSpriteInstanceBuffer(
|
|
48
|
-
transforms: Float32Array,
|
|
49
|
-
regions: Float32Array,
|
|
50
|
-
includePrevious = false,
|
|
51
|
-
): Float32Array {
|
|
52
|
-
const count = transforms.length / 16;
|
|
53
|
-
const stride = includePrevious ? 36 : 20;
|
|
54
|
-
const regionOffset = includePrevious ? 32 : 16;
|
|
55
|
-
const out = new Float32Array(count * stride);
|
|
56
|
-
for (let i = 0; i < count; i++) {
|
|
57
|
-
const dstBase = i * stride;
|
|
58
|
-
const transformBase = i * 16;
|
|
59
|
-
const regionBase = i * 4;
|
|
60
|
-
for (let k = 0; k < 16; k++) out[dstBase + k] = transforms[transformBase + k] ?? 0;
|
|
61
|
-
if (includePrevious) {
|
|
62
|
-
for (let k = 0; k < 16; k++) {
|
|
63
|
-
out[dstBase + 16 + k] = transforms[transformBase + k] ?? 0;
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
for (let k = 0; k < 4; k++) {
|
|
67
|
-
out[dstBase + regionOffset + k] = regions[regionBase + k] ?? 0;
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
return out;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
/**
|
|
74
|
-
* Check whether the existing per-entity sprite buffer still matches the
|
|
75
|
-
* extract snapshot and interleaved byte count.
|
|
76
|
-
*/
|
|
77
|
-
export function spriteInstancesCacheHit(
|
|
78
|
-
entry: InstanceBufferCacheEntry | undefined,
|
|
79
|
-
snapshot: SpriteInstancesSnapshot,
|
|
80
|
-
requestedBytes: number,
|
|
81
|
-
): boolean {
|
|
82
|
-
return (
|
|
83
|
-
entry !== undefined &&
|
|
84
|
-
entry.uploadedArchVersion === snapshot.archVersion &&
|
|
85
|
-
entry.uploadedByteLength === requestedBytes
|
|
86
|
-
);
|
|
87
|
-
}
|
|
88
|
-
|
|
89
37
|
/**
|
|
90
38
|
* Decide whether the LDR record needs the transparent sprite sub-pass. This
|
|
91
39
|
* remains beside the sprite record owner so the frame stage and draw stage
|
|
@@ -144,7 +92,7 @@ export function recordSpritePass(
|
|
|
144
92
|
materialSlot: number,
|
|
145
93
|
submeshMaterial: MaterialSnapshot,
|
|
146
94
|
entityKey: number,
|
|
147
|
-
materialWorld:
|
|
95
|
+
materialWorld: RenderResourceScope,
|
|
148
96
|
materialShaderId?: string,
|
|
149
97
|
) => BindGroup,
|
|
150
98
|
graphPass?: RhiRenderPassEncoder,
|
|
@@ -382,7 +330,7 @@ function recordSpriteTransparentPbrDraws(
|
|
|
382
330
|
slot: number,
|
|
383
331
|
material: MaterialSnapshot,
|
|
384
332
|
entityKey: number,
|
|
385
|
-
world:
|
|
333
|
+
world: RenderResourceScope,
|
|
386
334
|
shader?: string,
|
|
387
335
|
) => BindGroup,
|
|
388
336
|
meshGroup2: BindGroup | null,
|
|
@@ -455,7 +403,7 @@ function recordSpriteEntityDraws(
|
|
|
455
403
|
materialSlot: number,
|
|
456
404
|
material: MaterialSnapshot,
|
|
457
405
|
entityKey: number,
|
|
458
|
-
materialWorld:
|
|
406
|
+
materialWorld: RenderResourceScope,
|
|
459
407
|
) => BindGroup,
|
|
460
408
|
spritePH: RenderPipeline | null,
|
|
461
409
|
spritePH_withRegion: RenderPipeline | null,
|
|
@@ -760,100 +708,6 @@ function recordSpriteEntityDraws(
|
|
|
760
708
|
}
|
|
761
709
|
}
|
|
762
710
|
|
|
763
|
-
/**
|
|
764
|
-
* feat-20260704 M3/w19: resolve the interleaved SpriteInstances (@group(3))
|
|
765
|
-
* buffer + instanceCount for a sprite entity in the LDR blend sub-pass,
|
|
766
|
-
* extracted verbatim from recordSpriteEntityDraws. Uploads the interleaved
|
|
767
|
-
* mat4 + per-instance UV region transforms (cache-keyed on the snapshot); on
|
|
768
|
-
* over-cap fires the structured limit-exceeded error and leaves the passed-in
|
|
769
|
-
* fallback buffer/count. Returns the resolved (or unchanged) buffer + count.
|
|
770
|
-
*
|
|
771
|
-
* @internal
|
|
772
|
-
*/
|
|
773
|
-
function resolveSpriteInstancesBuffer(
|
|
774
|
-
c: _InternalRenderPipelineContext,
|
|
775
|
-
spriteEntry: _InternalRenderPipelineContext['validatedOrdered'][number],
|
|
776
|
-
fallbackBuffer: Buffer,
|
|
777
|
-
fallbackCount: number,
|
|
778
|
-
): { buffer: Buffer; count: number } {
|
|
779
|
-
const { runtime, frameState } = c;
|
|
780
|
-
let buffer = fallbackBuffer;
|
|
781
|
-
let count = fallbackCount;
|
|
782
|
-
const spriteInstancesSnap: SpriteInstancesSnapshot | undefined =
|
|
783
|
-
spriteEntry.source.spriteInstances;
|
|
784
|
-
if (spriteInstancesSnap !== undefined) {
|
|
785
|
-
const uniformFallback = runtime.device.caps.storageBuffer === false;
|
|
786
|
-
const interleaved = interleaveSpriteInstanceBuffer(
|
|
787
|
-
spriteInstancesSnap.transforms,
|
|
788
|
-
spriteInstancesSnap.regions,
|
|
789
|
-
!uniformFallback,
|
|
790
|
-
);
|
|
791
|
-
const requestedBytes = interleaved.byteLength;
|
|
792
|
-
const cap = runtime.device.limits.maxStorageBufferBindingSize;
|
|
793
|
-
if (typeof cap === 'number' && requestedBytes > cap) {
|
|
794
|
-
runtime.errorRegistry.fire(
|
|
795
|
-
new RhiError({
|
|
796
|
-
code: 'limit-exceeded',
|
|
797
|
-
expected: `requestedBytes (${requestedBytes}) <= maxStorageBufferBindingSize (${cap})`,
|
|
798
|
-
hint: 'reduce SpriteInstances instance count to fit within device.limits.maxStorageBufferBindingSize (144 bytes per instance: current mat4 64B + previous mat4 64B + region 16B)',
|
|
799
|
-
detail: {
|
|
800
|
-
maxStorageBufferBindingSize: cap,
|
|
801
|
-
requestedBytes,
|
|
802
|
-
},
|
|
803
|
-
}),
|
|
804
|
-
);
|
|
805
|
-
} else {
|
|
806
|
-
const cachedSpriteInst = frameState.instanceBuffers.get(
|
|
807
|
-
worldEntityKey(spriteEntry.source.worldId, spriteInstancesSnap.cacheKey),
|
|
808
|
-
);
|
|
809
|
-
let activeSpriteInst: InstanceBufferCacheEntry | null = null;
|
|
810
|
-
if (spriteInstancesCacheHit(cachedSpriteInst, spriteInstancesSnap, requestedBytes)) {
|
|
811
|
-
activeSpriteInst = cachedSpriteInst ?? null;
|
|
812
|
-
} else if (requestedBytes > 0) {
|
|
813
|
-
const bufRes = runtime.device.createBuffer({
|
|
814
|
-
size: requestedBytes,
|
|
815
|
-
usage:
|
|
816
|
-
(uniformFallback ? GPU_BUFFER_USAGE_UNIFORM : GPU_BUFFER_USAGE_STORAGE) |
|
|
817
|
-
GPU_BUFFER_USAGE_COPY_DST,
|
|
818
|
-
mappedAtCreation: false,
|
|
819
|
-
});
|
|
820
|
-
if (!bufRes.ok) {
|
|
821
|
-
runtime.errorRegistry.fire(bufRes.error);
|
|
822
|
-
} else {
|
|
823
|
-
if (cachedSpriteInst !== undefined && !cachedSpriteInst.buffer.isDestroyed) {
|
|
824
|
-
const r = cachedSpriteInst.buffer.destroy();
|
|
825
|
-
if (!r.ok) runtime.errorRegistry.fire(r.error);
|
|
826
|
-
}
|
|
827
|
-
const newBuf = new GpuBuffer(runtime.device, bufRes.value);
|
|
828
|
-
activeSpriteInst = {
|
|
829
|
-
buffer: newBuf,
|
|
830
|
-
uploadedArchVersion: spriteInstancesSnap.archVersion,
|
|
831
|
-
uploadedByteLength: requestedBytes,
|
|
832
|
-
};
|
|
833
|
-
frameState.instanceBuffers.set(
|
|
834
|
-
worldEntityKey(spriteEntry.source.worldId, spriteInstancesSnap.cacheKey),
|
|
835
|
-
activeSpriteInst,
|
|
836
|
-
);
|
|
837
|
-
}
|
|
838
|
-
}
|
|
839
|
-
if (activeSpriteInst !== null && requestedBytes > 0) {
|
|
840
|
-
const writeRes = runtime.device.queue.writeBuffer(
|
|
841
|
-
activeSpriteInst.buffer.handle,
|
|
842
|
-
0,
|
|
843
|
-
interleaved,
|
|
844
|
-
);
|
|
845
|
-
if (!writeRes.ok) {
|
|
846
|
-
runtime.errorRegistry.fire(writeRes.error);
|
|
847
|
-
} else {
|
|
848
|
-
buffer = activeSpriteInst.buffer.handle;
|
|
849
|
-
count = spriteInstancesSnap.instanceCount;
|
|
850
|
-
}
|
|
851
|
-
}
|
|
852
|
-
}
|
|
853
|
-
}
|
|
854
|
-
return { buffer, count };
|
|
855
|
-
}
|
|
856
|
-
|
|
857
711
|
function transparentPassColorFormat(
|
|
858
712
|
c: _InternalRenderPipelineContext,
|
|
859
713
|
pipelineState: _InternalRenderPipelineContext['pipelineState'] = c.pipelineState,
|
package/src/record/main-pass.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import type { World } from '@forgeax/engine-ecs';
|
|
2
1
|
import { probeVideoHighPerfUpload } from '@forgeax/engine-graphics-extras';
|
|
3
2
|
import type { GraphResourceResolver } from '@forgeax/engine-render-graph';
|
|
4
3
|
import {
|
|
@@ -19,6 +18,7 @@ import { getOrCreateIblCache } from '../ibl/IblPipelineCache';
|
|
|
19
18
|
import type { SkylightBindGroupResources } from '../ibl/skylight-bind-group';
|
|
20
19
|
import { buildBeginRenderPassDescriptor, standardTopologyBindGroupReady } from '../pipeline-spec';
|
|
21
20
|
import { POINTS_LINES_MATERIAL_SHADER_ID } from '../points-lines/record';
|
|
21
|
+
import type { RenderResourceScope } from '../publication/resource-scope';
|
|
22
22
|
import type { ReflectionProbeSelectionResult } from '../reflection/projection';
|
|
23
23
|
import type { RenderRecordPhase } from '../render-contract';
|
|
24
24
|
import type {
|
|
@@ -529,7 +529,7 @@ export function recordMainPass(
|
|
|
529
529
|
identities: [
|
|
530
530
|
getOpaqueResourceIdentity(skylightResources.irradianceSampler as object),
|
|
531
531
|
getOpaqueResourceIdentity(skylightResources.prefilterSampler as object),
|
|
532
|
-
getOpaqueResourceIdentity(skylightResources.
|
|
532
|
+
getOpaqueResourceIdentity(skylightResources.irradianceSampler as object),
|
|
533
533
|
],
|
|
534
534
|
},
|
|
535
535
|
resources: {
|
|
@@ -549,7 +549,9 @@ export function recordMainPass(
|
|
|
549
549
|
},
|
|
550
550
|
brdfLut: {
|
|
551
551
|
viewIdentity: getOpaqueResourceIdentity(skylightResources.brdfLutView as object),
|
|
552
|
-
samplerIdentity: getOpaqueResourceIdentity(
|
|
552
|
+
samplerIdentity: getOpaqueResourceIdentity(
|
|
553
|
+
skylightResources.irradianceSampler as object,
|
|
554
|
+
),
|
|
553
555
|
deviceGeneration: runtime.deviceScope.generation,
|
|
554
556
|
},
|
|
555
557
|
intensityBufferIdentity: getOpaqueResourceIdentity(
|
|
@@ -590,7 +592,7 @@ export function recordMainPass(
|
|
|
590
592
|
// which cannot render a PBR decal). Captures only frame-stable closure
|
|
591
593
|
// state; the caller passes the per-submesh material snapshot + entityKey
|
|
592
594
|
// (for video texture routing) and sets the dynamic UBO offset itself.
|
|
593
|
-
// Selection keys use the extracted frame index, never
|
|
595
|
+
// Selection keys use the extracted frame index, never RenderResourceScope.identity.
|
|
594
596
|
const hasProbeBindings = (c.reflectionProbes?.table.rows.length ?? 0) > 0;
|
|
595
597
|
const worldIndices = hasProbeBindings
|
|
596
598
|
? new Map(
|
|
@@ -632,7 +634,6 @@ export function recordMainPass(
|
|
|
632
634
|
skylightPrefilterView: skylightResources.prefilterView,
|
|
633
635
|
prefilterSampler: row.sampler,
|
|
634
636
|
brdfLutView: skylightResources.brdfLutView,
|
|
635
|
-
brdfLutSampler: skylightResources.brdfLutSampler,
|
|
636
637
|
intensityBuffer: row.uniformBuffer,
|
|
637
638
|
};
|
|
638
639
|
return { resources: probeResources, probeIndex: row.index };
|
|
@@ -657,7 +658,7 @@ export function recordMainPass(
|
|
|
657
658
|
const buildPerSubmeshMaterialBg = (
|
|
658
659
|
submeshMaterial: MaterialSnapshot,
|
|
659
660
|
entityKey: number,
|
|
660
|
-
materialWorld:
|
|
661
|
+
materialWorld: RenderResourceScope = world,
|
|
661
662
|
materialShaderId: string | undefined = submeshMaterial.materialShaderId,
|
|
662
663
|
): BindGroup =>
|
|
663
664
|
buildPerSubmeshMaterialBgImpl(
|
|
@@ -748,7 +749,7 @@ export function recordMainPass(
|
|
|
748
749
|
materialSlot: number,
|
|
749
750
|
material: MaterialSnapshot,
|
|
750
751
|
entityKey: number,
|
|
751
|
-
materialWorld:
|
|
752
|
+
materialWorld: RenderResourceScope = world,
|
|
752
753
|
materialShaderId: string | undefined = material.materialShaderId,
|
|
753
754
|
): BindGroup =>
|
|
754
755
|
!hasProbeBindings &&
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { resolveAssetHandle } from '@forgeax/engine-assets-runtime';
|
|
2
|
-
import type { World } from '@forgeax/engine-ecs';
|
|
3
2
|
import type { BindGroupEntry, BindGroupLayout, Buffer } from '@forgeax/engine-rhi';
|
|
4
3
|
import { err, ok } from '@forgeax/engine-rhi';
|
|
5
4
|
import {
|
|
@@ -14,6 +13,8 @@ import { transmissionBackdropAvailable } from '../assembly/device-feature-admiss
|
|
|
14
13
|
import { GPU_BUFFER_USAGE_COPY_DST, GPU_BUFFER_USAGE_UNIFORM } from '../gpu-usage';
|
|
15
14
|
import type { SkylightBindGroupResources } from '../ibl/skylight-bind-group';
|
|
16
15
|
import { assembleMaterialWithSkylightEntries } from '../ibl/skylight-bind-group';
|
|
16
|
+
import type { RenderResourceScope } from '../publication/resource-scope';
|
|
17
|
+
import { internSharedRefFromGuid } from '../render-system-extract';
|
|
17
18
|
import {
|
|
18
19
|
applyParamSchemaDefaultsToUbo,
|
|
19
20
|
applyParamSnapshotToUbo,
|
|
@@ -28,7 +29,6 @@ export type PreparedResolverCaches = {
|
|
|
28
29
|
readonly preparedGroup0Pipelines: WeakSet<object>;
|
|
29
30
|
readonly preparedViewOnlyPipelines: WeakSet<object>;
|
|
30
31
|
readonly preparedRenderMaterialPipelines: WeakSet<object>;
|
|
31
|
-
readonly preparedAssetHandles: WeakMap<World, Map<string, number>>;
|
|
32
32
|
};
|
|
33
33
|
|
|
34
34
|
export function createPreparedResolverCaches(): PreparedResolverCaches {
|
|
@@ -38,36 +38,23 @@ export function createPreparedResolverCaches(): PreparedResolverCaches {
|
|
|
38
38
|
preparedGroup0Pipelines: new WeakSet(),
|
|
39
39
|
preparedViewOnlyPipelines: new WeakSet(),
|
|
40
40
|
preparedRenderMaterialPipelines: new WeakSet(),
|
|
41
|
-
preparedAssetHandles: new WeakMap(),
|
|
42
41
|
};
|
|
43
42
|
}
|
|
44
43
|
|
|
45
44
|
function preparedHandle<Brand extends string>(
|
|
46
45
|
runtime: RenderSystemInternals,
|
|
47
|
-
|
|
48
|
-
world: World,
|
|
46
|
+
world: RenderResourceScope,
|
|
49
47
|
guid: string,
|
|
50
48
|
brand: Brand,
|
|
51
49
|
): Handle<Brand, 'shared'> | undefined {
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
caches.preparedAssetHandles.set(world, handles);
|
|
56
|
-
}
|
|
57
|
-
const key = `${brand}:${guid.toLowerCase()}`;
|
|
58
|
-
const cached = handles.get(key);
|
|
59
|
-
if (cached !== undefined) return cached as Handle<Brand, 'shared'>;
|
|
60
|
-
const asset = runtime.assets.lookup(guid);
|
|
61
|
-
if (asset === undefined) return undefined;
|
|
62
|
-
const handle = world.allocSharedRef(brand, asset);
|
|
63
|
-
handles.set(key, handle as number);
|
|
64
|
-
return handle;
|
|
50
|
+
if ('resolveAsset' in world)
|
|
51
|
+
return world.handleForGuid(guid) as Handle<Brand, 'shared'> | undefined;
|
|
52
|
+
return internSharedRefFromGuid(world, runtime.assets, guid, brand);
|
|
65
53
|
}
|
|
66
54
|
|
|
67
55
|
export function preparedMaterialBindings(
|
|
68
56
|
runtime: RenderSystemInternals,
|
|
69
|
-
|
|
70
|
-
worlds: readonly World[],
|
|
57
|
+
worlds: readonly RenderResourceScope[],
|
|
71
58
|
materialShaderId: string,
|
|
72
59
|
worldIndex: number,
|
|
73
60
|
materialGuid: string,
|
|
@@ -75,11 +62,16 @@ export function preparedMaterialBindings(
|
|
|
75
62
|
skylightResources?: SkylightBindGroupResources,
|
|
76
63
|
) {
|
|
77
64
|
const world = worlds[worldIndex];
|
|
78
|
-
const
|
|
65
|
+
const handle =
|
|
66
|
+
world === undefined ? undefined : preparedHandle(runtime, world, materialGuid, 'MaterialAsset');
|
|
79
67
|
const pipelineState = runtime.getPipelineState();
|
|
80
|
-
if (world === undefined ||
|
|
68
|
+
if (world === undefined || handle === undefined || pipelineState === null) {
|
|
81
69
|
return err(new Error('prepared material asset is unavailable'));
|
|
82
70
|
}
|
|
71
|
+
const resolved = resolveAssetHandle<MaterialAsset>(world, handle);
|
|
72
|
+
if (!resolved.ok) return resolved;
|
|
73
|
+
const material = resolved.value;
|
|
74
|
+
if (material.kind !== 'material') return err(new Error('prepared material asset is unavailable'));
|
|
83
75
|
const schema = runtime.getParamSchema?.(materialShaderId) ?? [];
|
|
84
76
|
// Feature materials share the ordinary linear parameter domain and semantic texture defaults.
|
|
85
77
|
const values = materialValuesToLinearRuntime(
|
|
@@ -126,13 +118,7 @@ export function preparedMaterialBindings(
|
|
|
126
118
|
: undefined;
|
|
127
119
|
let sampler = pipelineState.defaultSampler;
|
|
128
120
|
if (textureValue?.sampler !== undefined) {
|
|
129
|
-
const handle = preparedHandle(
|
|
130
|
-
runtime,
|
|
131
|
-
caches,
|
|
132
|
-
world,
|
|
133
|
-
String(textureValue.sampler),
|
|
134
|
-
'SamplerAsset',
|
|
135
|
-
);
|
|
121
|
+
const handle = preparedHandle(runtime, world, String(textureValue.sampler), 'SamplerAsset');
|
|
136
122
|
if (handle !== undefined) {
|
|
137
123
|
const asset = resolveAssetHandle<SamplerAsset>(world, handle);
|
|
138
124
|
if (asset.ok) {
|
|
@@ -143,13 +129,7 @@ export function preparedMaterialBindings(
|
|
|
143
129
|
}
|
|
144
130
|
let view = defaultViewForUserRegionField(field, pipelineState, schema);
|
|
145
131
|
if (textureValue !== undefined) {
|
|
146
|
-
const handle = preparedHandle(
|
|
147
|
-
runtime,
|
|
148
|
-
caches,
|
|
149
|
-
world,
|
|
150
|
-
String(textureValue.texture),
|
|
151
|
-
'TextureAsset',
|
|
152
|
-
);
|
|
132
|
+
const handle = preparedHandle(runtime, world, String(textureValue.texture), 'TextureAsset');
|
|
153
133
|
if (handle !== undefined) {
|
|
154
134
|
view = residentTextureView(world, runtime.gpuStore, runtime, handle) ?? view;
|
|
155
135
|
}
|
|
@@ -203,7 +183,6 @@ export function preparedMaterialBindings(
|
|
|
203
183
|
prefilterView: fallback.prefilterView,
|
|
204
184
|
prefilterSampler: fallback.sampler,
|
|
205
185
|
brdfLutView: fallback.brdfLutView,
|
|
206
|
-
brdfLutSampler: fallback.sampler,
|
|
207
186
|
intensityBuffer: fallback.intensityBuffer,
|
|
208
187
|
},
|
|
209
188
|
transmissionBackdropAvailable(runtime.device.limits.maxSampledTexturesPerShaderStage)
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import type { AssetRegistry, DynamicTextureStore } from '@forgeax/engine-assets-runtime';
|
|
2
|
-
import type { World } from '@forgeax/engine-ecs';
|
|
3
2
|
import type { VertexLayoutProjection } from '@forgeax/engine-geometry';
|
|
4
3
|
import type { Profiler } from '@forgeax/engine-profiler';
|
|
5
4
|
import type { CompiledRenderGraphInfo } from '@forgeax/engine-render-graph';
|
|
@@ -58,6 +57,7 @@ import type { StandardProfile } from '../pipeline/standard-profile';
|
|
|
58
57
|
import type { PipelineBuilderShaderModuleFactory } from '../pipeline-builder';
|
|
59
58
|
import type { PointsLinesInspection } from '../points-lines/inspection';
|
|
60
59
|
import type { PointsLinesRecordPlan } from '../points-lines/record';
|
|
60
|
+
import type { RenderResourceScope } from '../publication/resource-scope';
|
|
61
61
|
import type { ReflectionProbeTable } from '../reflection/gpu-table';
|
|
62
62
|
import type { ReflectionProbeSelectionResult } from '../reflection/projection';
|
|
63
63
|
import type { FrameObservationDomain } from '../render-contract';
|
|
@@ -582,7 +582,7 @@ export interface _StandardForwardSceneView {
|
|
|
582
582
|
readonly skybox: SkyboxSnapshot | undefined;
|
|
583
583
|
readonly profilePhase?: <T>(phase: RenderRecordPhase, action: () => T) => T;
|
|
584
584
|
readonly directionalShadowCacheReuse: boolean;
|
|
585
|
-
readonly world:
|
|
585
|
+
readonly world: RenderResourceScope;
|
|
586
586
|
readonly tonemapActive: boolean;
|
|
587
587
|
readonly geometryColorView: TextureView | null;
|
|
588
588
|
readonly geometryDepthView: TextureView | null;
|
|
@@ -620,6 +620,8 @@ export interface _StandardForwardSceneView {
|
|
|
620
620
|
readonly gpuDrivenShadowDrawKeys?: ReadonlySet<string>;
|
|
621
621
|
/** View-scoped ShadowCaster claims for exact CPU residual routing. */
|
|
622
622
|
readonly gpuDrivenShadowDrawKeysByView?: ReadonlyMap<string, ReadonlySet<string>>;
|
|
623
|
+
/** Per-shadow-view frusta shared by GPU compaction and CPU residual routing. */
|
|
624
|
+
readonly shadowViewPlanesByView?: ReadonlyMap<string, Float32Array>;
|
|
623
625
|
/** Extracted structured ShadowCaster ownership facts. */
|
|
624
626
|
readonly shadowCasterMembership?: readonly ShadowCasterMembership[];
|
|
625
627
|
/** Complete retained ShadowCaster rows, including camera-culled casters. */
|