@forgeax/engine-runtime 0.1.27 → 0.1.29
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 +98 -0
- package/dist/collect-scene-asset.d.ts.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.mjs +480 -15
- package/dist/index.mjs.map +1 -1
- package/dist/scene-utils/mount-override-fold.d.ts +3 -1
- package/dist/scene-utils/mount-override-fold.d.ts.map +1 -1
- package/package.json +37 -30
- package/src/__tests__/animation-graph-collect-roundtrip.test.ts +4 -2
- package/src/__tests__/asset-registry-aabb.cases.unit.test.ts +5 -4
- package/src/__tests__/asset-registry-guid-reverse.test.ts +22 -27
- package/src/__tests__/asset-registry-mounts.test.ts +174 -734
- package/src/__tests__/asset-registry-scene.cases.unit.test.ts +9 -18
- package/src/__tests__/asset-registry.recursive.spec.ts +23 -29
- package/src/__tests__/camera-ortho.cases.unit.test.ts +12 -3
- package/src/__tests__/collect-scene-asset.test.ts +96 -113
- package/src/__tests__/collect-scene-mount-collapse.test.ts +64 -66
- package/src/__tests__/collect-transient-children-absent.test.ts +11 -17
- package/src/__tests__/collect-transient-roundtrip.test.ts +12 -13
- package/src/__tests__/collect-transient-skip.test.ts +20 -27
- package/src/__tests__/components.test-d.ts +17 -1
- package/src/__tests__/components.unit.test.ts +75 -27
- package/src/__tests__/composite-skybox-cross-world.browser.test.ts +4 -2
- package/src/__tests__/dawn/instances-per-instance-pbr.dawn.test.ts +8 -4
- package/src/__tests__/dawn/instances-shadow.dawn.test.ts +4 -1
- package/src/__tests__/dawn/instances-uniform-fallback.dawn.test.ts +66 -92
- package/src/__tests__/dawn/material-cooked-fixture.dawn.test.ts +200 -4
- package/src/__tests__/errors.unit.test.ts +13 -0
- package/src/__tests__/feature-depth-material.dawn.test.ts +23 -0
- package/src/__tests__/feature-depth-material.fixture.ts +473 -0
- package/src/__tests__/fullscreen-post-process-pass.dawn.test.ts +14 -14
- package/src/__tests__/geometry.unit.test.ts +42 -43
- package/src/__tests__/gpu-resource-release.cases.unit.test.ts +16 -9
- package/src/__tests__/handle-migration.test.ts +0 -1
- package/src/__tests__/instances-renderer-lifecycle.integration.test.ts +20 -14
- package/src/__tests__/instances.test-d.ts +13 -52
- package/src/__tests__/instantiate-mount-deferred-wiring.test.ts +42 -80
- package/src/__tests__/lazy-catalog.cases.unit.test.ts +17 -3
- package/src/__tests__/loader-registry.cases.unit.test.ts +4 -4
- package/src/__tests__/material-publication.browser.test.ts +29 -0
- package/src/__tests__/material-publication.commands.ts +23 -0
- package/src/__tests__/material-publication.dawn.test.ts +24 -0
- package/src/__tests__/material-publication.fixture.ts +349 -0
- package/src/__tests__/material-publication.server.ts +109 -0
- package/src/__tests__/parse-scene-payload-refs.cases.unit.test.ts +73 -96
- package/src/__tests__/pbr-pipeline.unit.test.ts +25 -11
- package/src/__tests__/point-light-shadow.browser.test.ts +8 -2
- package/src/__tests__/point-light-shadow.unit.test.ts +37 -8
- package/src/__tests__/record-all-topology.cases.unit.test.ts +52 -0
- package/src/__tests__/record-draw-branch.cases.unit.test.ts +1 -0
- package/src/__tests__/record-worldid-isolation.test.ts +47 -28
- package/src/__tests__/render-error-exhaustive.test-d.ts +24 -0
- package/src/__tests__/render-system-extract-dispatch-ordering.test.ts +15 -4
- package/src/__tests__/render-system-extract.test.ts +61 -0
- package/src/__tests__/render-system-extract.unit.test.ts +21 -7
- package/src/__tests__/render-system-fold-bucket.unit.test.ts +33 -1
- package/src/__tests__/render-system-fold-material.unit.test.ts +32 -6
- package/src/__tests__/render-system-fold-modegate.unit.test.ts +26 -4
- package/src/__tests__/render-system-fold.dawn.test.ts +4 -1
- package/src/__tests__/render-system-mega.test.ts +50 -62
- package/src/__tests__/renderer-device-loss-provider-feasibility.dawn.test.ts +0 -1
- package/src/__tests__/renderer-device-loss-recovery.dawn.test.ts +0 -3
- package/src/__tests__/renderer-draw-world.cases.unit.test.ts +16 -513
- package/src/__tests__/resolve-scene-guids.cases.unit.test.ts +48 -43
- package/src/__tests__/rhi-null-command-flow.unit.test.ts +9 -7
- package/src/__tests__/roots-to-scene-asset.test.ts +27 -28
- package/src/__tests__/roundtrip-primitive.test.ts +24 -23
- package/src/__tests__/scene-equirect-roundtrip.test.ts +5 -16
- package/src/__tests__/scene-instantiate-cycle-runtime.test.ts +13 -29
- package/src/__tests__/scene-mount-fixed-point.test.ts +104 -227
- package/src/__tests__/scene-mount-roundtrip.test.ts +95 -961
- package/src/__tests__/scene-mount-wrapper-roundtrip.test.ts +36 -182
- package/src/__tests__/scene-sugar-instantiate.test.ts +20 -15
- package/src/__tests__/serialize-mounts-roundtrip.test.ts +108 -492
- package/src/__tests__/serialize-scene-asset.test.ts +36 -50
- package/src/__tests__/shadow-caster-empty-schema.test.ts +3 -1
- package/src/__tests__/shadow-fields-observable.dawn.test.ts +34 -19
- package/src/__tests__/shadow-mesh-ssbo-order.test.ts +5 -12
- package/src/__tests__/skin-extract-getarrayview-count.unit.test.ts +6 -4
- package/src/__tests__/skin-m2-extract-happy.cases.unit.test.ts +50 -2
- package/src/__tests__/skin-m2-extract-joint-error.cases.unit.test.ts +50 -2
- package/src/__tests__/skin-m2-extract-null-assets.cases.unit.test.ts +50 -2
- package/src/__tests__/skin-m2-extract-skeleton-error.cases.unit.test.ts +50 -2
- package/src/__tests__/skin-palette-extract.cases.unit.test.ts +2 -0
- package/src/__tests__/skinned-shadow-mixed.dawn.test.ts +93 -48
- package/src/__tests__/skylight-pipeline-layout.cases.unit.test.ts +6 -2
- package/src/__tests__/sparse-tag-scene-roundtrip.test.ts +1 -1
- package/src/__tests__/sprite-lit-bgl-byte-identical.test.ts +11 -3
- package/src/__tests__/template-game-default-api-contract.test.ts +21 -21
- package/src/__tests__/tonemap-hdr-target.cases.unit.test.ts +8 -5
- package/src/__tests__/tonemap-pipeline-split.cases.unit.test.ts +3 -0
- package/src/__tests__/transient-fields-collect.test.ts +4 -4
- package/src/__tests__/transient-runtime-behavior.test.ts +9 -9
- package/src/__tests__/vfx-depth-material.dawn.test.ts +42 -0
- package/src/__tests__/vfx-mesh-lighting.browser.test.ts +16 -0
- package/src/__tests__/vfx-mesh-lighting.commands.ts +14 -0
- package/src/__tests__/vfx-mesh-lighting.dawn.test.ts +16 -0
- package/src/__tests__/vfx-mesh-lighting.fixture.ts +883 -0
- package/src/__tests__/wave1-dynamic-geometry.browser.test.ts +326 -0
- package/src/__tests__/wave1-rendering-materials.browser.test.ts +617 -0
- package/src/__tests__/wave1-rendering-p0.browser.test.ts +751 -0
- package/src/__tests__/wave1-rendering-recovery.browser.test.ts +666 -0
- package/src/__tests__/wave1-shadow-diagnostic.browser.test.ts +582 -0
- package/src/__tests__/world-scene-despawn.test.ts +8 -8
- package/src/__tests__/world-scene-instantiate.test.ts +23 -29
- package/src/__tests__/world-scene-nested.test.ts +90 -163
- package/src/__tests__/world-scene-override.test.ts +17 -16
- package/src/__tests__/zero-compression-zero-load.integration.test.ts +1 -0
- package/src/collect-scene-asset.ts +637 -19
- package/src/components/__tests__/sprite-animation.test-d.ts +2 -2
- package/src/index.ts +1 -0
- package/src/scene-utils/mount-override-fold.ts +5 -14
- package/src/__tests__/node-shims.d.ts +0 -31
|
@@ -1,514 +1,17 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
//
|
|
6
|
-
//
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
// - packages/runtime/src/__tests__/pipeline-cache-key-topology.test.ts
|
|
17
|
-
// - packages/runtime/src/__tests__/pipeline-rename-grep-gate.test.ts
|
|
18
|
-
// - packages/runtime/src/__tests__/pipeline-vertex-stride-branch.test.ts
|
|
19
|
-
// - packages/runtime/src/__tests__/post-process-register.test.ts
|
|
20
|
-
// - packages/runtime/src/__tests__/record-all-topology.test.ts
|
|
21
|
-
// - packages/runtime/src/__tests__/record-draw-branch.test.ts
|
|
22
|
-
// - packages/runtime/src/__tests__/record-strip-index-format.test.ts
|
|
23
|
-
// - packages/runtime/src/__tests__/render-query-regression.test.ts
|
|
24
|
-
// - packages/runtime/src/__tests__/renderer-draw-world.test.ts
|
|
25
|
-
// - packages/runtime/src/__tests__/renderer-input-snapshot.test.ts
|
|
26
|
-
// - packages/runtime/src/__tests__/renderer-read-pixels.test.ts
|
|
27
|
-
// - packages/runtime/src/__tests__/renderer-ready.test.ts
|
|
28
|
-
// - packages/runtime/src/__tests__/renderstate-pipeline-cache.test.ts
|
|
29
|
-
// - packages/runtime/src/__tests__/storage-buffer-caps.test.ts
|
|
30
|
-
// - packages/runtime/src/__tests__/device/gpu-residency.test.ts
|
|
31
|
-
// - packages/runtime/src/__tests__/render-data.test.ts
|
|
32
|
-
// - packages/runtime/src/__tests__/hdrp-bgl-slots.test.ts
|
|
33
|
-
// - packages/runtime/src/__tests__/hdrp-caps-gate.test.ts
|
|
34
|
-
// - packages/runtime/src/__tests__/hdrp-grid-invalid.test.ts
|
|
35
|
-
// - packages/runtime/src/__tests__/hdrp-index-list-overflow-once.test.ts
|
|
36
|
-
// - packages/runtime/src/__tests__/hdrp-light-budget.test.ts
|
|
37
|
-
// - packages/runtime/src/__tests__/hdrp-pipeline-asset-config.test.ts
|
|
38
|
-
// - packages/runtime/src/__tests__/m7-hdrp-demo-shape.test.ts
|
|
39
|
-
//
|
|
40
|
-
// Paradigm: each block-scope wraps a source file. ancestorTitles[0] is the
|
|
41
|
-
// source-preserved inner describe (NOT the source filename for these 3 files
|
|
42
|
-
// — recovery path: vitest report ancestorTitles -> grep this file -> upstream
|
|
43
|
-
// `// ─── from <name>.test.ts ───` block separator -> source filename).
|
|
44
|
-
// Top-level imports merged + deduped.
|
|
45
|
-
|
|
46
|
-
import { existsSync, readFileSync } from 'node:fs';
|
|
47
|
-
import { dirname, resolve } from 'node:path';
|
|
48
|
-
import { fileURLToPath } from 'node:url';
|
|
49
|
-
import { HANDLE_CUBE, HANDLE_TRIANGLE, resolveAssetHandle } from '@forgeax/engine-assets-runtime';
|
|
50
|
-
import type { World as WorldType } from '@forgeax/engine-ecs';
|
|
51
|
-
import { defineComponent, World } from '@forgeax/engine-ecs';
|
|
52
|
-
import {
|
|
53
|
-
buildMeshAttributeMapForUvSets,
|
|
54
|
-
createBoxGeometry,
|
|
55
|
-
createConeGeometry,
|
|
56
|
-
createCylinderGeometry,
|
|
57
|
-
createPlaneGeometry,
|
|
58
|
-
createSphereGeometry,
|
|
59
|
-
createTorusGeometry,
|
|
60
|
-
PROCEDURAL_FLOATS_PER_VERTEX,
|
|
61
|
-
} from '@forgeax/engine-geometry';
|
|
62
|
-
import { type Mat4, mat4, type Vec3, vec3 } from '@forgeax/engine-math';
|
|
63
|
-
import type { Renderer as RendererType } from '@forgeax/engine-render';
|
|
64
|
-
import { Camera, MeshFilter, MeshRenderer } from '@forgeax/engine-render';
|
|
65
|
-
import {
|
|
66
|
-
err,
|
|
67
|
-
ok,
|
|
68
|
-
type PipelineLayout,
|
|
69
|
-
type RenderPipeline,
|
|
70
|
-
type Result,
|
|
71
|
-
type RhiCaps,
|
|
72
|
-
type RhiDevice,
|
|
73
|
-
RhiError,
|
|
74
|
-
ok as rhiOk,
|
|
75
|
-
type ShaderModule,
|
|
76
|
-
} from '@forgeax/engine-rhi';
|
|
77
|
-
import {
|
|
78
|
-
acquireCanvasContext as acquireNullCanvasContext,
|
|
79
|
-
createShaderModule as createNullShaderModule,
|
|
80
|
-
RhiNullAdapter,
|
|
81
|
-
} from '@forgeax/engine-rhi-null';
|
|
82
|
-
import { ChildOf, Transform } from '@forgeax/engine-scene';
|
|
83
|
-
import {
|
|
84
|
-
findVariantByKey,
|
|
85
|
-
type MaterialShaderEntry,
|
|
86
|
-
type MaterialShaderManifestEntry,
|
|
87
|
-
type MaterialShaderManifestVariant,
|
|
88
|
-
} from '@forgeax/engine-shader';
|
|
89
|
-
import {
|
|
90
|
-
type AssetError,
|
|
91
|
-
type EquirectAsset,
|
|
92
|
-
type Handle,
|
|
93
|
-
type MaterialRenderState,
|
|
94
|
-
type MeshAsset,
|
|
95
|
-
type PassSelector,
|
|
96
|
-
type PrimitiveTopology,
|
|
97
|
-
type RenderPipelineAsset,
|
|
98
|
-
type TextureAsset,
|
|
99
|
-
toShared,
|
|
100
|
-
} from '@forgeax/engine-types';
|
|
101
|
-
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
102
|
-
import {
|
|
103
|
-
bin,
|
|
104
|
-
type ClusterBinError,
|
|
105
|
-
calculateSphereClusterBounds,
|
|
106
|
-
clusterSpaceObjectAabb,
|
|
107
|
-
deriveCullingRadius,
|
|
108
|
-
ndcPositionToCluster,
|
|
109
|
-
viewZToZSlice,
|
|
110
|
-
} from '../../../render/src/cluster-binner';
|
|
111
|
-
import { GpuResidencyCache } from '../../../render/src/device/gpu-residency';
|
|
112
|
-
import { createEngineMetrics } from '../../../render/src/engine-metrics';
|
|
113
|
-
import { assertStorageBufferCap } from '../../../render/src/light-buffer-layout';
|
|
114
|
-
import {
|
|
115
|
-
buildPbrPipelineLayouts,
|
|
116
|
-
buildPbrViewBglEntries,
|
|
117
|
-
type PbrCaps,
|
|
118
|
-
} from '../../../render/src/pbr-pipeline';
|
|
119
|
-
import {
|
|
120
|
-
HdrpInstallError,
|
|
121
|
-
validateClusterGrid,
|
|
122
|
-
} from '../../../render/src/pipeline/standard-pipeline';
|
|
123
|
-
import {
|
|
124
|
-
buildPipelineForMaterialShader,
|
|
125
|
-
type PipelineBuilderContext,
|
|
126
|
-
type PipelineBuilderShaderModuleFactory,
|
|
127
|
-
} from '../../../render/src/pipeline-builder';
|
|
128
|
-
import {
|
|
129
|
-
cacheKeyOf,
|
|
130
|
-
createHdrpBindGroupLayoutDescriptor,
|
|
131
|
-
type PipelineSpec,
|
|
132
|
-
} from '../../../render/src/pipeline-spec';
|
|
133
|
-
import {
|
|
134
|
-
deriveRenderDataCubemap,
|
|
135
|
-
deriveRenderDataMesh,
|
|
136
|
-
deriveRenderDataTexture,
|
|
137
|
-
} from '../../../render/src/render-data';
|
|
138
|
-
import { extractFrame, prepareExtractContext } from '../../../render/src/render-system-extract';
|
|
139
|
-
import { matchPass } from '../../../render/src/systems/pass-selector';
|
|
140
|
-
import { makeMockShaderRegistry } from './helpers/mock-shader-registry';
|
|
141
|
-
import { standardMaterialShaderVariants } from './helpers/standard-material-manifest';
|
|
142
|
-
|
|
143
|
-
function makeExplicitNullRhi(spies: {
|
|
144
|
-
setIndexBuffer: ReturnType<typeof vi.fn>;
|
|
145
|
-
setVertexBuffer: ReturnType<typeof vi.fn>;
|
|
146
|
-
draw: ReturnType<typeof vi.fn>;
|
|
147
|
-
drawIndexed: ReturnType<typeof vi.fn>;
|
|
148
|
-
}): unknown {
|
|
149
|
-
const adapter = new RhiNullAdapter();
|
|
150
|
-
const requestDevice = adapter.requestDevice.bind(adapter);
|
|
151
|
-
adapter.requestDevice = async () => {
|
|
152
|
-
const result = await requestDevice();
|
|
153
|
-
if (result.ok) {
|
|
154
|
-
const device = result.value;
|
|
155
|
-
const createCommandEncoder = device.createCommandEncoder.bind(device);
|
|
156
|
-
device.createCommandEncoder = (desc) => {
|
|
157
|
-
const encoderResult = createCommandEncoder(desc);
|
|
158
|
-
if (!encoderResult.ok) return encoderResult;
|
|
159
|
-
const encoder = encoderResult.value;
|
|
160
|
-
const beginRenderPass = encoder.beginRenderPass.bind(encoder);
|
|
161
|
-
encoder.beginRenderPass = (passDesc) => {
|
|
162
|
-
const pass = beginRenderPass(passDesc);
|
|
163
|
-
const draw = pass.draw.bind(pass);
|
|
164
|
-
const drawIndexed = pass.drawIndexed.bind(pass);
|
|
165
|
-
const setIndexBuffer = pass.setIndexBuffer.bind(pass);
|
|
166
|
-
const setVertexBuffer = pass.setVertexBuffer.bind(pass);
|
|
167
|
-
pass.draw = (...args) => {
|
|
168
|
-
spies.draw(...args);
|
|
169
|
-
draw(...args);
|
|
170
|
-
};
|
|
171
|
-
pass.drawIndexed = (...args) => {
|
|
172
|
-
spies.drawIndexed(...args);
|
|
173
|
-
drawIndexed(...args);
|
|
174
|
-
};
|
|
175
|
-
pass.setIndexBuffer = (...args) => {
|
|
176
|
-
spies.setIndexBuffer(...args);
|
|
177
|
-
setIndexBuffer(...args);
|
|
178
|
-
};
|
|
179
|
-
pass.setVertexBuffer = (...args) => {
|
|
180
|
-
spies.setVertexBuffer(...args);
|
|
181
|
-
setVertexBuffer(...args);
|
|
182
|
-
};
|
|
183
|
-
return pass;
|
|
184
|
-
};
|
|
185
|
-
return { ok: true, value: encoder };
|
|
186
|
-
};
|
|
187
|
-
}
|
|
188
|
-
return result;
|
|
189
|
-
};
|
|
190
|
-
return {
|
|
191
|
-
requestAdapter: async () => ({ ok: true, value: adapter }),
|
|
192
|
-
acquireCanvasContext: acquireNullCanvasContext,
|
|
193
|
-
createShaderModule: (device: unknown, desc: { code: string; label?: string }) =>
|
|
194
|
-
createNullShaderModule(device as never, desc),
|
|
195
|
-
};
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
vi.mock('@forgeax/engine-rhi-wgpu', () => {
|
|
199
|
-
return {
|
|
200
|
-
rhi: {
|
|
201
|
-
requestAdapter: async () => ({
|
|
202
|
-
ok: false,
|
|
203
|
-
error: {
|
|
204
|
-
code: 'adapter-unavailable',
|
|
205
|
-
expected: 'adapter available',
|
|
206
|
-
hint: 'default mock fail',
|
|
207
|
-
},
|
|
208
|
-
}),
|
|
209
|
-
getPreferredCanvasFormat: () => 'bgra8unorm',
|
|
210
|
-
acquireCanvasContext: () => ({
|
|
211
|
-
ok: false,
|
|
212
|
-
error: {
|
|
213
|
-
code: 'webgpu-runtime-error',
|
|
214
|
-
expected: 'context available',
|
|
215
|
-
hint: 'default mock fail',
|
|
216
|
-
},
|
|
217
|
-
}),
|
|
218
|
-
},
|
|
219
|
-
ensureReady: async () => undefined,
|
|
220
|
-
};
|
|
221
|
-
});
|
|
222
|
-
|
|
223
|
-
void [
|
|
224
|
-
Camera,
|
|
225
|
-
ChildOf,
|
|
226
|
-
GpuResidencyCache,
|
|
227
|
-
HANDLE_CUBE,
|
|
228
|
-
HANDLE_TRIANGLE,
|
|
229
|
-
HdrpInstallError,
|
|
230
|
-
MeshFilter,
|
|
231
|
-
MeshRenderer,
|
|
232
|
-
PROCEDURAL_FLOATS_PER_VERTEX,
|
|
233
|
-
RhiError,
|
|
234
|
-
RhiNullAdapter,
|
|
235
|
-
Transform,
|
|
236
|
-
World,
|
|
237
|
-
acquireNullCanvasContext,
|
|
238
|
-
afterEach,
|
|
239
|
-
assertStorageBufferCap,
|
|
240
|
-
beforeEach,
|
|
241
|
-
bin,
|
|
242
|
-
buildMeshAttributeMapForUvSets,
|
|
243
|
-
buildPbrPipelineLayouts,
|
|
244
|
-
buildPbrViewBglEntries,
|
|
245
|
-
buildPipelineForMaterialShader,
|
|
246
|
-
cacheKeyOf,
|
|
247
|
-
calculateSphereClusterBounds,
|
|
248
|
-
clusterSpaceObjectAabb,
|
|
249
|
-
createBoxGeometry,
|
|
250
|
-
createConeGeometry,
|
|
251
|
-
createCylinderGeometry,
|
|
252
|
-
createEngineMetrics,
|
|
253
|
-
createHdrpBindGroupLayoutDescriptor,
|
|
254
|
-
createNullShaderModule,
|
|
255
|
-
createPlaneGeometry,
|
|
256
|
-
createSphereGeometry,
|
|
257
|
-
createTorusGeometry,
|
|
258
|
-
defineComponent,
|
|
259
|
-
deriveCullingRadius,
|
|
260
|
-
deriveRenderDataCubemap,
|
|
261
|
-
deriveRenderDataMesh,
|
|
262
|
-
deriveRenderDataTexture,
|
|
263
|
-
describe,
|
|
264
|
-
dirname,
|
|
265
|
-
err,
|
|
266
|
-
existsSync,
|
|
267
|
-
expect,
|
|
268
|
-
extractFrame,
|
|
269
|
-
fileURLToPath,
|
|
270
|
-
findVariantByKey,
|
|
271
|
-
it,
|
|
272
|
-
makeExplicitNullRhi,
|
|
273
|
-
makeMockShaderRegistry,
|
|
274
|
-
mat4,
|
|
275
|
-
matchPass,
|
|
276
|
-
ndcPositionToCluster,
|
|
277
|
-
ok,
|
|
278
|
-
prepareExtractContext,
|
|
279
|
-
readFileSync,
|
|
280
|
-
resolve,
|
|
281
|
-
resolveAssetHandle,
|
|
282
|
-
rhiOk,
|
|
283
|
-
standardMaterialShaderVariants,
|
|
284
|
-
toShared,
|
|
285
|
-
validateClusterGrid,
|
|
286
|
-
vec3,
|
|
287
|
-
vi,
|
|
288
|
-
viewZToZSlice,
|
|
289
|
-
];
|
|
290
|
-
type __MergedKeep =
|
|
291
|
-
| AssetError
|
|
292
|
-
| ClusterBinError
|
|
293
|
-
| EquirectAsset
|
|
294
|
-
| Handle
|
|
295
|
-
| Mat4
|
|
296
|
-
| MaterialRenderState
|
|
297
|
-
| MaterialShaderEntry
|
|
298
|
-
| MaterialShaderManifestEntry
|
|
299
|
-
| MaterialShaderManifestVariant
|
|
300
|
-
| MeshAsset
|
|
301
|
-
| PassSelector
|
|
302
|
-
| PbrCaps
|
|
303
|
-
| PipelineBuilderContext
|
|
304
|
-
| PipelineBuilderShaderModuleFactory
|
|
305
|
-
| PipelineLayout
|
|
306
|
-
| PipelineSpec
|
|
307
|
-
| PrimitiveTopology
|
|
308
|
-
| RenderPipeline
|
|
309
|
-
| RenderPipelineAsset
|
|
310
|
-
| RendererType
|
|
311
|
-
| Result
|
|
312
|
-
| RhiCaps
|
|
313
|
-
| RhiDevice
|
|
314
|
-
| ShaderModule
|
|
315
|
-
| TextureAsset
|
|
316
|
-
| Vec3
|
|
317
|
-
| WorldType;
|
|
318
|
-
|
|
319
|
-
{
|
|
320
|
-
// --- from renderer-draw-world.test.ts ---
|
|
321
|
-
const _ENGINE = new URL('../../../render/src/assembly/factory.ts', import.meta.url).href;
|
|
322
|
-
const RENDERER = new URL('../../../render/src/assembly/factory.ts', import.meta.url).href;
|
|
323
|
-
|
|
324
|
-
// ─── Mock helpers ───────────────────────────────────────────────────────────
|
|
325
|
-
|
|
326
|
-
interface MockGL2Context {
|
|
327
|
-
__mockTag: 'webgl2';
|
|
328
|
-
getExtension: () => null;
|
|
329
|
-
getParameter: () => number;
|
|
330
|
-
isContextLost: () => boolean;
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
function makeMockGL2(): MockGL2Context {
|
|
334
|
-
return {
|
|
335
|
-
__mockTag: 'webgl2',
|
|
336
|
-
getExtension: () => null,
|
|
337
|
-
getParameter: () => 1,
|
|
338
|
-
isContextLost: () => false,
|
|
339
|
-
};
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
interface CanvasOptions {
|
|
343
|
-
webgl2: 'context' | 'null';
|
|
344
|
-
webgpu?: 'context' | 'null';
|
|
345
|
-
}
|
|
346
|
-
|
|
347
|
-
function _makeMockCanvas(opts: CanvasOptions): HTMLCanvasElement {
|
|
348
|
-
const canvas = {
|
|
349
|
-
width: 800,
|
|
350
|
-
height: 600,
|
|
351
|
-
getContext(kind: string): unknown {
|
|
352
|
-
if (kind === 'webgl2') {
|
|
353
|
-
return opts.webgl2 === 'context' ? makeMockGL2() : null;
|
|
354
|
-
}
|
|
355
|
-
if (kind === 'webgpu') {
|
|
356
|
-
if (opts.webgpu === 'context') {
|
|
357
|
-
return {
|
|
358
|
-
__mockTag: 'webgpu-canvas-context',
|
|
359
|
-
configure: () => undefined,
|
|
360
|
-
unconfigure: () => undefined,
|
|
361
|
-
getCurrentTexture: () => ({ createView: () => ({}) }),
|
|
362
|
-
};
|
|
363
|
-
}
|
|
364
|
-
return null;
|
|
365
|
-
}
|
|
366
|
-
return null;
|
|
367
|
-
},
|
|
368
|
-
addEventListener: () => undefined,
|
|
369
|
-
removeEventListener: () => undefined,
|
|
370
|
-
} as unknown as HTMLCanvasElement;
|
|
371
|
-
return canvas;
|
|
372
|
-
}
|
|
373
|
-
|
|
374
|
-
function _makeMockGPUDevice(): { device: unknown } {
|
|
375
|
-
const lost = new Promise<unknown>(() => undefined);
|
|
376
|
-
const device = {
|
|
377
|
-
__mockTag: 'gpu-device',
|
|
378
|
-
lost,
|
|
379
|
-
features: new Set(),
|
|
380
|
-
limits: {},
|
|
381
|
-
queue: {
|
|
382
|
-
submit: () => undefined,
|
|
383
|
-
writeBuffer: () => undefined,
|
|
384
|
-
// bug-20260519 AC-03 path: zero-manifest path runs through fallback
|
|
385
|
-
// texture seed (writeTexture) which the legacy 4 cases never reach.
|
|
386
|
-
writeTexture: () => undefined,
|
|
387
|
-
},
|
|
388
|
-
createShaderModule: () => ({
|
|
389
|
-
getCompilationInfo: async () => ({ messages: [] }),
|
|
390
|
-
}),
|
|
391
|
-
createBindGroupLayout: () => ({}),
|
|
392
|
-
createPipelineLayout: () => ({}),
|
|
393
|
-
createRenderPipeline: () => ({}),
|
|
394
|
-
createBindGroup: () => ({}),
|
|
395
|
-
createBuffer: () => ({
|
|
396
|
-
getMappedRange: () => new ArrayBuffer(64),
|
|
397
|
-
unmap: () => undefined,
|
|
398
|
-
}),
|
|
399
|
-
createCommandEncoder: () => ({
|
|
400
|
-
beginRenderPass: () => ({
|
|
401
|
-
setPipeline: () => undefined,
|
|
402
|
-
setVertexBuffer: () => undefined,
|
|
403
|
-
setIndexBuffer: () => undefined,
|
|
404
|
-
setBindGroup: () => undefined,
|
|
405
|
-
draw: () => undefined,
|
|
406
|
-
drawIndexed: () => undefined,
|
|
407
|
-
end: () => undefined,
|
|
408
|
-
}),
|
|
409
|
-
finish: () => ({}),
|
|
410
|
-
}),
|
|
411
|
-
createTexture: () => ({
|
|
412
|
-
createView: () => ({}),
|
|
413
|
-
}),
|
|
414
|
-
createSampler: () => ({}),
|
|
415
|
-
destroy: () => undefined,
|
|
416
|
-
};
|
|
417
|
-
return { device };
|
|
418
|
-
}
|
|
419
|
-
|
|
420
|
-
function _makeMockGPU(deviceObj: unknown): unknown {
|
|
421
|
-
return {
|
|
422
|
-
requestAdapter: async () => ({
|
|
423
|
-
requestDevice: async () => deviceObj,
|
|
424
|
-
}),
|
|
425
|
-
getPreferredCanvasFormat: () => 'bgra8unorm',
|
|
426
|
-
};
|
|
427
|
-
}
|
|
428
|
-
|
|
429
|
-
const baseNavigator = { userAgent: 'mock-engine-test' } as unknown as Navigator;
|
|
430
|
-
|
|
431
|
-
function _buildManifestDataUrl(): string {
|
|
432
|
-
// feat-20260518-pbr-direct-lighting-mvp M5 / w22.9: createRenderer's
|
|
433
|
-
// post-fallback path requires both pbr (`f_schlick(` marker) + unlit
|
|
434
|
-
// entries; seed two minimal stubs (mock device's createShaderModule does
|
|
435
|
-
// not parse WGSL).
|
|
436
|
-
const manifest = {
|
|
437
|
-
schemaVersion: '1.0.0',
|
|
438
|
-
entries: [
|
|
439
|
-
{ hash: 'pbr00000', wgsl: '/* pbr stub - calls f_schlick( */', glsl: '', bindings: '' },
|
|
440
|
-
{ hash: 'unlit000', wgsl: '/* unlit stub */', glsl: '', bindings: '' },
|
|
441
|
-
{
|
|
442
|
-
hash: 'tonemap0',
|
|
443
|
-
wgsl: '/* tonemap stub - struct TonemapParams { exposure: f32 }; */',
|
|
444
|
-
glsl: '',
|
|
445
|
-
bindings: '',
|
|
446
|
-
},
|
|
447
|
-
],
|
|
448
|
-
};
|
|
449
|
-
return `data:application/json,${encodeURIComponent(JSON.stringify(manifest))}`;
|
|
450
|
-
}
|
|
451
|
-
|
|
452
|
-
beforeEach(() => {
|
|
453
|
-
vi.stubGlobal('navigator', { ...baseNavigator });
|
|
454
|
-
});
|
|
455
|
-
|
|
456
|
-
afterEach(() => {
|
|
457
|
-
vi.unstubAllGlobals();
|
|
1
|
+
import { readFileSync } from 'node:fs';
|
|
2
|
+
import { describe, expect, it } from 'vitest';
|
|
3
|
+
import * as rendererFactory from '../../../render/src/assembly/factory';
|
|
4
|
+
|
|
5
|
+
// This is a source/export contract. It creates no renderer, World, canvas, or
|
|
6
|
+
// device and must not retain the unrelated fixtures from the old merged suite.
|
|
7
|
+
describe('Renderer.draw(world) K-4 contract rewrite (D-S11)', () => {
|
|
8
|
+
it('removes the RendererDrawTarget interface from the renderer source file', () => {
|
|
9
|
+
const text = readFileSync(
|
|
10
|
+
new URL('../../../render/src/assembly/webgpu-renderer.ts', import.meta.url),
|
|
11
|
+
'utf8',
|
|
12
|
+
);
|
|
13
|
+
expect(text).not.toMatch(/interface RendererDrawTarget/);
|
|
14
|
+
expect(text).not.toMatch(/RendererDrawTarget/);
|
|
15
|
+
expect(rendererFactory).not.toHaveProperty('RendererDrawTarget');
|
|
458
16
|
});
|
|
459
|
-
|
|
460
|
-
// ─── Tests ──────────────────────────────────────────────────────────────────
|
|
461
|
-
|
|
462
|
-
describe('Renderer.draw(world) K-4 contract rewrite (D-S11)', () => {
|
|
463
|
-
it('removes the RendererDrawTarget interface from the renderer source file', async () => {
|
|
464
|
-
// Source-level grep gate: the D-S11 + K-4 rewrite removes the
|
|
465
|
-
// RendererDrawTarget interface declaration entirely (charter
|
|
466
|
-
// proposition 5 single PBR main path; no double-shader branching).
|
|
467
|
-
const fsId = 'node:fs';
|
|
468
|
-
const pathId = 'node:path';
|
|
469
|
-
const urlId = 'node:url';
|
|
470
|
-
const fs = (await import(/* @vite-ignore */ fsId)) as {
|
|
471
|
-
readFileSync: (p: string, enc: string) => string;
|
|
472
|
-
};
|
|
473
|
-
const path = (await import(/* @vite-ignore */ pathId)) as {
|
|
474
|
-
resolve: (...parts: string[]) => string;
|
|
475
|
-
dirname: (p: string) => string;
|
|
476
|
-
};
|
|
477
|
-
const url = (await import(/* @vite-ignore */ urlId)) as {
|
|
478
|
-
fileURLToPath: (u: string) => string;
|
|
479
|
-
};
|
|
480
|
-
const here = url.fileURLToPath(import.meta.url);
|
|
481
|
-
const rendererSrc = path.resolve(
|
|
482
|
-
path.dirname(here),
|
|
483
|
-
'..',
|
|
484
|
-
'..',
|
|
485
|
-
'..',
|
|
486
|
-
'render',
|
|
487
|
-
'src',
|
|
488
|
-
'assembly',
|
|
489
|
-
'webgpu-renderer.ts',
|
|
490
|
-
);
|
|
491
|
-
const text = fs.readFileSync(rendererSrc, 'utf8');
|
|
492
|
-
expect(text).not.toMatch(/interface RendererDrawTarget/);
|
|
493
|
-
expect(text).not.toMatch(/RendererDrawTarget/);
|
|
494
|
-
// Module runtime export must also be absent (already erased by tsc for
|
|
495
|
-
// type-only members; covers `export type` removal at the surface level).
|
|
496
|
-
const mod = (await import(RENDERER)) as Record<string, unknown>;
|
|
497
|
-
expect(mod.RendererDrawTarget).toBeUndefined();
|
|
498
|
-
});
|
|
499
|
-
});
|
|
500
|
-
|
|
501
|
-
// bug-20260519 AC-03: when a world *does* carry a `MeshRenderer` entity but
|
|
502
|
-
// the renderer was created without `shaderManifestUrl`, render-time access
|
|
503
|
-
// to the now-nullable `pipelineState.{unlitPipeline,standardPipeline}` must
|
|
504
|
-
// feat-20260529 D-3: materials without passes are caught at extract stage
|
|
505
|
-
// as `material-no-effective-pass` (the shared MaterialError), before
|
|
506
|
-
// reaching the record-stage pipeline-pick branch. The test's original
|
|
507
|
-
// bug-20260519 AC-03 intent — "zero-manifest renderer fires structured error
|
|
508
|
-
// not crash" — is preserved; the detection point has moved upstream.
|
|
509
|
-
// Original test expected `shader-compile-failed` from the record stage.
|
|
510
|
-
// After D-3, the material registered below has `kind:'material'` +
|
|
511
|
-
// `baseColor` but zero passes — the extract stage
|
|
512
|
-
// walks the parent chain (no parent), finds zero passes, and fires
|
|
513
|
-
// `material-no-effective-pass` with a recovery hint for adding a pass.
|
|
514
|
-
}
|
|
17
|
+
});
|