@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
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
DynamicTextureStore,
|
|
7
7
|
} from '@forgeax/engine-assets-runtime';
|
|
8
8
|
import { audioLoader } from '@forgeax/engine-audio-webaudio';
|
|
9
|
-
import {
|
|
9
|
+
import type { World } from '@forgeax/engine-ecs';
|
|
10
10
|
import { createRenderReadLease, type RenderReadLease } from '@forgeax/engine-ecs/projection';
|
|
11
11
|
import {
|
|
12
12
|
DEFAULT_VERTEX_ATTRIBUTE_MAP,
|
|
@@ -21,7 +21,6 @@ import type {
|
|
|
21
21
|
RhiDevice,
|
|
22
22
|
} from '@forgeax/engine-rhi';
|
|
23
23
|
import { err, ok, RhiError, validateDrawArgs } from '@forgeax/engine-rhi';
|
|
24
|
-
import { registerPropagateTransforms } from '@forgeax/engine-scene';
|
|
25
24
|
import {
|
|
26
25
|
findVariantByKey,
|
|
27
26
|
type MaterialShaderEntry,
|
|
@@ -39,6 +38,11 @@ import type {
|
|
|
39
38
|
PrimitiveTopology,
|
|
40
39
|
VertexAttributeMap,
|
|
41
40
|
} from '@forgeax/engine-types';
|
|
41
|
+
import { type PublishedRenderFrameInput, RenderPublicationError } from '../publication/contract';
|
|
42
|
+
import { installPublicationPrograms } from '../publication/programs';
|
|
43
|
+
import { type PreparedRenderPublication, RenderPublicationReceiver } from '../publication/receiver';
|
|
44
|
+
import { RenderPublicationTargetReceiver } from '../publication/targets';
|
|
45
|
+
import { registerRenderSourceSystems } from '../scene/source-systems';
|
|
42
46
|
import { transmissionBackdropAvailable } from './device-feature-admission';
|
|
43
47
|
|
|
44
48
|
export type { MaterialShaderManifestEntry } from '@forgeax/engine-shader';
|
|
@@ -71,7 +75,6 @@ import {
|
|
|
71
75
|
type PostProcessShaderEntry,
|
|
72
76
|
postProcessShaderModuleLabel,
|
|
73
77
|
} from '../fullscreen-post-process-pass';
|
|
74
|
-
import { glyphTextLayoutSystem } from '../glyph-text-layout-system';
|
|
75
78
|
import { GPU_SHADER_STAGE_FRAGMENT, GPU_SHADER_STAGE_VERTEX } from '../gpu-stage';
|
|
76
79
|
import { type BloomInspection, emptyBloomInspection } from '../inspection-types';
|
|
77
80
|
import { DeviceScope } from '../lifecycle';
|
|
@@ -155,7 +158,6 @@ import {
|
|
|
155
158
|
import { createGpuPassTimingObservationStore, observeGpuPassTimingDisabled } from '../renderer.js';
|
|
156
159
|
import { postSpawnResolveJoints } from '../scene-instances/post-spawn-resolve-joints';
|
|
157
160
|
import type { RenderTarget } from '../targets/contracts';
|
|
158
|
-
import { tilemapChunkExtractSystem } from '../tilemap-chunk-extract-system';
|
|
159
161
|
import type { TypedFrameObservationCapture } from '../typed-render-graph-primitives';
|
|
160
162
|
import { registerAnalyticFogPostProcess } from './analytic-fog-registration';
|
|
161
163
|
import type { RhiBackendPack } from './backend-contract';
|
|
@@ -303,7 +305,6 @@ export type { WebGPUOutcome, WebGPURendererInternals } from './webgpu-renderer-c
|
|
|
303
305
|
export { disposeObservationCaptureSet } from './webgpu-renderer-observation';
|
|
304
306
|
|
|
305
307
|
/** Bundler injection and the WebGPU renderer construction entry points. */
|
|
306
|
-
let nextDerivedSystemId = 0;
|
|
307
308
|
export async function tryCreateWebGPURenderer(
|
|
308
309
|
canvas: HTMLCanvasElement | OffscreenCanvas,
|
|
309
310
|
options: RendererOptions | undefined,
|
|
@@ -315,7 +316,12 @@ export async function tryCreateWebGPURenderer(
|
|
|
315
316
|
async function makeWebGPURenderer(
|
|
316
317
|
internals: WebGPURendererInternals,
|
|
317
318
|
): Promise<RendererAssemblyImplementation> {
|
|
319
|
+
let publicationTargets: RenderPublicationTargetReceiver | undefined;
|
|
318
320
|
let disposed = false;
|
|
321
|
+
const publicationReceiver =
|
|
322
|
+
internals.options?.publicationSource === undefined
|
|
323
|
+
? undefined
|
|
324
|
+
: new RenderPublicationReceiver(internals.options.publicationSource);
|
|
319
325
|
const observeTiming = observeGpuPassTimingDisabled;
|
|
320
326
|
const frameContinuations = new Set<ContinuationTerminator>();
|
|
321
327
|
type RecoveryInspection = RenderInspection['recovery'];
|
|
@@ -564,6 +570,8 @@ async function makeWebGPURenderer(
|
|
|
564
570
|
const getShader = (): ShaderCatalog => {
|
|
565
571
|
const state = candidateShaderState ?? activeShaderState;
|
|
566
572
|
if (state.shaderInstance === null) {
|
|
573
|
+
const activeCatalog = activeShaderState.shaderInstance;
|
|
574
|
+
// Reuse validated manifest CPU rows; candidate preparation selects variants.
|
|
567
575
|
// feat-20260608-create-app-param-surface-trim / M2 / D-2 q5-A:
|
|
568
576
|
// shaderManifestUrl moved to BundlerOptions (third arg). The fallback
|
|
569
577
|
// literal '/shaders/manifest.json' stays here so the LO 1.1
|
|
@@ -572,39 +580,20 @@ async function makeWebGPURenderer(
|
|
|
572
580
|
// the zero-entry opt-in: explicitly passing
|
|
573
581
|
// `bundler: { shaderManifestUrl: undefined }` retains the
|
|
574
582
|
// old "no manifest fetched" mode used by tests / camera-only worlds.
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
583
|
+
state.shaderInstance =
|
|
584
|
+
state === candidateShaderState && activeCatalog !== null
|
|
585
|
+
? activeCatalog.forkForDevice(getShaderModuleAdapter())
|
|
586
|
+
: new ShaderCatalog({
|
|
587
|
+
device: getShaderModuleAdapter(),
|
|
588
|
+
manifestUrl:
|
|
589
|
+
internals.bundler !== undefined && 'shaderManifestUrl' in internals.bundler
|
|
590
|
+
? internals.bundler.shaderManifestUrl
|
|
591
|
+
: '/shaders/manifest.json',
|
|
592
|
+
});
|
|
584
593
|
}
|
|
585
594
|
return state.shaderInstance;
|
|
586
595
|
};
|
|
587
|
-
// D-S9: AssetRegistry instance shared with RenderSystem. RenderSystem
|
|
588
|
-
// looks up MeshFilter.assetHandle here per frame; buildReadyWebGPU step 3
|
|
589
|
-
// uploads the registry's builtin mesh geometry to GPU buffers so the
|
|
590
|
-
// RenderSystem can route MeshFilter.assetHandle to a real (vbo, ibo) pair.
|
|
591
|
-
// feat-20260527 M1 / w1: ShaderCatalog is now eager-constructed and
|
|
592
|
-
// constructor-injected into AssetRegistry (plan-strategy D-1). The
|
|
593
|
-
// ShaderCatalogDevice adapter (shared between the catalog and per-MaterialShader
|
|
594
|
-
// pipeline cache) is already available at this point.
|
|
595
596
|
const shaderCatalog = getShader();
|
|
596
|
-
// bug-20260601-hello-tonemap-material-register M1 (plan-strategy D-1):
|
|
597
|
-
// All material-shader entries are now registered from the manifest
|
|
598
|
-
// BEFORE the renderer is returned, so `register<MaterialAsset>` referencing
|
|
599
|
-
// an engine shader succeeds without waiting for `renderer.initialization`.
|
|
600
|
-
// Host-injected ImportTransport remains a constructor-only dependency.
|
|
601
|
-
// feat-20260705-runtime-tier2-decomposition M1 / w10 (D-1 / D-2): the sole
|
|
602
|
-
// production assembly point injects (a) the post-spawn hook
|
|
603
|
-
// `postSpawnResolveJoints` (auto-wire Skin.joints; D-1) and the audio
|
|
604
|
-
// catalog-entry loader. The latter stays at this assembly boundary so
|
|
605
|
-
// assets-runtime remains independent of the concrete Web Audio backend.
|
|
606
|
-
// videoLoader is wired internally from graphics-extras; the full registry has
|
|
607
|
-
// 11 engine kinds. This is the only `new AssetRegistry(...)` call in the repo.
|
|
608
597
|
const assets = new AssetRegistry(
|
|
609
598
|
shaderCatalog,
|
|
610
599
|
internals.importTransport,
|
|
@@ -735,7 +724,9 @@ async function makeWebGPURenderer(
|
|
|
735
724
|
gpuStore.configureGpuDevice(
|
|
736
725
|
internals.device,
|
|
737
726
|
packShaderFactory,
|
|
738
|
-
(world, pod) => {
|
|
727
|
+
(world, pod, source) => {
|
|
728
|
+
// The accepted equirect identity already owns this renderer-local GPU projection.
|
|
729
|
+
if ('resolveAsset' in world) return ok(source);
|
|
739
730
|
const handle = world.allocSharedRef('EquirectAsset', pod);
|
|
740
731
|
return ok(handle);
|
|
741
732
|
},
|
|
@@ -2562,7 +2553,6 @@ async function makeWebGPURenderer(
|
|
|
2562
2553
|
currentGeneration: () => activeDeviceScope.generation,
|
|
2563
2554
|
renderSystem,
|
|
2564
2555
|
});
|
|
2565
|
-
const derivedSystemNames = new Map<World, string>();
|
|
2566
2556
|
const transformReleases = new Map<World, () => void>();
|
|
2567
2557
|
const attachmentOwner = {};
|
|
2568
2558
|
let frameId = 0;
|
|
@@ -2599,6 +2589,13 @@ async function makeWebGPURenderer(
|
|
|
2599
2589
|
renderSystem.setSurfaceDynamicInput(frame);
|
|
2600
2590
|
},
|
|
2601
2591
|
attach(world: World): RenderResult<RenderWorldLease, RenderError> {
|
|
2592
|
+
if (publicationReceiver !== undefined)
|
|
2593
|
+
return err(
|
|
2594
|
+
new RenderPublicationError({
|
|
2595
|
+
reason: 'identity',
|
|
2596
|
+
subject: 'publication Renderer has no World attachment',
|
|
2597
|
+
}),
|
|
2598
|
+
);
|
|
2602
2599
|
const attached = this.attachScene(world);
|
|
2603
2600
|
if (!attached.ok) {
|
|
2604
2601
|
return err(new RendererContractFailureError('attach', attached.error.hint));
|
|
@@ -2850,23 +2847,7 @@ async function makeWebGPURenderer(
|
|
|
2850
2847
|
}
|
|
2851
2848
|
if (attachedWorlds.has(world)) return ok(undefined);
|
|
2852
2849
|
try {
|
|
2853
|
-
|
|
2854
|
-
const derivedSystemName = `renderDerived:${++nextDerivedSystemId}`;
|
|
2855
|
-
const derived = world.addSystem(Update, {
|
|
2856
|
-
name: derivedSystemName,
|
|
2857
|
-
queries: [],
|
|
2858
|
-
fn: (world) => {
|
|
2859
|
-
tilemapChunkExtractSystem(world, (guid) => assets.lookup(guid));
|
|
2860
|
-
const glyphResult = glyphTextLayoutSystem(world, gpuStore);
|
|
2861
|
-
if (!glyphResult.ok) throw glyphResult.error;
|
|
2862
|
-
},
|
|
2863
|
-
});
|
|
2864
|
-
if (!derived.ok) {
|
|
2865
|
-
releaseTransforms();
|
|
2866
|
-
throw new Error(`failed to register ${derivedSystemName}: ${derived.error.code}`);
|
|
2867
|
-
}
|
|
2868
|
-
transformReleases.set(world, releaseTransforms);
|
|
2869
|
-
derivedSystemNames.set(world, derivedSystemName);
|
|
2850
|
+
transformReleases.set(world, registerRenderSourceSystems(world, assets, gpuStore));
|
|
2870
2851
|
attachedWorlds.add(world);
|
|
2871
2852
|
return ok(undefined);
|
|
2872
2853
|
} catch (cause) {
|
|
@@ -2897,11 +2878,6 @@ async function makeWebGPURenderer(
|
|
|
2897
2878
|
}
|
|
2898
2879
|
}
|
|
2899
2880
|
renderSystem.detachScene(world);
|
|
2900
|
-
const derivedSystemName = derivedSystemNames.get(world);
|
|
2901
|
-
if (derivedSystemName !== undefined) {
|
|
2902
|
-
world.removeSystem(Update, derivedSystemName);
|
|
2903
|
-
derivedSystemNames.delete(world);
|
|
2904
|
-
}
|
|
2905
2881
|
transformReleases.get(world)?.();
|
|
2906
2882
|
transformReleases.delete(world);
|
|
2907
2883
|
},
|
|
@@ -3105,17 +3081,43 @@ async function makeWebGPURenderer(
|
|
|
3105
3081
|
: ok(result.value);
|
|
3106
3082
|
},
|
|
3107
3083
|
draw(
|
|
3108
|
-
worldsOrRequest: readonly World[] | RenderFrameInput,
|
|
3084
|
+
worldsOrRequest: readonly World[] | RenderFrameInput | PublishedRenderFrameInput,
|
|
3109
3085
|
options?: DrawOwnerOptions,
|
|
3110
3086
|
): Result<void | FrameReceipt, RhiError | RenderError> {
|
|
3111
3087
|
const isFrameRequest = !Array.isArray(worldsOrRequest);
|
|
3112
|
-
const
|
|
3088
|
+
const publicationRequest =
|
|
3089
|
+
isFrameRequest && 'publication' in worldsOrRequest
|
|
3090
|
+
? (worldsOrRequest as PublishedRenderFrameInput)
|
|
3091
|
+
: undefined;
|
|
3092
|
+
const frameRequest =
|
|
3093
|
+
isFrameRequest && publicationRequest === undefined
|
|
3094
|
+
? (worldsOrRequest as RenderFrameInput)
|
|
3095
|
+
: undefined;
|
|
3096
|
+
let publication: PreparedRenderPublication | undefined;
|
|
3097
|
+
if (publicationRequest !== undefined) {
|
|
3098
|
+
if (publicationReceiver === undefined)
|
|
3099
|
+
return err(
|
|
3100
|
+
new RenderPublicationError({
|
|
3101
|
+
reason: 'identity',
|
|
3102
|
+
subject: 'RendererOptions.publicationSource',
|
|
3103
|
+
}),
|
|
3104
|
+
);
|
|
3105
|
+
} else if (publicationReceiver !== undefined) {
|
|
3106
|
+
return err(
|
|
3107
|
+
new RenderPublicationError({
|
|
3108
|
+
reason: 'identity',
|
|
3109
|
+
subject: 'a publication-bound renderer cannot consume local World leases',
|
|
3110
|
+
}),
|
|
3111
|
+
);
|
|
3112
|
+
}
|
|
3113
3113
|
const worlds: readonly World[] =
|
|
3114
3114
|
frameRequest !== undefined
|
|
3115
3115
|
? frameRequest.leases
|
|
3116
3116
|
.map((lease) => attachedLeases.get(lease))
|
|
3117
3117
|
.filter((world): world is World => world !== undefined)
|
|
3118
|
-
:
|
|
3118
|
+
: publicationRequest === undefined
|
|
3119
|
+
? (worldsOrRequest as readonly World[])
|
|
3120
|
+
: [];
|
|
3119
3121
|
const readLeases: readonly RenderReadLease[] | undefined =
|
|
3120
3122
|
frameRequest !== undefined
|
|
3121
3123
|
? frameRequest.leases
|
|
@@ -3170,7 +3172,14 @@ async function makeWebGPURenderer(
|
|
|
3170
3172
|
? {}
|
|
3171
3173
|
: { geometryLane: frameRequest.geometryLane }),
|
|
3172
3174
|
}
|
|
3173
|
-
:
|
|
3175
|
+
: publicationRequest === undefined
|
|
3176
|
+
? (options ?? { cameraOwner: 0, resourceOwner: 0 })
|
|
3177
|
+
: {
|
|
3178
|
+
cameraOwner: 0,
|
|
3179
|
+
resourceOwner: 0,
|
|
3180
|
+
sampleTimeSeconds: publicationRequest.publication.sampleTimeSeconds,
|
|
3181
|
+
temporalReset: publicationRequest.publication.temporalReset,
|
|
3182
|
+
};
|
|
3174
3183
|
// feat-20260612-rhi-destroy-renderer-dispose-gpu-lifecycle / M5 / w21
|
|
3175
3184
|
// (plan-strategy D-1, D-8): post-dispose the renderer is dead. AI
|
|
3176
3185
|
// users observing `result.ok === false && err.code === 'rhi-not-
|
|
@@ -3246,7 +3255,8 @@ async function makeWebGPURenderer(
|
|
|
3246
3255
|
// are non-exclusive: an empty array short-circuits to empty-worlds. The
|
|
3247
3256
|
// check is defensive against JS callers passing a non-array despite the
|
|
3248
3257
|
// compile-time World[] type (red-window migration safety).
|
|
3249
|
-
const worldCount =
|
|
3258
|
+
const worldCount =
|
|
3259
|
+
publicationRequest === undefined ? (Array.isArray(worlds) ? worlds.length : 0) : 1;
|
|
3250
3260
|
if (worldCount === 0 && internals.device.caps.backendKind === 'null') {
|
|
3251
3261
|
return ok(undefined);
|
|
3252
3262
|
}
|
|
@@ -3268,12 +3278,27 @@ async function makeWebGPURenderer(
|
|
|
3268
3278
|
internals.errorRegistry,
|
|
3269
3279
|
);
|
|
3270
3280
|
if (!contextConfigured.ok) return contextConfigured;
|
|
3271
|
-
renderTargetHost.beginFrame();
|
|
3272
3281
|
// w24 — facade-level try/catch produces Result.err on unexpected throw
|
|
3273
3282
|
// (D-P6 dual-channel preserved: per-stage RhiError continues to fan out
|
|
3274
3283
|
// through onError separately; the facade Result is the synchronous
|
|
3275
3284
|
// summary AI users can ignore or branch on).
|
|
3276
3285
|
try {
|
|
3286
|
+
if (publicationRequest !== undefined && publicationReceiver !== undefined) {
|
|
3287
|
+
const accepted = publicationReceiver.accept(publicationRequest.publication);
|
|
3288
|
+
if (!accepted.ok) return accepted;
|
|
3289
|
+
publicationTargets ??= new RenderPublicationTargetReceiver(renderTargetHost);
|
|
3290
|
+
publication = {
|
|
3291
|
+
...publicationTargets.apply(accepted.value),
|
|
3292
|
+
...(publicationRequest.onFeatureSourceSubmitted === undefined
|
|
3293
|
+
? {}
|
|
3294
|
+
: {
|
|
3295
|
+
onFeatureSourceSubmitted: publicationRequest.onFeatureSourceSubmitted,
|
|
3296
|
+
}),
|
|
3297
|
+
};
|
|
3298
|
+
installPublicationPrograms(assets, publicationRequest.publication.programs);
|
|
3299
|
+
}
|
|
3300
|
+
renderTargetHost.beginFrame();
|
|
3301
|
+
|
|
3277
3302
|
const timingHost = internals as WebGPURendererInternals & {
|
|
3278
3303
|
gpuPassTimingFrameIdentity?:
|
|
3279
3304
|
| {
|
|
@@ -3311,7 +3336,13 @@ async function makeWebGPURenderer(
|
|
|
3311
3336
|
graphGeneration: 0,
|
|
3312
3337
|
};
|
|
3313
3338
|
}
|
|
3314
|
-
const submitted = renderSystem.draw(
|
|
3339
|
+
const submitted = renderSystem.draw(
|
|
3340
|
+
worlds,
|
|
3341
|
+
drawOptions,
|
|
3342
|
+
readLeases,
|
|
3343
|
+
volumeTimingCapture,
|
|
3344
|
+
publication,
|
|
3345
|
+
);
|
|
3315
3346
|
timingHost.observationFrameId = undefined;
|
|
3316
3347
|
timingHost.observationCaptureDomains = undefined;
|
|
3317
3348
|
timingHost.gpuPassTimingFrameIdentity = undefined;
|
|
@@ -3510,6 +3541,10 @@ async function makeWebGPURenderer(
|
|
|
3510
3541
|
});
|
|
3511
3542
|
internals.errorRegistry.fire(e);
|
|
3512
3543
|
return err(e);
|
|
3544
|
+
} finally {
|
|
3545
|
+
// Native video pixels have been consumed by synchronous queue copy calls.
|
|
3546
|
+
// Release them on every success/failure path, including direct publication users.
|
|
3547
|
+
publicationReceiver?.releaseVideoFrames();
|
|
3513
3548
|
}
|
|
3514
3549
|
},
|
|
3515
3550
|
async observe(
|
|
@@ -3752,6 +3787,7 @@ async function makeWebGPURenderer(
|
|
|
3752
3787
|
disposed = true;
|
|
3753
3788
|
for (const world of attachedWorlds) dynamicGeometryHost.invalidateDynamicGeometryWorld(world);
|
|
3754
3789
|
dynamicGeometry.dispose();
|
|
3790
|
+
publicationReceiver?.dispose();
|
|
3755
3791
|
for (const continuation of frameContinuations) {
|
|
3756
3792
|
continuation.terminate({ code: 'disposed' });
|
|
3757
3793
|
}
|
|
@@ -3762,11 +3798,6 @@ async function makeWebGPURenderer(
|
|
|
3762
3798
|
}
|
|
3763
3799
|
for (const world of attachedWorlds) {
|
|
3764
3800
|
try {
|
|
3765
|
-
const derivedSystemName = derivedSystemNames.get(world);
|
|
3766
|
-
if (derivedSystemName !== undefined) {
|
|
3767
|
-
world.removeSystem(Update, derivedSystemName);
|
|
3768
|
-
derivedSystemNames.delete(world);
|
|
3769
|
-
}
|
|
3770
3801
|
transformReleases.get(world)?.();
|
|
3771
3802
|
transformReleases.delete(world);
|
|
3772
3803
|
} catch (cause) {
|
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
type VertexLayoutProjection,
|
|
9
9
|
} from '@forgeax/engine-geometry';
|
|
10
10
|
import type { VertexAttributeMap } from '@forgeax/engine-types';
|
|
11
|
+
import { PARTICLE_MESH_VERTEX_BUFFER } from '../features/particle-mesh-layout';
|
|
11
12
|
import { RENDER_FEATURE_VERTEX_LAYOUTS } from '../features/prepared-graphics';
|
|
12
13
|
|
|
13
14
|
type FeatureFloatVertexFormat = 'float32x2' | 'float32x3' | 'float32x4';
|
|
@@ -101,14 +102,6 @@ const MESH_GEOMETRY_MATERIAL_INSTANCE_SPEC = {
|
|
|
101
102
|
export const PREPARED_INSTANCE_VERTEX_ATTRS = buildMeshAttributeMapForUvSets(2);
|
|
102
103
|
export const PREPARED_MATERIAL_INSTANCE_VERTEX_ATTRS = SKIN_VERTEX_ATTRIBUTE_MAP;
|
|
103
104
|
|
|
104
|
-
function canonicalMeshVertexBufferLayout(): GPUVertexBufferLayout {
|
|
105
|
-
const [buffer] = toGpuVertexBufferLayouts(deriveVertexBufferLayout(DEFAULT_VERTEX_ATTRIBUTE_MAP));
|
|
106
|
-
if (buffer === undefined) {
|
|
107
|
-
throw new Error('The canonical mesh vertex layout must contain one vertex buffer');
|
|
108
|
-
}
|
|
109
|
-
return { ...buffer, stepMode: 'vertex' };
|
|
110
|
-
}
|
|
111
|
-
|
|
112
105
|
export const POSITION_SIZE_COLOR_INSTANCE_VERTEX_BUFFERS = [
|
|
113
106
|
defineFeatureVertexBuffer(POSITION_SIZE_COLOR_INSTANCE_SPEC),
|
|
114
107
|
] satisfies readonly GPUVertexBufferLayout[];
|
|
@@ -127,7 +120,7 @@ export const TOPOLOGY_SEGMENT_INSTANCE_VERTEX_BUFFERS = [
|
|
|
127
120
|
* particle transform/material data rather than MeshAsset attributes.
|
|
128
121
|
*/
|
|
129
122
|
export const MESH_GEOMETRY_MATERIAL_INSTANCE_VERTEX_BUFFERS = [
|
|
130
|
-
|
|
123
|
+
PARTICLE_MESH_VERTEX_BUFFER,
|
|
131
124
|
defineFeatureVertexBuffer(MESH_GEOMETRY_MATERIAL_INSTANCE_SPEC),
|
|
132
125
|
] satisfies readonly GPUVertexBufferLayout[];
|
|
133
126
|
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import type { World } from '@forgeax/engine-ecs';
|
|
2
1
|
import type { RenderFeatureFrameContext, RenderFeatureViewContext } from '../features/types';
|
|
2
|
+
import type { RenderResourceScope } from '../publication/resource-scope';
|
|
3
3
|
import type { CameraSnapshot } from '../render-contract';
|
|
4
4
|
import type { ExtractedCloudLayer } from './extract';
|
|
5
5
|
|
|
6
6
|
/** Project the stable camera/world facts consumed by the cloud feature owner. */
|
|
7
7
|
export function createCloudFeatureView(
|
|
8
8
|
camera: CameraSnapshot | undefined,
|
|
9
|
-
worlds: readonly
|
|
9
|
+
worlds: readonly RenderResourceScope[],
|
|
10
10
|
cameraOwner: number,
|
|
11
11
|
width: number,
|
|
12
12
|
height: number,
|
|
@@ -176,6 +176,7 @@ export class DeviceScope {
|
|
|
176
176
|
this.clearChildren();
|
|
177
177
|
this._clearResources();
|
|
178
178
|
this.lifecycleState = 'retired';
|
|
179
|
+
this.parent?.detachChild(this);
|
|
179
180
|
}
|
|
180
181
|
|
|
181
182
|
abandon(): void {
|
|
@@ -183,6 +184,7 @@ export class DeviceScope {
|
|
|
183
184
|
this.lifecycleState = 'abandoned';
|
|
184
185
|
this.clearChildren();
|
|
185
186
|
this._clearResources();
|
|
187
|
+
this.parent?.detachChild(this);
|
|
186
188
|
}
|
|
187
189
|
|
|
188
190
|
dispose(): void {
|
|
@@ -190,6 +192,7 @@ export class DeviceScope {
|
|
|
190
192
|
this.lifecycleState = 'disposed';
|
|
191
193
|
this.clearChildren();
|
|
192
194
|
this._clearResources();
|
|
195
|
+
this.parent?.detachChild(this);
|
|
193
196
|
}
|
|
194
197
|
|
|
195
198
|
async replace(
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { RenderResourceScope } from '../publication/resource-scope';
|
|
1
2
|
import { type MeshResidencyLease, MeshResidencyLifetime } from './mesh-residency-lifetime';
|
|
2
3
|
// @forgeax/engine-runtime - GpuResidencyCache
|
|
3
4
|
// (feat-20260601-device/gpu-residency-extraction M1; M2 added the deriveRenderData
|
|
@@ -37,7 +38,6 @@ import {
|
|
|
37
38
|
type MipmapShaderModuleFactory,
|
|
38
39
|
prepareMipmaps,
|
|
39
40
|
} from '@forgeax/engine-assets-runtime';
|
|
40
|
-
import type { World } from '@forgeax/engine-ecs';
|
|
41
41
|
import { deriveVertexCount, type VertexLayoutProjection } from '@forgeax/engine-geometry';
|
|
42
42
|
import { halfFloat } from '@forgeax/engine-math';
|
|
43
43
|
import {
|
|
@@ -288,8 +288,9 @@ function makeImageError<C extends ImageErrorCode>(
|
|
|
288
288
|
|
|
289
289
|
/** Cube-POD register-relay injected by the wire layer (D-3). */
|
|
290
290
|
type RegisterCube = (
|
|
291
|
-
world:
|
|
291
|
+
world: RenderResourceScope,
|
|
292
292
|
pod: EquirectAsset,
|
|
293
|
+
source: Handle<'EquirectAsset', 'shared'>,
|
|
293
294
|
) => Result<Handle<'EquirectAsset', 'shared'>, AssetError>;
|
|
294
295
|
|
|
295
296
|
// feat-20260612-rhi-destroy-renderer-dispose-gpu-lifecycle / M-3 / w11:
|
|
@@ -607,16 +608,16 @@ export class GpuResidencyCache {
|
|
|
607
608
|
}
|
|
608
609
|
|
|
609
610
|
/**
|
|
610
|
-
* Compose a cache key from the raw handle slot and its owning
|
|
611
|
+
* Compose a cache key from the raw handle slot and its owning RenderResourceScope. The
|
|
611
612
|
* draw-time world index is only a position in one frame's `worlds[]`; it is
|
|
612
|
-
* not an asset identity and can be reused by a later
|
|
613
|
+
* not an asset identity and can be reused by a later RenderResourceScope. RenderResourceScope objects
|
|
613
614
|
* therefore receive a renderer-local namespace, while numeric callers keep
|
|
614
615
|
* the legacy namespace for low-level tests and built-in upload paths.
|
|
615
616
|
*/
|
|
616
|
-
private readonly worldNamespaces = new WeakMap<
|
|
617
|
+
private readonly worldNamespaces = new WeakMap<RenderResourceScope, number>();
|
|
617
618
|
private nextWorldNamespace = 1;
|
|
618
619
|
|
|
619
|
-
private worldKey(slot: number, world:
|
|
620
|
+
private worldKey(slot: number, world: RenderResourceScope | number): string | number {
|
|
620
621
|
if (typeof world === 'number') {
|
|
621
622
|
return world === 0 ? slot : world * 0x1000000 + slot;
|
|
622
623
|
}
|
|
@@ -809,7 +810,7 @@ export class GpuResidencyCache {
|
|
|
809
810
|
*/
|
|
810
811
|
evictTexture(
|
|
811
812
|
handle: Handle<'TextureAsset', 'shared'>,
|
|
812
|
-
worldId:
|
|
813
|
+
worldId: RenderResourceScope | number = 0,
|
|
813
814
|
): { freed: number; errors: RhiError[] } {
|
|
814
815
|
const id = this.worldKey(handleSlot(handle), worldId);
|
|
815
816
|
const entry = this.textureGpuHandles.get(id);
|
|
@@ -835,7 +836,7 @@ export class GpuResidencyCache {
|
|
|
835
836
|
|
|
836
837
|
evictMesh(
|
|
837
838
|
handle: Handle<'MeshAsset', 'shared'>,
|
|
838
|
-
worldId:
|
|
839
|
+
worldId: RenderResourceScope | number = 0,
|
|
839
840
|
): { freed: number; errors: RhiError[] } {
|
|
840
841
|
const id = this.worldKey(Number(handle), worldId);
|
|
841
842
|
const entry = this.meshGpuHandles.get(id);
|
|
@@ -1000,7 +1001,7 @@ export class GpuResidencyCache {
|
|
|
1000
1001
|
*/
|
|
1001
1002
|
_getTextureGpuTexture(
|
|
1002
1003
|
handle: Handle<'TextureAsset', 'shared'>,
|
|
1003
|
-
worldId:
|
|
1004
|
+
worldId: RenderResourceScope | number = 0,
|
|
1004
1005
|
): GpuTexture | undefined {
|
|
1005
1006
|
return this.textureGpuHandles.get(this.worldKey(handleSlot(handle), worldId))?.texture;
|
|
1006
1007
|
}
|
|
@@ -1011,7 +1012,7 @@ export class GpuResidencyCache {
|
|
|
1011
1012
|
*/
|
|
1012
1013
|
getTextureGpuView(
|
|
1013
1014
|
handle: Handle<'TextureAsset', 'shared'>,
|
|
1014
|
-
worldId:
|
|
1015
|
+
worldId: RenderResourceScope | number = 0,
|
|
1015
1016
|
): TextureView | undefined {
|
|
1016
1017
|
return this.textureGpuHandles.get(this.worldKey(handleSlot(handle), worldId))?.view;
|
|
1017
1018
|
}
|
|
@@ -1024,7 +1025,7 @@ export class GpuResidencyCache {
|
|
|
1024
1025
|
ensureSamplerResident(
|
|
1025
1026
|
handle: Handle<'SamplerAsset', 'shared'>,
|
|
1026
1027
|
pod: SamplerAsset,
|
|
1027
|
-
worldId:
|
|
1028
|
+
worldId: RenderResourceScope | number = 0,
|
|
1028
1029
|
): Result<Sampler, RhiError> {
|
|
1029
1030
|
const key = this.worldKey(handleSlot(handle), worldId);
|
|
1030
1031
|
const existing = this.samplerGpuHandles.get(key);
|
|
@@ -1093,7 +1094,7 @@ export class GpuResidencyCache {
|
|
|
1093
1094
|
*/
|
|
1094
1095
|
getMeshGpuHandles(
|
|
1095
1096
|
handle: Handle<'MeshAsset', 'shared'>,
|
|
1096
|
-
worldId:
|
|
1097
|
+
worldId: RenderResourceScope | number = 0,
|
|
1097
1098
|
): MeshGpuHandles | undefined {
|
|
1098
1099
|
return this.meshGpuHandles.get(this.worldKey(Number(handle), worldId));
|
|
1099
1100
|
}
|
|
@@ -1101,7 +1102,7 @@ export class GpuResidencyCache {
|
|
|
1101
1102
|
/** Candidate leases retain the concrete allocation even after cache invalidation. */
|
|
1102
1103
|
retainMeshResidency(
|
|
1103
1104
|
handle: Handle<'MeshAsset', 'shared'>,
|
|
1104
|
-
worldId:
|
|
1105
|
+
worldId: RenderResourceScope | number = 0,
|
|
1105
1106
|
): MeshResidencyLease | undefined {
|
|
1106
1107
|
const key = this.worldKey(Number(handle), worldId);
|
|
1107
1108
|
const entry = this.meshGpuHandles.get(key);
|
|
@@ -1114,7 +1115,7 @@ export class GpuResidencyCache {
|
|
|
1114
1115
|
}
|
|
1115
1116
|
|
|
1116
1117
|
/** In-place author changes immediately miss the cache; old submissions keep their allocation. */
|
|
1117
|
-
invalidateMesh(handle: number, worldId:
|
|
1118
|
+
invalidateMesh(handle: number, worldId: RenderResourceScope | number = 0): void {
|
|
1118
1119
|
const key = this.worldKey(handle, worldId);
|
|
1119
1120
|
const entry = this.meshGpuHandles.get(key);
|
|
1120
1121
|
if (entry !== undefined) this.retireMeshEntry(key, entry);
|
|
@@ -1137,18 +1138,18 @@ export class GpuResidencyCache {
|
|
|
1137
1138
|
ensureResident(
|
|
1138
1139
|
handle: Handle<'MeshAsset', 'shared'>,
|
|
1139
1140
|
pod: TypesMeshAsset,
|
|
1140
|
-
worldId?:
|
|
1141
|
+
worldId?: RenderResourceScope | number,
|
|
1141
1142
|
lodMeshes?: readonly TypesMeshAsset[],
|
|
1142
1143
|
): Result<MeshGpuHandles, RhiError | AssetError | ImageError>;
|
|
1143
1144
|
ensureResident(
|
|
1144
1145
|
handle: Handle<'TextureAsset', 'shared'>,
|
|
1145
1146
|
pod: TextureAsset,
|
|
1146
|
-
worldId?:
|
|
1147
|
+
worldId?: RenderResourceScope | number,
|
|
1147
1148
|
): Result<TextureGpuEntry, RhiError | AssetError | ImageError>;
|
|
1148
1149
|
ensureResident(
|
|
1149
1150
|
handle: Handle<'MeshAsset', 'shared'> | Handle<'TextureAsset', 'shared'>,
|
|
1150
1151
|
pod: TypesMeshAsset | TextureAsset,
|
|
1151
|
-
worldId:
|
|
1152
|
+
worldId: RenderResourceScope | number = 0,
|
|
1152
1153
|
lodMeshes: readonly TypesMeshAsset[] = [],
|
|
1153
1154
|
): Result<TextureGpuEntry | MeshGpuHandles, RhiError | AssetError | ImageError> {
|
|
1154
1155
|
const id = handleSlot(handle);
|
|
@@ -1218,17 +1219,17 @@ export class GpuResidencyCache {
|
|
|
1218
1219
|
prepareResidentForRecovery(
|
|
1219
1220
|
handle: Handle<'MeshAsset', 'shared'>,
|
|
1220
1221
|
pod: TypesMeshAsset,
|
|
1221
|
-
worldId?:
|
|
1222
|
+
worldId?: RenderResourceScope | number,
|
|
1222
1223
|
): Result<RecoveryResidencyPreparation, RhiError | AssetError | ImageError>;
|
|
1223
1224
|
prepareResidentForRecovery(
|
|
1224
1225
|
handle: Handle<'TextureAsset', 'shared'>,
|
|
1225
1226
|
pod: TextureAsset,
|
|
1226
|
-
worldId?:
|
|
1227
|
+
worldId?: RenderResourceScope | number,
|
|
1227
1228
|
): Result<RecoveryResidencyPreparation, RhiError | AssetError | ImageError>;
|
|
1228
1229
|
prepareResidentForRecovery(
|
|
1229
1230
|
handle: Handle<'MeshAsset', 'shared'> | Handle<'TextureAsset', 'shared'>,
|
|
1230
1231
|
pod: TypesMeshAsset | TextureAsset,
|
|
1231
|
-
worldId:
|
|
1232
|
+
worldId: RenderResourceScope | number = 0,
|
|
1232
1233
|
): Result<RecoveryResidencyPreparation, RhiError | AssetError | ImageError> {
|
|
1233
1234
|
const id = handleSlot(handle);
|
|
1234
1235
|
if (pod.kind === 'mesh') {
|
|
@@ -1316,7 +1317,7 @@ export class GpuResidencyCache {
|
|
|
1316
1317
|
handle: Handle<'TextureAsset', 'shared'>,
|
|
1317
1318
|
pod: TextureAsset,
|
|
1318
1319
|
decoded: DecodedImage,
|
|
1319
|
-
worldId:
|
|
1320
|
+
worldId: RenderResourceScope | number = 0,
|
|
1320
1321
|
): Promise<Result<void, AssetError | ImageError | RhiError>> {
|
|
1321
1322
|
const device = this.gpuDevice;
|
|
1322
1323
|
const projected = deriveRenderDataTexture(pod);
|
|
@@ -1392,7 +1393,7 @@ export class GpuResidencyCache {
|
|
|
1392
1393
|
pod: TextureAsset,
|
|
1393
1394
|
decoded: DecodedImage,
|
|
1394
1395
|
renderData: TextureRenderData,
|
|
1395
|
-
worldId:
|
|
1396
|
+
worldId: RenderResourceScope | number = 0,
|
|
1396
1397
|
): Result<TextureGpuEntry, AssetError | ImageError | RhiError> {
|
|
1397
1398
|
const device = this.gpuDevice;
|
|
1398
1399
|
const prepared = this.prepareTextureUpload(handle, pod, decoded, renderData);
|
|
@@ -1654,7 +1655,7 @@ export class GpuResidencyCache {
|
|
|
1654
1655
|
* retries by inferring "no entry => try again".
|
|
1655
1656
|
*/
|
|
1656
1657
|
async _uploadCubemapFromEquirect(
|
|
1657
|
-
world:
|
|
1658
|
+
world: RenderResourceScope,
|
|
1658
1659
|
sourceHandle: Handle<'EquirectAsset', 'shared'>,
|
|
1659
1660
|
sourcePod: EquirectAsset,
|
|
1660
1661
|
): Promise<Result<Handle<'EquirectAsset', 'shared'>, AssetError | RhiError>> {
|
|
@@ -1999,7 +2000,7 @@ export class GpuResidencyCache {
|
|
|
1999
2000
|
view: cubeView,
|
|
2000
2001
|
faceViews,
|
|
2001
2002
|
});
|
|
2002
|
-
const regResult = registerCube(world, cubeAsset);
|
|
2003
|
+
const regResult = registerCube(world, cubeAsset, sourceHandle);
|
|
2003
2004
|
if (!regResult.ok) return recordFailed(regResult.error);
|
|
2004
2005
|
const cubeHandle = regResult.value;
|
|
2005
2006
|
const cubeId = handleSlot(cubeHandle);
|
|
@@ -2252,7 +2253,7 @@ export class GpuResidencyCache {
|
|
|
2252
2253
|
handle: Handle<'MeshAsset', 'shared'>,
|
|
2253
2254
|
newVertices: Float32Array,
|
|
2254
2255
|
newIndices: Uint16Array,
|
|
2255
|
-
worldId:
|
|
2256
|
+
worldId: RenderResourceScope | number = 0,
|
|
2256
2257
|
submeshes?: readonly Submesh[],
|
|
2257
2258
|
): void {
|
|
2258
2259
|
const id = this.worldKey(handleSlot(handle), worldId);
|
package/src/errors/render.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { RenderPublicationError } from '../publication/contract';
|
|
1
2
|
// @forgeax/engine-render -- render cluster error classes.
|
|
2
3
|
//
|
|
3
4
|
// feat-20260704-runtime-tier1-decomposition M2 / w8 (D-3): the monolithic
|
|
@@ -562,7 +563,7 @@ export class PointShadowAtlasBoundsViolationError extends Error {
|
|
|
562
563
|
* Fired by the per-frame record stage (`videoTextureView`) when a VideoPlayer
|
|
563
564
|
* entity can reach neither video upload path this frame: the general
|
|
564
565
|
* `copyExternalImageToTexture` path (no host HTMLVideoElement resolved via
|
|
565
|
-
* `
|
|
566
|
+
* `VideoSourceProvider`) AND the high-perf `GPUExternalTexture` path
|
|
566
567
|
* (capability absent). The engine surfaces this explicit failure rather than
|
|
567
568
|
* silently rendering a stale/garbage texture (charter P3, plan-strategy D-6).
|
|
568
569
|
* - `.code = 'video-upload-unsupported'`
|
|
@@ -1980,6 +1981,7 @@ export type RenderErrorCode = RenderError['code'];
|
|
|
1980
1981
|
* `RenderErrorCode` discriminant on `.code`.
|
|
1981
1982
|
*/
|
|
1982
1983
|
export type RenderError =
|
|
1984
|
+
| RenderPublicationError
|
|
1983
1985
|
| LifecycleConstructionError
|
|
1984
1986
|
| AutoExposureError
|
|
1985
1987
|
| RendererExpectedOperationError
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { MaterialCookProgramContext } from '@forgeax/engine-pack/material-cook';
|
|
2
|
+
import type { RhiCaps } from '@forgeax/engine-rhi';
|
|
3
|
+
|
|
4
|
+
/** The receiving device selects the immutable material program domain. */
|
|
5
|
+
export function renderMaterialContext(caps: Pick<RhiCaps, 'backendKind' | 'storageBuffer'>): {
|
|
6
|
+
readonly materialContext?: MaterialCookProgramContext;
|
|
7
|
+
} {
|
|
8
|
+
if (caps.backendKind === 'null') return {};
|
|
9
|
+
return {
|
|
10
|
+
materialContext: {
|
|
11
|
+
backend: caps.backendKind === 'wgpu-webgl2' ? 'webgl2' : caps.backendKind,
|
|
12
|
+
capability: caps.storageBuffer ? 'storage-buffer' : 'uniform-fallback',
|
|
13
|
+
pipeline: 'forward',
|
|
14
|
+
geometry: 'mesh',
|
|
15
|
+
pass: 'forward',
|
|
16
|
+
profile: 'forgeax-material-wgsl-v1',
|
|
17
|
+
toolchain: 'naga-oil',
|
|
18
|
+
instrumentation: 'none',
|
|
19
|
+
},
|
|
20
|
+
};
|
|
21
|
+
}
|