@forgeax/engine-render 0.1.23 → 0.1.24
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +131 -9
- package/dist/assembly/bundler-contract.d.ts +9 -0
- package/dist/assembly/bundler-contract.d.ts.map +1 -0
- package/dist/assembly/device-feature-admission.d.ts +8 -0
- package/dist/assembly/device-feature-admission.d.ts.map +1 -1
- package/dist/assembly/extended-lighting-fallback.d.ts +13 -0
- package/dist/assembly/extended-lighting-fallback.d.ts.map +1 -0
- package/dist/assembly/factory.d.ts +7 -243
- package/dist/assembly/factory.d.ts.map +1 -1
- package/dist/assembly/material/assembly.d.ts +3 -2
- package/dist/assembly/material/assembly.d.ts.map +1 -1
- package/dist/assembly/material/standard-layer-projection.d.ts +10 -0
- package/dist/assembly/material/standard-layer-projection.d.ts.map +1 -0
- package/dist/assembly/material-shader-policy.d.ts +168 -0
- package/dist/assembly/material-shader-policy.d.ts.map +1 -0
- package/dist/assembly/material-shader-prewarm.d.ts +21 -0
- package/dist/assembly/material-shader-prewarm.d.ts.map +1 -0
- package/dist/assembly/mesh-ssbo-grow.d.ts +88 -0
- package/dist/assembly/mesh-ssbo-grow.d.ts.map +1 -0
- package/dist/assembly/recovery/device-loss-fanout.d.ts +14 -0
- package/dist/assembly/recovery/device-loss-fanout.d.ts.map +1 -0
- package/dist/assembly/recovery/generation.d.ts +46 -0
- package/dist/assembly/recovery/generation.d.ts.map +1 -0
- package/dist/assembly/recovery/recovery-attempt.d.ts +63 -0
- package/dist/assembly/recovery/recovery-attempt.d.ts.map +1 -0
- package/dist/assembly/recovery/renderer-recover.d.ts +115 -0
- package/dist/assembly/recovery/renderer-recover.d.ts.map +1 -0
- package/dist/assembly/renderer-facade.d.ts +10 -0
- package/dist/assembly/renderer-facade.d.ts.map +1 -0
- package/dist/assembly/renderer-frame-transaction.d.ts +17 -0
- package/dist/assembly/renderer-frame-transaction.d.ts.map +1 -1
- package/dist/assembly/renderer-helpers.d.ts +19 -0
- package/dist/assembly/renderer-helpers.d.ts.map +1 -0
- package/dist/assembly/renderer-lifecycle.d.ts +34 -0
- package/dist/assembly/renderer-lifecycle.d.ts.map +1 -1
- package/dist/assembly/shader-prewarm-policy.d.ts +15 -0
- package/dist/assembly/shader-prewarm-policy.d.ts.map +1 -0
- package/dist/assembly/webgpu-ready-contract.d.ts +9 -0
- package/dist/assembly/webgpu-ready-contract.d.ts.map +1 -0
- package/dist/assembly/webgpu-ready.d.ts +55 -0
- package/dist/assembly/webgpu-ready.d.ts.map +1 -0
- package/dist/assembly/webgpu-renderer.d.ts +152 -0
- package/dist/assembly/webgpu-renderer.d.ts.map +1 -0
- package/dist/authoring.mjs +1 -1
- package/dist/{chunk-4L3P6DT5.mjs → chunk-GE3SDD72.mjs} +37 -5
- package/dist/chunk-GE3SDD72.mjs.map +1 -0
- package/dist/{chunk-HZUPSYW7.mjs → chunk-KZFTK6DO.mjs} +102 -15
- package/dist/chunk-KZFTK6DO.mjs.map +1 -0
- package/dist/{chunk-FF7K3FSO.mjs → chunk-Q752SHI5.mjs} +89 -89
- package/dist/{chunk-FF7K3FSO.mjs.map → chunk-Q752SHI5.mjs.map} +1 -1
- package/dist/{chunk-QODA5UKU.mjs → chunk-RR5L4SRS.mjs} +2 -2
- package/dist/chunk-RR5L4SRS.mjs.map +1 -0
- package/dist/{chunk-YALPS44A.mjs → chunk-TFH5I7JJ.mjs} +47 -47
- package/dist/chunk-TFH5I7JJ.mjs.map +1 -0
- package/dist/{chunk-FBC4R44J.mjs → chunk-UQYS7FRM.mjs} +57 -57
- package/dist/chunk-UQYS7FRM.mjs.map +1 -0
- package/dist/{chunk-4NPUASZR.mjs → chunk-YKB5DQV7.mjs} +161 -19
- package/dist/chunk-YKB5DQV7.mjs.map +1 -0
- package/dist/{chunk-ZUWKAZ2I.mjs → chunk-YRUYGA4A.mjs} +615 -237
- package/dist/chunk-YRUYGA4A.mjs.map +1 -0
- package/dist/{chunk-DIYW3M5D.mjs → chunk-Z3YYH2MB.mjs} +2210 -2213
- package/dist/chunk-Z3YYH2MB.mjs.map +1 -0
- package/dist/construct-renderer.mjs +19841 -16190
- package/dist/construct-renderer.mjs.map +1 -1
- package/dist/device/device-scope.d.ts +2 -0
- package/dist/device/device-scope.d.ts.map +1 -1
- package/dist/device/gpu-residency.d.ts +24 -4
- package/dist/device/gpu-residency.d.ts.map +1 -1
- package/dist/environment/frame.d.ts +5 -0
- package/dist/environment/frame.d.ts.map +1 -1
- package/dist/environment/inspection.d.ts +7 -0
- package/dist/environment/inspection.d.ts.map +1 -1
- package/dist/environment/lifecycle.d.ts +20 -2
- package/dist/environment/lifecycle.d.ts.map +1 -1
- package/dist/errors/recover.d.ts +58 -2
- package/dist/errors/recover.d.ts.map +1 -1
- package/dist/errors/render.d.ts +13 -0
- package/dist/errors/render.d.ts.map +1 -1
- package/dist/extract/contracts.d.ts +899 -0
- package/dist/extract/contracts.d.ts.map +1 -0
- package/dist/features/host.d.ts +2 -0
- package/dist/features/host.d.ts.map +1 -1
- package/dist/features/prepared-gpu-work.d.ts +3 -0
- package/dist/features/prepared-gpu-work.d.ts.map +1 -1
- package/dist/features/prepared-graphics-store.d.ts +2 -0
- package/dist/features/prepared-graphics-store.d.ts.map +1 -1
- package/dist/gpu-driven/production-raster.d.ts +28 -0
- package/dist/gpu-driven/production-raster.d.ts.map +1 -1
- package/dist/gpu-scene.d.ts +1 -0
- package/dist/gpu-scene.d.ts.map +1 -1
- package/dist/ibl/IblPipelineCache.d.ts +7 -6
- package/dist/ibl/IblPipelineCache.d.ts.map +1 -1
- package/dist/ibl/skylight-bind-group.d.ts +7 -1
- package/dist/ibl/skylight-bind-group.d.ts.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.mjs +6 -6
- package/dist/internal.mjs +6 -6
- package/dist/light-buffer-layout.d.ts +3 -0
- package/dist/light-buffer-layout.d.ts.map +1 -1
- package/dist/materials.d.ts +34 -10
- package/dist/materials.d.ts.map +1 -1
- package/dist/mesh-material-bindings.d.ts +56 -0
- package/dist/mesh-material-bindings.d.ts.map +1 -1
- package/dist/occlusion-proxy.d.ts +4 -0
- package/dist/occlusion-proxy.d.ts.map +1 -0
- package/dist/pbr-pipeline.d.ts +32 -9
- package/dist/pbr-pipeline.d.ts.map +1 -1
- package/dist/points-lines/prepare.d.ts +3 -0
- package/dist/points-lines/prepare.d.ts.map +1 -1
- package/dist/points-lines/standard-owner.d.ts +33 -0
- package/dist/points-lines/standard-owner.d.ts.map +1 -0
- package/dist/record/frame-snapshot.d.ts +5 -0
- package/dist/record/frame-snapshot.d.ts.map +1 -1
- package/dist/record/frame-targets.d.ts.map +1 -1
- package/dist/record/frame.d.ts +14 -2
- package/dist/record/frame.d.ts.map +1 -1
- package/dist/record/main-pass-geometry.d.ts +14 -1
- package/dist/record/main-pass-geometry.d.ts.map +1 -1
- package/dist/record/main-pass-material.d.ts +7 -17
- package/dist/record/main-pass-material.d.ts.map +1 -1
- package/dist/record/main-pass.d.ts.map +1 -1
- package/dist/record/mesh-ssbo.d.ts +11 -3
- package/dist/record/mesh-ssbo.d.ts.map +1 -1
- package/dist/record/recovery-pipeline.d.ts +30 -0
- package/dist/record/recovery-pipeline.d.ts.map +1 -0
- package/dist/record/render-context.d.ts +26 -4
- package/dist/record/render-context.d.ts.map +1 -1
- package/dist/record/typed-frame-graph.d.ts +1 -1
- package/dist/record/typed-frame-graph.d.ts.map +1 -1
- package/dist/recovery/render-system-candidate.d.ts +65 -0
- package/dist/recovery/render-system-candidate.d.ts.map +1 -0
- package/dist/render-contract.d.ts +64 -7
- package/dist/render-contract.d.ts.map +1 -1
- package/dist/render-system-extract-tail.d.ts +12 -0
- package/dist/render-system-extract-tail.d.ts.map +1 -0
- package/dist/render-system-extract.d.ts +156 -22
- package/dist/render-system-extract.d.ts.map +1 -1
- package/dist/render-system.d.ts +128 -4
- package/dist/render-system.d.ts.map +1 -1
- package/dist/scene/render-scene.d.ts +19 -0
- package/dist/scene/render-scene.d.ts.map +1 -1
- package/dist/temporal/frame-coordinator.d.ts.map +1 -1
- package/dist/temporal/index.mjs +6 -6
- package/dist/temporal/taa-history-store.d.ts +15 -1
- package/dist/temporal/taa-history-store.d.ts.map +1 -1
- package/dist/temporal/transaction.d.ts +5 -0
- package/dist/temporal/transaction.d.ts.map +1 -1
- package/package.json +20 -20
- package/src/__tests__/device-feature-admission.unit.test.ts +6 -0
- package/src/__tests__/device-loss-fanout.unit.test.ts +107 -0
- package/src/__tests__/device-scope-lifecycle.unit.test.ts +21 -0
- package/src/__tests__/environment-generation.integration.test.ts +23 -0
- package/src/__tests__/expose-renderer-errors.unit.test.ts +34 -0
- package/src/__tests__/factory-contract.integration.test.ts +122 -7
- package/src/__tests__/fallback-row-stride-surface.unit.test.ts +4 -1
- package/src/__tests__/ibl/face-uniforms.unit.test.ts +2 -0
- package/src/__tests__/ibl-residency-publication.unit.test.ts +113 -0
- package/src/__tests__/material-contract-inventory.unit.test.ts +24 -9
- package/src/__tests__/material-cooked-projection.unit.test.ts +19 -1
- package/src/__tests__/material-static-dynamic-route.unit.test.ts +29 -0
- package/src/__tests__/material-stride-surface.unit.test.ts +7 -3
- package/src/__tests__/materials-standard-contract.unit.test.ts +104 -0
- package/src/__tests__/mesh-buffer-usage-surface.unit.test.ts +1 -1
- package/src/__tests__/physical-clearcoat.integration.test.ts +89 -0
- package/src/__tests__/prepared-gpu-driven-pbr.integration.test.ts +1 -1
- package/src/__tests__/prepared-graphics-pipeline-warmup.unit.test.ts +1 -1
- package/src/__tests__/recover-error-policy-owner.unit.test.ts +6 -3
- package/src/__tests__/recovery-candidate-prepare.contract.test.ts +140 -0
- package/src/__tests__/renderer-factory-material-contract.unit.test.ts +85 -18
- package/src/__tests__/renderer-frame-generation-fence.integration.test.ts +47 -0
- package/src/__tests__/renderer-generation-assembly.unit.test.ts +77 -0
- package/src/__tests__/renderer-generation-failure.unit.test.ts +108 -0
- package/src/__tests__/renderer-producer-root-matrix.integration.test.ts +33 -0
- package/src/__tests__/renderer-recovery-capability-matrix.unit.test.ts +59 -0
- package/src/__tests__/renderer-recovery-contract.unit.test.ts +73 -0
- package/src/__tests__/renderer-recovery-lifecycle.unit.test.ts +216 -0
- package/src/__tests__/renderer-target-history-recovery.integration.test.ts +80 -0
- package/src/__tests__/shader-manifest-fixture.ts +13 -16
- package/src/__tests__/shader-stage-surface.unit.test.ts +1 -1
- package/src/__tests__/standard-layer-projection.unit.test.ts +23 -0
- package/src/__tests__/transmission-prewarm.unit.test.ts +95 -85
- package/src/__tests__/volumetric-fog-topology.unit.test.ts +3 -1
- package/src/assembly/bundler-contract.ts +9 -0
- package/src/assembly/device-feature-admission.ts +15 -5
- package/src/assembly/extended-lighting-fallback.ts +216 -0
- package/src/assembly/factory.ts +81 -10088
- package/src/assembly/material/assembly.ts +18 -2
- package/src/assembly/material/standard-layer-projection.ts +16 -0
- package/src/assembly/material-shader-policy.ts +854 -0
- package/src/assembly/material-shader-prewarm.ts +88 -0
- package/src/assembly/mesh-ssbo-grow.ts +270 -0
- package/src/assembly/recovery/device-loss-fanout.ts +89 -0
- package/src/assembly/recovery/generation.ts +141 -0
- package/src/assembly/recovery/recovery-attempt.ts +800 -0
- package/src/assembly/recovery/renderer-recover.ts +906 -0
- package/src/assembly/renderer-facade.ts +342 -0
- package/src/assembly/renderer-frame-transaction.ts +45 -0
- package/src/assembly/renderer-helpers.ts +99 -0
- package/src/assembly/renderer-lifecycle.ts +159 -0
- package/src/assembly/shader-prewarm-policy.ts +157 -0
- package/src/assembly/webgpu-ready-contract.ts +14 -0
- package/src/assembly/webgpu-ready.ts +4079 -0
- package/src/assembly/webgpu-renderer.ts +4095 -0
- package/src/components/camera.ts +1 -1
- package/src/debug-draw-glue.ts +1 -1
- package/src/device/device-scope.ts +35 -6
- package/src/device/gpu-residency.ts +194 -26
- package/src/environment/frame.ts +6 -0
- package/src/environment/inspection.ts +10 -0
- package/src/environment/lifecycle.ts +114 -8
- package/src/errors/recover.ts +76 -5
- package/src/errors/render.ts +17 -0
- package/src/extract/contracts.ts +974 -0
- package/src/features/host.ts +16 -0
- package/src/features/prepared-gpu-work.ts +20 -2
- package/src/features/prepared-graphics-store.ts +17 -0
- package/src/gpu-driven/production-raster.ts +97 -2
- package/src/gpu-scene.ts +3 -2
- package/src/ibl/IblPipelineCache.ts +134 -50
- package/src/ibl/skylight-bind-group.ts +26 -0
- package/src/index.ts +9 -1
- package/src/light-buffer-layout.ts +3 -0
- package/src/materials.ts +262 -45
- package/src/mesh-material-bindings.ts +59 -0
- package/src/occlusion-proxy.ts +64 -0
- package/src/pbr-pipeline.ts +139 -15
- package/src/points-lines/__tests__/cache-recovery.unit.test.ts +22 -0
- package/src/points-lines/prepare.ts +9 -0
- package/src/points-lines/standard-owner.ts +403 -0
- package/src/record/__tests__/frame-targets-recovery.unit.test.ts +60 -0
- package/src/record/__tests__/main-pass-geometry.unit.test.ts +26 -1
- package/src/record/__tests__/mesh-ssbo.unit.test.ts +38 -0
- package/src/record/__tests__/recovery-pipeline.unit.test.ts +124 -0
- package/src/record/__tests__/sprite-material-abi.unit.test.ts +28 -13
- package/src/record/__tests__/standard-pbr-ubo-layout.unit.test.ts +47 -4
- package/src/record/__tests__/temporal-payload.unit.test.ts +22 -43
- package/src/record/__tests__/typed-frame-graph-plan.unit.test.ts +1 -1
- package/src/record/frame-snapshot.ts +15 -0
- package/src/record/frame-targets.ts +11 -1
- package/src/record/frame.ts +6 -2
- package/src/record/helpers.ts +1 -1
- package/src/record/main-pass-geometry.ts +230 -5
- package/src/record/main-pass-material.ts +316 -209
- package/src/record/main-pass-sprite-draws.ts +6 -7
- package/src/record/main-pass.ts +94 -6
- package/src/record/mesh-ssbo.ts +32 -10
- package/src/record/recovery-pipeline.ts +695 -0
- package/src/record/render-context.ts +35 -4
- package/src/record/typed-frame-graph.ts +45 -1
- package/src/record/view-ubo.ts +3 -3
- package/src/recovery/render-system-candidate.ts +839 -0
- package/src/render-contract.ts +65 -7
- package/src/render-system-extract-tail.ts +2983 -0
- package/src/render-system-extract.ts +124 -2977
- package/src/render-system.ts +868 -659
- package/src/scene/render-scene.ts +124 -1
- package/src/temporal/frame-coordinator.ts +4 -1
- package/src/temporal/taa-history-store.ts +46 -2
- package/src/temporal/temporal-view.ts +1 -1
- package/src/temporal/transaction.ts +9 -0
- package/src/tilemap-chunk-extract-system.ts +1 -1
- package/src/transmission/__tests__/standard-transmission.dawn.test.ts +19 -12
- package/dist/chunk-4L3P6DT5.mjs.map +0 -1
- package/dist/chunk-4NPUASZR.mjs.map +0 -1
- package/dist/chunk-DIYW3M5D.mjs.map +0 -1
- package/dist/chunk-FBC4R44J.mjs.map +0 -1
- package/dist/chunk-HZUPSYW7.mjs.map +0 -1
- package/dist/chunk-QODA5UKU.mjs.map +0 -1
- package/dist/chunk-YALPS44A.mjs.map +0 -1
- package/dist/chunk-ZUWKAZ2I.mjs.map +0 -1
|
@@ -27,7 +27,6 @@ import {
|
|
|
27
27
|
type BindGroup,
|
|
28
28
|
type BindGroupLayout,
|
|
29
29
|
type Buffer,
|
|
30
|
-
type CommandBuffer,
|
|
31
30
|
err,
|
|
32
31
|
ok,
|
|
33
32
|
type RenderPipeline,
|
|
@@ -93,9 +92,8 @@ export interface IblPipelineError {
|
|
|
93
92
|
* Per-DeviceScope-generation IBL pipeline cache instance.
|
|
94
93
|
*
|
|
95
94
|
* M3.5 (round-2 t52): the 4 pipeline slots are mutable so createIblPipelines
|
|
96
|
-
* can fill them after construction. The
|
|
97
|
-
*
|
|
98
|
-
* (idempotent).
|
|
95
|
+
* can fill them after construction. The output textures and views are
|
|
96
|
+
* promoted here only after a completed precompute submission.
|
|
99
97
|
*/
|
|
100
98
|
export interface IblPipelineCache {
|
|
101
99
|
/** Reusable generation-scoped kernel state; per-probe outputs stay elsewhere. */
|
|
@@ -604,6 +602,17 @@ export interface RunIblPrecomputeOptions {
|
|
|
604
602
|
readonly cubeVertexBuffer: Buffer;
|
|
605
603
|
}
|
|
606
604
|
|
|
605
|
+
interface IblPrecomputeCandidate {
|
|
606
|
+
irradianceTexture: Texture;
|
|
607
|
+
irradianceView: TextureView;
|
|
608
|
+
irradianceFaceViews: ReadonlyArray<TextureView>;
|
|
609
|
+
prefilterTexture: Texture;
|
|
610
|
+
prefilterView: TextureView;
|
|
611
|
+
prefilterFaceViewsByMip: ReadonlyArray<ReadonlyArray<TextureView>>;
|
|
612
|
+
brdfLutTexture: Texture;
|
|
613
|
+
brdfLutView: TextureView;
|
|
614
|
+
}
|
|
615
|
+
|
|
607
616
|
export interface IblPrecomputeError {
|
|
608
617
|
readonly code: 'ibl-precompute-not-dispatched';
|
|
609
618
|
readonly expected: string;
|
|
@@ -613,7 +622,9 @@ export interface IblPrecomputeError {
|
|
|
613
622
|
|
|
614
623
|
/**
|
|
615
624
|
* Execute the 4 IBL precompute passes (equirect-to-cube / irradiance /
|
|
616
|
-
* prefilter / brdf-lut)
|
|
625
|
+
* prefilter / brdf-lut) as ordered, stage-bounded submissions. Outputs stay
|
|
626
|
+
* candidate-local until every queue completion fence and generation check
|
|
627
|
+
* pass.
|
|
617
628
|
*
|
|
618
629
|
* Counter invariant (AC-20, plan D-7 / N-3): the
|
|
619
630
|
* `irradiance/prefilter/brdfLut BakeCount` counters are incremented
|
|
@@ -625,12 +636,19 @@ export interface IblPrecomputeError {
|
|
|
625
636
|
* underlying device lacks queue.submit or one of the 4 pipelines was not
|
|
626
637
|
* created (createIblPipelines must run first).
|
|
627
638
|
*/
|
|
628
|
-
export function runIblPrecompute(
|
|
639
|
+
export async function runIblPrecompute(
|
|
629
640
|
opts: RunIblPrecomputeOptions,
|
|
630
|
-
): Result<{ submitted: boolean }, IblPrecomputeError
|
|
641
|
+
): Promise<Result<{ submitted: boolean }, IblPrecomputeError>> {
|
|
631
642
|
const { device, scope } = opts;
|
|
632
643
|
const cache = getOrCreateIblCache(scope);
|
|
633
644
|
const outputFormat = cache.outputFormat ?? 'rgba16float';
|
|
645
|
+
const generation = scope.generation;
|
|
646
|
+
const candidate: Partial<IblPrecomputeCandidate> = {};
|
|
647
|
+
const fail = (stage: string, cause?: RhiError): Promise<Result<never, IblPrecomputeError>> => {
|
|
648
|
+
// Candidate textures are adopted by the DeviceScope immediately after
|
|
649
|
+
// allocation, so every failure is retired with the owning generation.
|
|
650
|
+
return Promise.resolve(err(badAlloc(stage, cause)));
|
|
651
|
+
};
|
|
634
652
|
|
|
635
653
|
if (
|
|
636
654
|
cache.equirectToCubePipeline === undefined ||
|
|
@@ -652,7 +670,7 @@ export function runIblPrecompute(
|
|
|
652
670
|
// requires the TextureUsage::CopySrc bit on the source. Without it
|
|
653
671
|
// Dawn fails-fast "usage doesn't include CopySrc".
|
|
654
672
|
|
|
655
|
-
|
|
673
|
+
{
|
|
656
674
|
const textureResult = device.createTexture({
|
|
657
675
|
label: 'ibl-irradiance-cube',
|
|
658
676
|
size: { width: IRRADIANCE_SIZE, height: IRRADIANCE_SIZE, depthOrArrayLayers: 6 },
|
|
@@ -667,15 +685,15 @@ export function runIblPrecompute(
|
|
|
667
685
|
viewFormats: [],
|
|
668
686
|
textureBindingViewDimension: undefined,
|
|
669
687
|
});
|
|
670
|
-
if (!textureResult.ok) return
|
|
671
|
-
|
|
688
|
+
if (!textureResult.ok) return fail('irradiance-texture', textureResult.error);
|
|
689
|
+
candidate.irradianceTexture = adoptIblTexture(scope, device, textureResult.value);
|
|
672
690
|
const cubeViewResult = device.createTextureView(textureResult.value, {
|
|
673
691
|
label: 'ibl-irradiance-cube-view',
|
|
674
692
|
dimension: 'cube',
|
|
675
693
|
arrayLayerCount: 6,
|
|
676
694
|
});
|
|
677
|
-
if (!cubeViewResult.ok) return
|
|
678
|
-
|
|
695
|
+
if (!cubeViewResult.ok) return fail('irradiance-view', cubeViewResult.error);
|
|
696
|
+
candidate.irradianceView = cubeViewResult.value;
|
|
679
697
|
const faceViews: TextureView[] = [];
|
|
680
698
|
for (let f = 0; f < 6; f++) {
|
|
681
699
|
const viewResult = device.createTextureView(textureResult.value, {
|
|
@@ -684,13 +702,13 @@ export function runIblPrecompute(
|
|
|
684
702
|
baseArrayLayer: f,
|
|
685
703
|
arrayLayerCount: 1,
|
|
686
704
|
});
|
|
687
|
-
if (!viewResult.ok) return
|
|
705
|
+
if (!viewResult.ok) return fail('irradiance-face-view', viewResult.error);
|
|
688
706
|
faceViews.push(viewResult.value);
|
|
689
707
|
}
|
|
690
|
-
|
|
708
|
+
candidate.irradianceFaceViews = faceViews;
|
|
691
709
|
}
|
|
692
710
|
|
|
693
|
-
|
|
711
|
+
{
|
|
694
712
|
const textureResult = device.createTexture({
|
|
695
713
|
label: 'ibl-prefilter-cube',
|
|
696
714
|
size: { width: PREFILTER_SIZE, height: PREFILTER_SIZE, depthOrArrayLayers: 6 },
|
|
@@ -705,8 +723,8 @@ export function runIblPrecompute(
|
|
|
705
723
|
viewFormats: [],
|
|
706
724
|
textureBindingViewDimension: undefined,
|
|
707
725
|
});
|
|
708
|
-
if (!textureResult.ok) return
|
|
709
|
-
|
|
726
|
+
if (!textureResult.ok) return fail('prefilter-texture', textureResult.error);
|
|
727
|
+
candidate.prefilterTexture = adoptIblTexture(scope, device, textureResult.value);
|
|
710
728
|
const cubeViewResult = device.createTextureView(textureResult.value, {
|
|
711
729
|
label: 'ibl-prefilter-cube-view',
|
|
712
730
|
dimension: 'cube',
|
|
@@ -714,8 +732,8 @@ export function runIblPrecompute(
|
|
|
714
732
|
baseMipLevel: 0,
|
|
715
733
|
mipLevelCount: PREFILTER_MIP_LEVELS,
|
|
716
734
|
});
|
|
717
|
-
if (!cubeViewResult.ok) return
|
|
718
|
-
|
|
735
|
+
if (!cubeViewResult.ok) return fail('prefilter-view', cubeViewResult.error);
|
|
736
|
+
candidate.prefilterView = cubeViewResult.value;
|
|
719
737
|
const mipViews: TextureView[][] = [];
|
|
720
738
|
for (let m = 0; m < PREFILTER_MIP_LEVELS; m++) {
|
|
721
739
|
const faces: TextureView[] = [];
|
|
@@ -728,15 +746,15 @@ export function runIblPrecompute(
|
|
|
728
746
|
baseArrayLayer: f,
|
|
729
747
|
arrayLayerCount: 1,
|
|
730
748
|
});
|
|
731
|
-
if (!viewResult.ok) return
|
|
749
|
+
if (!viewResult.ok) return fail('prefilter-face-view', viewResult.error);
|
|
732
750
|
faces.push(viewResult.value);
|
|
733
751
|
}
|
|
734
752
|
mipViews.push(faces);
|
|
735
753
|
}
|
|
736
|
-
|
|
754
|
+
candidate.prefilterFaceViewsByMip = mipViews;
|
|
737
755
|
}
|
|
738
756
|
|
|
739
|
-
|
|
757
|
+
{
|
|
740
758
|
const textureResult = device.createTexture({
|
|
741
759
|
label: 'ibl-brdf-lut',
|
|
742
760
|
size: { width: BRDF_LUT_SIZE, height: BRDF_LUT_SIZE, depthOrArrayLayers: 1 },
|
|
@@ -751,14 +769,14 @@ export function runIblPrecompute(
|
|
|
751
769
|
viewFormats: [],
|
|
752
770
|
textureBindingViewDimension: undefined,
|
|
753
771
|
});
|
|
754
|
-
if (!textureResult.ok) return
|
|
755
|
-
|
|
772
|
+
if (!textureResult.ok) return fail('brdf-lut-texture', textureResult.error);
|
|
773
|
+
candidate.brdfLutTexture = adoptIblTexture(scope, device, textureResult.value);
|
|
756
774
|
const viewResult = device.createTextureView(textureResult.value, {
|
|
757
775
|
label: 'ibl-brdf-lut-view',
|
|
758
776
|
dimension: '2d',
|
|
759
777
|
});
|
|
760
|
-
if (!viewResult.ok) return
|
|
761
|
-
|
|
778
|
+
if (!viewResult.ok) return fail('brdf-lut-view', viewResult.error);
|
|
779
|
+
candidate.brdfLutView = viewResult.value;
|
|
762
780
|
}
|
|
763
781
|
|
|
764
782
|
// Shared sampler (filtering, linear-linear).
|
|
@@ -773,12 +791,35 @@ export function runIblPrecompute(
|
|
|
773
791
|
addressModeV: 'clamp-to-edge',
|
|
774
792
|
addressModeW: 'clamp-to-edge',
|
|
775
793
|
});
|
|
776
|
-
if (!samplerResult.ok) return
|
|
794
|
+
if (!samplerResult.ok) return fail('sampler', samplerResult.error);
|
|
777
795
|
const sampler: Sampler = samplerResult.value;
|
|
778
796
|
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
797
|
+
let encoderResult = device.createCommandEncoder({
|
|
798
|
+
label: 'ibl-precompute-encoder-equirect-to-cube',
|
|
799
|
+
});
|
|
800
|
+
if (!encoderResult.ok) return fail('encoder-equirect-to-cube', encoderResult.error);
|
|
801
|
+
let encoder: RhiCommandEncoder = encoderResult.value;
|
|
802
|
+
|
|
803
|
+
const submitStage = async (stage: string, createNextEncoder: boolean) => {
|
|
804
|
+
const finishRes = encoder.finish();
|
|
805
|
+
if (!finishRes.ok) return err(badAlloc(`${stage}-finish`, finishRes.error));
|
|
806
|
+
const submitRes = device.queue.submit([finishRes.value]);
|
|
807
|
+
if (!submitRes.ok) return err(badAlloc(`${stage}-submit`, submitRes.error));
|
|
808
|
+
try {
|
|
809
|
+
await device.queue.onSubmittedWorkDone();
|
|
810
|
+
} catch {
|
|
811
|
+
return err(badAlloc(`${stage}-fence`));
|
|
812
|
+
}
|
|
813
|
+
if (!scope.isAlive() || scope.generation !== generation) {
|
|
814
|
+
return err(badAlloc(`${stage}-device-scope-generation`));
|
|
815
|
+
}
|
|
816
|
+
if (createNextEncoder) {
|
|
817
|
+
encoderResult = device.createCommandEncoder({ label: `ibl-precompute-encoder-${stage}` });
|
|
818
|
+
if (!encoderResult.ok) return err(badAlloc(`${stage}-next-encoder`, encoderResult.error));
|
|
819
|
+
encoder = encoderResult.value;
|
|
820
|
+
}
|
|
821
|
+
return ok(true);
|
|
822
|
+
};
|
|
782
823
|
|
|
783
824
|
const faceUniformsBgl = cache.faceUniformsBgl;
|
|
784
825
|
const equirectGroup1Bgl = cache.equirectGroup1Bgl;
|
|
@@ -788,9 +829,14 @@ export function runIblPrecompute(
|
|
|
788
829
|
const irradiancePipeline = cache.irradiancePipeline;
|
|
789
830
|
const prefilterPipeline = cache.prefilterPipeline;
|
|
790
831
|
const brdfLutPipeline = cache.brdfLutPipeline;
|
|
791
|
-
const
|
|
792
|
-
const
|
|
793
|
-
const
|
|
832
|
+
const candidateIrradianceTexture = candidate.irradianceTexture;
|
|
833
|
+
const candidateIrradianceView = candidate.irradianceView;
|
|
834
|
+
const irrFaceViews = candidate.irradianceFaceViews;
|
|
835
|
+
const candidatePrefilterTexture = candidate.prefilterTexture;
|
|
836
|
+
const candidatePrefilterView = candidate.prefilterView;
|
|
837
|
+
const prefMipViews = candidate.prefilterFaceViewsByMip;
|
|
838
|
+
const candidateBrdfLutTexture = candidate.brdfLutTexture;
|
|
839
|
+
const brdfLutView = candidate.brdfLutView;
|
|
794
840
|
if (
|
|
795
841
|
faceUniformsBgl === undefined ||
|
|
796
842
|
equirectGroup1Bgl === undefined ||
|
|
@@ -800,11 +846,16 @@ export function runIblPrecompute(
|
|
|
800
846
|
irradiancePipeline === undefined ||
|
|
801
847
|
prefilterPipeline === undefined ||
|
|
802
848
|
brdfLutPipeline === undefined ||
|
|
849
|
+
candidateIrradianceTexture === undefined ||
|
|
850
|
+
candidateIrradianceView === undefined ||
|
|
803
851
|
irrFaceViews === undefined ||
|
|
852
|
+
candidatePrefilterTexture === undefined ||
|
|
853
|
+
candidatePrefilterView === undefined ||
|
|
804
854
|
prefMipViews === undefined ||
|
|
855
|
+
candidateBrdfLutTexture === undefined ||
|
|
805
856
|
brdfLutView === undefined
|
|
806
857
|
) {
|
|
807
|
-
return
|
|
858
|
+
return fail('ibl-cache-resources');
|
|
808
859
|
}
|
|
809
860
|
|
|
810
861
|
// Bind group: equirect group(1).
|
|
@@ -816,7 +867,7 @@ export function runIblPrecompute(
|
|
|
816
867
|
{ binding: 1, resource: { kind: 'sampler', value: sampler } },
|
|
817
868
|
],
|
|
818
869
|
});
|
|
819
|
-
if (!equirectBgResult.ok) return
|
|
870
|
+
if (!equirectBgResult.ok) return fail('equirect-bg', equirectBgResult.error);
|
|
820
871
|
const equirectBg: BindGroup = equirectBgResult.value;
|
|
821
872
|
|
|
822
873
|
// Bind group: cube group(1) for irradiance + prefilter.
|
|
@@ -828,14 +879,14 @@ export function runIblPrecompute(
|
|
|
828
879
|
{ binding: 1, resource: { kind: 'sampler', value: sampler } },
|
|
829
880
|
],
|
|
830
881
|
});
|
|
831
|
-
if (!cubeBgResult.ok) return
|
|
882
|
+
if (!cubeBgResult.ok) return fail('cube-bg', cubeBgResult.error);
|
|
832
883
|
const cubeBg: BindGroup = cubeBgResult.value;
|
|
833
884
|
|
|
834
885
|
// (a) equirect-to-cube: 6 face draws.
|
|
835
886
|
const cubeFaceViews = opts.cubeFaceViews;
|
|
836
887
|
for (let face = 0; face < 6; face++) {
|
|
837
888
|
const cubeFaceView = cubeFaceViews[face];
|
|
838
|
-
if (cubeFaceView === undefined) return
|
|
889
|
+
if (cubeFaceView === undefined) return fail('cube-face-view');
|
|
839
890
|
const pass: RhiRenderPassEncoder = encoder.beginRenderPass({
|
|
840
891
|
label: 'ibl-equirect-to-cube',
|
|
841
892
|
colorAttachments: [
|
|
@@ -865,7 +916,7 @@ export function runIblPrecompute(
|
|
|
865
916
|
},
|
|
866
917
|
],
|
|
867
918
|
});
|
|
868
|
-
if (!faceBgResult.ok) return
|
|
919
|
+
if (!faceBgResult.ok) return fail('face-bg', faceBgResult.error);
|
|
869
920
|
pass.setPipeline(equirectPipeline);
|
|
870
921
|
pass.setBindGroup(0, faceBgResult.value);
|
|
871
922
|
pass.setBindGroup(1, equirectBg);
|
|
@@ -874,10 +925,13 @@ export function runIblPrecompute(
|
|
|
874
925
|
pass.end();
|
|
875
926
|
}
|
|
876
927
|
|
|
928
|
+
const cubeStage = await submitStage('equirect-to-cube', true);
|
|
929
|
+
if (!cubeStage.ok) return err(cubeStage.error);
|
|
930
|
+
|
|
877
931
|
// (b) irradiance convolve: 6 face draws.
|
|
878
932
|
for (let face = 0; face < 6; face++) {
|
|
879
933
|
const irrFaceView = irrFaceViews[face];
|
|
880
|
-
if (irrFaceView === undefined) return
|
|
934
|
+
if (irrFaceView === undefined) return fail('irradiance-face-view');
|
|
881
935
|
const pass: RhiRenderPassEncoder = encoder.beginRenderPass({
|
|
882
936
|
label: 'ibl-irradiance',
|
|
883
937
|
colorAttachments: [
|
|
@@ -906,23 +960,26 @@ export function runIblPrecompute(
|
|
|
906
960
|
},
|
|
907
961
|
],
|
|
908
962
|
});
|
|
909
|
-
if (!faceBgResult.ok) return
|
|
963
|
+
if (!faceBgResult.ok) return fail('irr-face-bg', faceBgResult.error);
|
|
910
964
|
pass.setPipeline(irradiancePipeline);
|
|
911
965
|
pass.setBindGroup(0, faceBgResult.value);
|
|
912
966
|
pass.setBindGroup(1, cubeBg);
|
|
913
967
|
pass.setVertexBuffer(0, opts.cubeVertexBuffer);
|
|
914
968
|
pass.draw(6, 1, face * 6, 0);
|
|
915
969
|
pass.end();
|
|
970
|
+
|
|
971
|
+
const irradianceFaceStage = await submitStage(`irradiance-face-${face}`, true);
|
|
972
|
+
if (!irradianceFaceStage.ok) return err(irradianceFaceStage.error);
|
|
916
973
|
}
|
|
917
974
|
|
|
918
975
|
// (c) prefilter env: 5 mips x 6 faces = 30 sub-passes.
|
|
919
976
|
for (let mip = 0; mip < PREFILTER_MIP_LEVELS; mip++) {
|
|
920
977
|
const mipFaceViews = prefMipViews[mip];
|
|
921
|
-
if (mipFaceViews === undefined) return
|
|
978
|
+
if (mipFaceViews === undefined) return fail('prefilter-mip-views');
|
|
922
979
|
for (let face = 0; face < 6; face++) {
|
|
923
980
|
const subIdx = mip * 6 + face;
|
|
924
981
|
const mipFaceView = mipFaceViews[face];
|
|
925
|
-
if (mipFaceView === undefined) return
|
|
982
|
+
if (mipFaceView === undefined) return fail('prefilter-face-view');
|
|
926
983
|
const pass: RhiRenderPassEncoder = encoder.beginRenderPass({
|
|
927
984
|
label: 'ibl-prefilter',
|
|
928
985
|
colorAttachments: [
|
|
@@ -962,7 +1019,7 @@ export function runIblPrecompute(
|
|
|
962
1019
|
},
|
|
963
1020
|
],
|
|
964
1021
|
});
|
|
965
|
-
if (!bgResult.ok) return
|
|
1022
|
+
if (!bgResult.ok) return fail('pref-bg', bgResult.error);
|
|
966
1023
|
pass.setPipeline(prefilterPipeline);
|
|
967
1024
|
pass.setBindGroup(0, bgResult.value);
|
|
968
1025
|
pass.setBindGroup(1, cubeBg);
|
|
@@ -972,6 +1029,9 @@ export function runIblPrecompute(
|
|
|
972
1029
|
}
|
|
973
1030
|
}
|
|
974
1031
|
|
|
1032
|
+
const prefilterStage = await submitStage('prefilter', true);
|
|
1033
|
+
if (!prefilterStage.ok) return err(prefilterStage.error);
|
|
1034
|
+
|
|
975
1035
|
// (d) brdf-lut: fullscreen triangle.
|
|
976
1036
|
{
|
|
977
1037
|
const pass: RhiRenderPassEncoder = encoder.beginRenderPass({
|
|
@@ -990,13 +1050,30 @@ export function runIblPrecompute(
|
|
|
990
1050
|
pass.end();
|
|
991
1051
|
}
|
|
992
1052
|
|
|
993
|
-
//
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
const
|
|
998
|
-
|
|
999
|
-
|
|
1053
|
+
// The final stage is fenced before the candidate is promoted.
|
|
1054
|
+
const brdfStage = await submitStage('brdf-lut', false);
|
|
1055
|
+
if (!brdfStage.ok) return err(brdfStage.error);
|
|
1056
|
+
|
|
1057
|
+
const promoted: IblPrecomputeCandidate = {
|
|
1058
|
+
irradianceTexture: candidateIrradianceTexture,
|
|
1059
|
+
irradianceView: candidateIrradianceView,
|
|
1060
|
+
irradianceFaceViews: irrFaceViews,
|
|
1061
|
+
prefilterTexture: candidatePrefilterTexture,
|
|
1062
|
+
prefilterView: candidatePrefilterView,
|
|
1063
|
+
prefilterFaceViewsByMip: prefMipViews,
|
|
1064
|
+
brdfLutTexture: candidateBrdfLutTexture,
|
|
1065
|
+
brdfLutView,
|
|
1066
|
+
};
|
|
1067
|
+
// Previous outputs remain DeviceScope-owned until scope retirement. This
|
|
1068
|
+
// avoids destroying a texture still referenced by an already-recorded pass.
|
|
1069
|
+
cache.irradianceTexture = promoted.irradianceTexture;
|
|
1070
|
+
cache.irradianceView = promoted.irradianceView;
|
|
1071
|
+
cache.irradianceFaceViews = promoted.irradianceFaceViews;
|
|
1072
|
+
cache.prefilterTexture = promoted.prefilterTexture;
|
|
1073
|
+
cache.prefilterView = promoted.prefilterView;
|
|
1074
|
+
cache.prefilterFaceViewsByMip = promoted.prefilterFaceViewsByMip;
|
|
1075
|
+
cache.brdfLutTexture = promoted.brdfLutTexture;
|
|
1076
|
+
cache.brdfLutView = promoted.brdfLutView;
|
|
1000
1077
|
|
|
1001
1078
|
// POST-SUBMIT counter increments (AC-20).
|
|
1002
1079
|
cache.irradianceBakeCount += 1;
|
|
@@ -1006,6 +1083,13 @@ export function runIblPrecompute(
|
|
|
1006
1083
|
return ok({ submitted: true });
|
|
1007
1084
|
}
|
|
1008
1085
|
|
|
1086
|
+
function adoptIblTexture(scope: DeviceScope, device: IblRhiOwner, texture: Texture): Texture {
|
|
1087
|
+
scope._adopt('texture', texture, (value) => {
|
|
1088
|
+
device.destroyTexture(value);
|
|
1089
|
+
});
|
|
1090
|
+
return texture;
|
|
1091
|
+
}
|
|
1092
|
+
|
|
1009
1093
|
// Local helper -- structured error payload shared across allocation paths.
|
|
1010
1094
|
function badAlloc(stage: string, cause?: RhiError): IblPrecomputeError {
|
|
1011
1095
|
return {
|
|
@@ -240,6 +240,13 @@ export interface TransmissionBindGroupResources {
|
|
|
240
240
|
readonly backdropView?: TextureView | null;
|
|
241
241
|
}
|
|
242
242
|
|
|
243
|
+
/** Engine-owned texture injection resources derived from material parameters. */
|
|
244
|
+
export interface TextureInjectionResource {
|
|
245
|
+
readonly slot: number;
|
|
246
|
+
readonly sampler: Sampler;
|
|
247
|
+
readonly view: TextureView;
|
|
248
|
+
}
|
|
249
|
+
|
|
243
250
|
// Lightmap (emissive + occlusion sampler/texture pair x 2) and transmission
|
|
244
251
|
// injection starts are computed from the assembled list length on each push —
|
|
245
252
|
// no hardcoded binding literals.
|
|
@@ -248,6 +255,7 @@ export function assembleMaterialWithSkylightEntries(
|
|
|
248
255
|
materialEntries: readonly BindGroupEntry[],
|
|
249
256
|
skylight: SkylightBindGroupResources,
|
|
250
257
|
transmission?: TransmissionBindGroupResources | undefined,
|
|
258
|
+
textureInjections: readonly TextureInjectionResource[] = [],
|
|
251
259
|
): BindGroupEntry[] {
|
|
252
260
|
// IBL injection start = end of the user-region. The user-region IS
|
|
253
261
|
// `materialEntries` (UBO binding 0 + N sampler/texture pairs), so its length
|
|
@@ -303,6 +311,24 @@ export function assembleMaterialWithSkylightEntries(
|
|
|
303
311
|
resource: { kind: 'textureView', value: transmissionView },
|
|
304
312
|
},
|
|
305
313
|
);
|
|
314
|
+
const clearcoatStart = result.length;
|
|
315
|
+
for (let index = 0; index < textureInjections.length; index += 1) {
|
|
316
|
+
const resource = textureInjections[index];
|
|
317
|
+
if (resource === undefined) continue;
|
|
318
|
+
// Slots are offsets from one stable injection base. Using the growing
|
|
319
|
+
// result length here made slot 1/2 drift past their BGL bindings.
|
|
320
|
+
const binding = clearcoatStart + resource.slot * 2;
|
|
321
|
+
result.push(
|
|
322
|
+
{
|
|
323
|
+
binding,
|
|
324
|
+
resource: { kind: 'sampler', value: resource.sampler },
|
|
325
|
+
},
|
|
326
|
+
{
|
|
327
|
+
binding: binding + 1,
|
|
328
|
+
resource: { kind: 'textureView', value: resource.view },
|
|
329
|
+
},
|
|
330
|
+
);
|
|
331
|
+
}
|
|
306
332
|
return result;
|
|
307
333
|
}
|
|
308
334
|
|
package/src/index.ts
CHANGED
|
@@ -196,7 +196,15 @@ export type {
|
|
|
196
196
|
ReflectionProbeSelectionInspection,
|
|
197
197
|
TransmissionInspection,
|
|
198
198
|
} from './inspection-types';
|
|
199
|
-
export {
|
|
199
|
+
export {
|
|
200
|
+
type MaterialColorInput3,
|
|
201
|
+
type MaterialColorInput4,
|
|
202
|
+
type MaterialColorTuple3,
|
|
203
|
+
type MaterialColorTuple4,
|
|
204
|
+
Materials,
|
|
205
|
+
MaterialTransmissionContractError,
|
|
206
|
+
srgb,
|
|
207
|
+
} from './materials';
|
|
200
208
|
export {
|
|
201
209
|
type MeshMaterialBindingObservation,
|
|
202
210
|
type MeshMaterialBindingPreparationFailure,
|
|
@@ -46,6 +46,9 @@ export const STORAGE_BUFFER_MIN_REQUIRED = 4;
|
|
|
46
46
|
|
|
47
47
|
/** Byte size of one Point/Spot/Rect DirectLightSlot. */
|
|
48
48
|
export const BYTES_PER_DIRECT_LIGHT_SLOT = 80;
|
|
49
|
+
/** std430 slot aliases retained for the WebGPU ready-state sizing table. */
|
|
50
|
+
export const POINT_LIGHT_STD430_BYTES = BYTES_PER_DIRECT_LIGHT_SLOT;
|
|
51
|
+
export const SPOT_LIGHT_STD430_BYTES = BYTES_PER_DIRECT_LIGHT_SLOT;
|
|
49
52
|
|
|
50
53
|
/**
|
|
51
54
|
* Cap gate at createRenderer time: check whether the device has enough
|