@forgeax/engine-runtime 0.1.6 → 0.1.19
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 +61 -0
- package/dist/.tsbuildinfo +1 -1
- package/dist/__tests__/helpers/standard-material-manifest.d.ts +12 -0
- package/dist/__tests__/helpers/standard-material-manifest.d.ts.map +1 -0
- package/dist/__tests__/render-environment-consumer.integration.test.d.ts +2 -0
- package/dist/__tests__/render-environment-consumer.integration.test.d.ts.map +1 -0
- package/dist/__tests__/render-error-exhaustive.test-d.d.ts.map +1 -1
- package/dist/__tests__/render-feature-prepared-graphics.fixture.d.ts.map +1 -1
- package/dist/__tests__/renderer-host-fallback.unit.test.d.ts +2 -0
- package/dist/__tests__/renderer-host-fallback.unit.test.d.ts.map +1 -0
- package/dist/__tests__/skinned-shadow-mixed.dawn.test.d.ts +2 -0
- package/dist/__tests__/skinned-shadow-mixed.dawn.test.d.ts.map +1 -0
- package/dist/backend-selection.d.ts.map +1 -1
- package/dist/collect-scene-asset.d.ts +6 -3
- 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 +25 -4
- package/dist/index.mjs.map +1 -1
- package/dist/renderer-host.d.ts +2 -1
- package/dist/renderer-host.d.ts.map +1 -1
- package/dist/renderer-host.mjs +21 -2
- package/dist/renderer-host.mjs.map +1 -1
- package/package.json +30 -30
- package/src/__tests__/asset-registry-guid-reverse.test.ts +33 -0
- package/src/__tests__/dawn/instances-per-instance-pbr.dawn.test.ts +12 -11
- package/src/__tests__/dawn/material-cooked-fixture.dawn.test.ts +39 -6
- package/src/__tests__/errors.unit.test.ts +60 -0
- package/src/__tests__/extract-record-no-hardcoded-texture-fields.test.ts +4 -5
- package/src/__tests__/fullscreen-post-process-pass.dawn.test.ts +461 -18
- package/src/__tests__/geometry.unit.test.ts +3 -1
- package/src/__tests__/helpers/standard-material-manifest.ts +45 -0
- package/src/__tests__/lights.unit.test.ts +15 -11
- package/src/__tests__/material-texture-uv-scale.unit.test.ts +8 -14
- package/src/__tests__/materials.unit.test.ts +2 -0
- package/src/__tests__/pbr-pipeline.unit.test.ts +15 -12
- package/src/__tests__/pipeline-cache-keying.unit.test.ts +6 -4
- package/src/__tests__/pipeline.unit.test.ts +5 -2
- package/src/__tests__/render-environment-consumer.integration.test.ts +33 -0
- package/src/__tests__/render-error-exhaustive.test-d.ts +93 -0
- package/src/__tests__/render-feature-prepared-graphics.browser.test.ts +5 -1
- package/src/__tests__/render-feature-prepared-graphics.fixture.ts +10 -0
- package/src/__tests__/render-system-mega.test.ts +3 -1
- package/src/__tests__/render-system-record-multi-material-textureview.test.ts +3 -1
- package/src/__tests__/render-system-record-per-submesh-transparency.test.ts +3 -1
- package/src/__tests__/render-system-record.test.ts +8 -6
- package/src/__tests__/renderer-host-fallback.unit.test.ts +112 -0
- package/src/__tests__/renderer-lifecycle.integration.test.ts +10 -0
- package/src/__tests__/renderer-surface.unit.test.ts +66 -0
- package/src/__tests__/renderer.test-d.ts +2 -0
- package/src/__tests__/rhi-null-command-flow.unit.test.ts +14 -0
- package/src/__tests__/shadow-csm-cascade-loadop.test.ts +5 -1
- package/src/__tests__/shadow-csm-tile-consistency.test.ts +5 -1
- package/src/__tests__/skinned-shadow-mixed.dawn.test.ts +383 -0
- package/src/__tests__/sprite-lit-bgl-byte-identical.test.ts +10 -10
- package/src/__tests__/ssao-passes.test.ts +32 -12
- package/src/__tests__/systems.unit.test.ts +48 -31
- package/src/backend-selection.ts +4 -0
- package/src/collect-scene-asset.ts +14 -7
- package/src/index.ts +5 -1
- package/src/renderer-host.ts +30 -3
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/backend-selection.ts","../src/renderer-host.ts"],"names":[],"mappings":";;;;;AAKO,SAAS,WAAA,CACd,KACA,eAAA,EACgB;AAChB,EAAA,MAAM,MAAM,GAAA,CAAI,GAAA;AAChB,EAAA,MAAM,qBAAqB,GAAA,CAAI,kBAAA;AAG/B,EAAA,MAAM,gCAAgC,GAAA,CAAI,6BAAA;AAG1C,EAAA,MAAM,oBAAoB,GAAA,CAAI,sBAAA;AAG9B,EAAA,MAAM,yBAAyB,GAAA,CAAI,eAAA;AAGnC,EAAA,MAAM,IAAA,GAAuB;AAAA,IAC3B,GAAA;AAAA,IACA,GAAI,kBAAA,KAAuB,MAAA,GAAY,EAAC,GAAI,EAAE,kBAAA,EAAmB;AAAA,IACjE,GAAI,6BAAA,KAAkC,MAAA,GAAY,EAAC,GAAI,EAAE,6BAAA,EAA8B;AAAA,IACvF,GAAI,iBAAA,KAAsB,MAAA,GAAY,EAAC,GAAI,EAAE,wBAAwB,iBAAA;AAAkB,GACzF;AACA,EAAA,MAAM,0BAA0B,eAAA,IAAmB,sBAAA;AACnD,EAAA,OAAO,4BAA4B,MAAA,GAC/B,IAAA,GACA,EAAE,GAAG,IAAA,EAAM,iBAAiB,uBAAA,EAAwB;AAC1D;AAGA,eAAsB,eAAA,CACpB,OAAA,EACA,UAAA,GAAa,KAAA,EAIb;AACA,EAAA,MAAM,WAAW,OAAA,EAAS,GAAA;AAC1B,EAAA,IAAI,QAAA,KAAa,MAAA,IAAa,QAAA,KAAa,IAAA,EAAM;AAC/C,IAAA,OAAO,EAAA,CAAG,WAAA,CAAY,EAAE,GAAA,EAAK,QAAA,EAAU,GAAI,QAAA,EAAoB,EAAG,OAAA,EAAS,kBAAkB,CAAC,CAAA;AAAA,EAChG;AACA,EAAA,MAAM,GAAA,GACJ,OAAO,UAAA,KAAe,WAAA,GAClB,SACC,UAAA,CAAiD,SAAA;AACxD,EAAA,IAAI,CAAC,UAAA,IAAc,GAAA,EAAK,QAAQ,MAAA,IAAa,GAAA,CAAI,QAAQ,IAAA,EAAM;AAC7D,IAAA,OAAO,EAAA;AAAA,MACL,WAAA,CAAY,SAAA,EAAiD,OAAA,EAAS,kBAAkB;AAAA,KAC1F;AAAA,EACF;AACA,EAAA,IAAI;AACF,IAAA,MAAM,GAAA,GAAO,MAAM,OAAO,0BAA0B,CAAA;AACpD,IAAA,MAAO,IAAI,WAAA,EAAuC;AAClD,IAAA,OAAO,EAAA,CAAG,WAAA,CAAY,GAAA,EAAK,OAAA,EAAS,kBAAkB,CAAC,CAAA;AAAA,EACzD,SAAS,KAAA,EAAO;AACd,IAAA,OAAO,GAAA;AAAA,MACL,IAAI,QAAA,CAAS;AAAA,QACX,IAAA,EAAM,mBAAA;AAAA,QACN,QAAA,EAAU,mCAAA;AAAA,QACV,IAAA,EAAM,CAAA,6BAAA,EAAgC,MAAA,CAAO,KAAK,CAAC,CAAA;AAAA,OACpD;AAAA,KACH;AAAA,EACF;AACF;;;
|
|
1
|
+
{"version":3,"sources":["../src/backend-selection.ts","../src/renderer-host.ts"],"names":[],"mappings":"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","file":"renderer-host.mjs","sourcesContent":["import type { RendererOptions } from '@forgeax/engine-render';\nimport type { RhiBackendPack } from '@forgeax/engine-render/internal/construct-renderer';\nimport { err, ok, RhiError } from '@forgeax/engine-rhi';\nimport * as rhiWebgpu from '@forgeax/engine-rhi-webgpu';\n\nexport function loadRhiPack(\n mod: Record<string, unknown>,\n instrumentation?: RhiBackendPack['instrumentation'],\n): RhiBackendPack {\n const rhi = mod.rhi as unknown as RhiBackendPack['rhi'];\n const createShaderModule = mod.createShaderModule as\n | RhiBackendPack['createShaderModule']\n | undefined;\n const createShaderModuleImmediate = mod.createShaderModuleImmediate as\n | RhiBackendPack['createShaderModuleImmediate']\n | undefined;\n const translateErrorEventToRhiError = mod.translateErrorEventToRhiError as\n | RhiBackendPack['translateErrorEventToRhiError']\n | undefined;\n const rawDeviceAccessor = mod._internal_getRawDevice as unknown as\n | RhiBackendPack['_internal_getRawDevice']\n | undefined;\n const backendInstrumentation = mod.instrumentation as\n | RhiBackendPack['instrumentation']\n | undefined;\n const pack: RhiBackendPack = {\n rhi,\n ...(createShaderModule === undefined ? {} : { createShaderModule }),\n ...(createShaderModuleImmediate === undefined ? {} : { createShaderModuleImmediate }),\n ...(translateErrorEventToRhiError === undefined ? {} : { translateErrorEventToRhiError }),\n ...(rawDeviceAccessor === undefined ? {} : { _internal_getRawDevice: rawDeviceAccessor }),\n };\n const resolvedInstrumentation = instrumentation ?? backendInstrumentation;\n return resolvedInstrumentation === undefined\n ? pack\n : { ...pack, instrumentation: resolvedInstrumentation };\n}\n\n/** Selects one backend pack; render receives only this typed owner contract. */\nexport async function loadBackendPack(\n options: RendererOptions | undefined,\n preferWgpu = false,\n): Promise<\n | { readonly ok: true; readonly value: RhiBackendPack }\n | { readonly ok: false; readonly error: RhiError }\n> {\n const explicit = options?.rhi;\n if (explicit !== undefined && explicit !== null) {\n return ok(loadRhiPack({ rhi: explicit, ...(explicit as object) }, options?.rhiInstrumentation));\n }\n const nav =\n typeof globalThis === 'undefined'\n ? undefined\n : (globalThis as { navigator?: { gpu?: unknown } }).navigator;\n if (!preferWgpu && nav?.gpu !== undefined && nav.gpu !== null) {\n return ok(\n loadRhiPack(rhiWebgpu as unknown as Record<string, unknown>, options?.rhiInstrumentation),\n );\n }\n try {\n const mod = (await import('@forgeax/engine-rhi-wgpu')) as Record<string, unknown>;\n await (mod.ensureReady as () => Promise<unknown>)();\n return ok(loadRhiPack(mod, options?.rhiInstrumentation));\n } catch (cause) {\n return err(\n new RhiError({\n code: 'rhi-not-available',\n expected: 'a usable RHI backend is available',\n hint: `failed to load wgpu backend: ${String(cause)}`,\n }),\n );\n }\n}\n","import type { AssetRegistry } from '@forgeax/engine-assets-runtime';\nimport type { RenderError, RendererOptions, RenderResult } from '@forgeax/engine-render';\nimport type {\n BundlerOptions,\n RendererHostAssembly,\n} from '@forgeax/engine-render/internal/construct-renderer';\nimport {\n constructRendererHost,\n EngineEnvironmentError,\n} from '@forgeax/engine-render/internal/construct-renderer';\nimport { loadBackendPack } from './backend-selection';\n\nexport type {\n BundlerOptions,\n RendererHostAssembly,\n} from '@forgeax/engine-render/internal/construct-renderer';\n\nconst FALLBACK_ERROR_CODES = new Set([\n 'adapter-unavailable',\n 'request-adapter-threw',\n 'feature-not-enabled',\n 'limit-exceeded',\n 'rhi-not-available',\n 'device-lost',\n 'oom',\n]);\n\nfunction canFallbackToWgpu(error: unknown): boolean {\n if (!(error instanceof EngineEnvironmentError)) return false;\n const webgpuError = error.detail.webgpuError;\n if (webgpuError === undefined || typeof webgpuError !== 'object') return false;\n if (!('code' in webgpuError)) return false;\n const code = webgpuError.code;\n return typeof code === 'string' && FALLBACK_ERROR_CODES.has(code);\n}\n\n/** Assemble renderer plus asset services in the Runtime-owned backend host. */\nexport async function constructRuntimeRendererHost(\n canvas: unknown,\n options?: RendererOptions,\n bundler?: BundlerOptions,\n): Promise<RenderResult<RendererHostAssembly, RenderError | EngineEnvironmentError>> {\n const first = await loadBackendPack(options);\n if (!first.ok) throw first.error;\n const constructed = await constructRendererHost(canvas, options, bundler, first.value);\n if (\n constructed.ok ||\n options?.rhi !== undefined ||\n typeof globalThis === 'undefined' ||\n !canFallbackToWgpu(constructed.error)\n ) {\n return constructed;\n }\n const fallback = await loadBackendPack(options, true);\n if (!fallback.ok) return constructed;\n return constructRendererHost(canvas, options, bundler, fallback.value);\n}\n\nexport { loadRhiPack } from './backend-selection';\nexport type { AssetRegistry };\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@forgeax/engine-runtime",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.19",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -26,37 +26,37 @@
|
|
|
26
26
|
"LICENSE"
|
|
27
27
|
],
|
|
28
28
|
"dependencies": {
|
|
29
|
-
"@forgeax/engine-animation": "0.1.
|
|
30
|
-
"@forgeax/engine-assets-runtime": "0.1.
|
|
31
|
-
"@forgeax/engine-audio-webaudio": "0.1.
|
|
32
|
-
"@forgeax/engine-codec": "0.1.
|
|
33
|
-
"@forgeax/engine-debug-draw": "0.1.
|
|
34
|
-
"@forgeax/engine-ecs": "0.1.
|
|
35
|
-
"@forgeax/engine-font": "0.1.
|
|
36
|
-
"@forgeax/engine-geometry": "0.1.
|
|
37
|
-
"@forgeax/engine-graphics-extras": "0.1.
|
|
38
|
-
"@forgeax/engine-image": "0.1.
|
|
39
|
-
"@forgeax/engine-input": "0.1.
|
|
40
|
-
"@forgeax/engine-math": "0.1.
|
|
41
|
-
"@forgeax/engine-pack": "0.1.
|
|
42
|
-
"@forgeax/engine-profiler": "0.1.
|
|
43
|
-
"@forgeax/engine-render": "0.1.
|
|
44
|
-
"@forgeax/engine-render-graph": "0.1.
|
|
45
|
-
"@forgeax/engine-rhi": "0.1.
|
|
46
|
-
"@forgeax/engine-rhi-null": "0.1.
|
|
47
|
-
"@forgeax/engine-rhi-webgpu": "0.1.
|
|
48
|
-
"@forgeax/engine-rhi-wgpu": "0.1.
|
|
49
|
-
"@forgeax/engine-scene": "0.1.
|
|
50
|
-
"@forgeax/engine-shader": "0.1.
|
|
51
|
-
"@forgeax/engine-skinning": "0.1.
|
|
52
|
-
"@forgeax/engine-types": "0.1.
|
|
53
|
-
"@forgeax/engine-vfx": "0.1.
|
|
29
|
+
"@forgeax/engine-animation": "0.1.19",
|
|
30
|
+
"@forgeax/engine-assets-runtime": "0.1.19",
|
|
31
|
+
"@forgeax/engine-audio-webaudio": "0.1.19",
|
|
32
|
+
"@forgeax/engine-codec": "0.1.19",
|
|
33
|
+
"@forgeax/engine-debug-draw": "0.1.19",
|
|
34
|
+
"@forgeax/engine-ecs": "0.1.19",
|
|
35
|
+
"@forgeax/engine-font": "0.1.19",
|
|
36
|
+
"@forgeax/engine-geometry": "0.1.19",
|
|
37
|
+
"@forgeax/engine-graphics-extras": "0.1.19",
|
|
38
|
+
"@forgeax/engine-image": "0.1.19",
|
|
39
|
+
"@forgeax/engine-input": "0.1.19",
|
|
40
|
+
"@forgeax/engine-math": "0.1.19",
|
|
41
|
+
"@forgeax/engine-pack": "0.1.19",
|
|
42
|
+
"@forgeax/engine-profiler": "0.1.19",
|
|
43
|
+
"@forgeax/engine-render": "0.1.19",
|
|
44
|
+
"@forgeax/engine-render-graph": "0.1.19",
|
|
45
|
+
"@forgeax/engine-rhi": "0.1.19",
|
|
46
|
+
"@forgeax/engine-rhi-null": "0.1.19",
|
|
47
|
+
"@forgeax/engine-rhi-webgpu": "0.1.19",
|
|
48
|
+
"@forgeax/engine-rhi-wgpu": "0.1.19",
|
|
49
|
+
"@forgeax/engine-scene": "0.1.19",
|
|
50
|
+
"@forgeax/engine-shader": "0.1.19",
|
|
51
|
+
"@forgeax/engine-skinning": "0.1.19",
|
|
52
|
+
"@forgeax/engine-types": "0.1.19",
|
|
53
|
+
"@forgeax/engine-vfx": "0.1.19"
|
|
54
54
|
},
|
|
55
55
|
"devDependencies": {
|
|
56
|
-
"@forgeax/engine-import": "0.1.
|
|
57
|
-
"@forgeax/engine-naga": "0.1.
|
|
58
|
-
"@forgeax/engine-state": "0.1.
|
|
59
|
-
"@forgeax/engine-vite-plugin-shader": "0.1.
|
|
56
|
+
"@forgeax/engine-import": "0.1.19",
|
|
57
|
+
"@forgeax/engine-naga": "0.1.19",
|
|
58
|
+
"@forgeax/engine-state": "0.1.19",
|
|
59
|
+
"@forgeax/engine-vite-plugin-shader": "0.1.19",
|
|
60
60
|
"@types/node": "^20.14.0"
|
|
61
61
|
},
|
|
62
62
|
"forgeax": {
|
|
@@ -18,6 +18,7 @@ import * as SceneOwner from '@forgeax/engine-scene';
|
|
|
18
18
|
import {
|
|
19
19
|
type Asset,
|
|
20
20
|
AssetRegistry,
|
|
21
|
+
HANDLE_CUBE,
|
|
21
22
|
resolveAssetHandle,
|
|
22
23
|
SceneCollectAssetGuidUnresolvedError,
|
|
23
24
|
} from '@forgeax/engine-assets-runtime';
|
|
@@ -205,6 +206,38 @@ describe('m1-t2 — uncatalogued scene MISS path', () => {
|
|
|
205
206
|
});
|
|
206
207
|
});
|
|
207
208
|
|
|
209
|
+
describe('builtin reverse lookup ownership', () => {
|
|
210
|
+
it('collects a builtin mesh GUID without cataloguing the process-static payload', () => {
|
|
211
|
+
const registry = { guidOf: () => undefined };
|
|
212
|
+
const world = new World();
|
|
213
|
+
prepareWorld(world);
|
|
214
|
+
const scene: SceneAsset = {
|
|
215
|
+
kind: 'scene',
|
|
216
|
+
entities: [
|
|
217
|
+
{
|
|
218
|
+
localId: 0 as never,
|
|
219
|
+
components: {
|
|
220
|
+
Transform: {},
|
|
221
|
+
MeshFilter: { assetHandle: HANDLE_CUBE as never },
|
|
222
|
+
},
|
|
223
|
+
},
|
|
224
|
+
],
|
|
225
|
+
};
|
|
226
|
+
const sceneHandle = world.allocSharedRef<'SceneAsset', SceneAsset>('SceneAsset', scene);
|
|
227
|
+
const instantiated = SceneOwner.worldInstantiateScene(world, sceneHandle);
|
|
228
|
+
expect(instantiated.ok).toBe(true);
|
|
229
|
+
if (!instantiated.ok) return;
|
|
230
|
+
|
|
231
|
+
const collected = rootsToSceneAsset(registry, world, [instantiated.value.root]);
|
|
232
|
+
expect(collected.ok).toBe(true);
|
|
233
|
+
if (!collected.ok) return;
|
|
234
|
+
const meshEntity = collected.value.entities.find(
|
|
235
|
+
(entity) => entity.components.MeshFilter !== undefined,
|
|
236
|
+
);
|
|
237
|
+
expect(meshEntity?.components.MeshFilter?.assetHandle).toBe(GUID_A);
|
|
238
|
+
});
|
|
239
|
+
});
|
|
240
|
+
|
|
208
241
|
// ── w14 (M4) PROBE: mounted-scene-with-material identity anchor ──────────
|
|
209
242
|
//
|
|
210
243
|
// feat-20260713 M4 / w14 (D-6, probe-first). Empirically anchors the true
|
|
@@ -10,11 +10,8 @@
|
|
|
10
10
|
// AC-01: PBR instances=N vs instances=1 frames differ (diffCount>0).
|
|
11
11
|
// AC-06: single entity + N instance reads meshes[0] (not meshes[instance_index]).
|
|
12
12
|
//
|
|
13
|
-
//
|
|
14
|
-
//
|
|
15
|
-
// (diffCount===0) because instance=1 at origin and instances=N all at origin
|
|
16
|
-
// produce the same pixel pattern. GREEN after w4 lands (PBR vs_main reads
|
|
17
|
-
// meshes[0] + instances[idx]).
|
|
13
|
+
// The PBR vertex path must combine the entity transform from meshes[0] with
|
|
14
|
+
// the per-instance transform selected by instance_index.
|
|
18
15
|
//
|
|
19
16
|
// Dual-state methodology: render to two textures (instances=N vs instances=1),
|
|
20
17
|
// read back both, count pixels that differ by more than epsilon. The
|
|
@@ -52,6 +49,11 @@ const INSTANCE_GRID_Y = 3;
|
|
|
52
49
|
const INSTANCE_GRID_Z = 2;
|
|
53
50
|
const INSTANCE_COUNT = INSTANCE_GRID_X * INSTANCE_GRID_Y * INSTANCE_GRID_Z; // 30
|
|
54
51
|
const SPACING = 2.5;
|
|
52
|
+
// Windows Dawn first-touch attempts have reached about 80 seconds for this
|
|
53
|
+
// two-renderer PBR/readback probe. Keep the test bounded, but above the
|
|
54
|
+
// project-wide 30-second budget so retries do not turn a slow valid probe into
|
|
55
|
+
// a cancelled nightly job.
|
|
56
|
+
const PBR_DAWN_TEST_TIMEOUT_MS = 120_000;
|
|
55
57
|
|
|
56
58
|
function buildTranslationGrid(): Float32Array {
|
|
57
59
|
const out = new Float32Array(INSTANCE_COUNT * 16);
|
|
@@ -85,8 +87,10 @@ const ENGINE_MANIFEST_URL = `data:application/json,${encodeURIComponent(
|
|
|
85
87
|
JSON.stringify(ENGINE_MANIFEST),
|
|
86
88
|
)}`;
|
|
87
89
|
|
|
88
|
-
describe('w2 -- PBR dual-state dawn smoke (AC-01 / AC-06
|
|
89
|
-
it('instances=N vs instances=1: frames differ in pixel diff count
|
|
90
|
+
describe('w2 -- PBR dual-state dawn smoke (AC-01 / AC-06)', () => {
|
|
91
|
+
it('instances=N vs instances=1: frames differ in pixel diff count', {
|
|
92
|
+
timeout: PBR_DAWN_TEST_TIMEOUT_MS,
|
|
93
|
+
}, async () => {
|
|
90
94
|
const dawnAvailable = typeof globalThis.navigator?.gpu?.requestAdapter === 'function';
|
|
91
95
|
if (!dawnAvailable) {
|
|
92
96
|
throw new Error('dawn-node navigator.gpu not injected; vitest.setup-webgpu.ts regressed');
|
|
@@ -366,9 +370,6 @@ describe('w2 -- PBR dual-state dawn smoke (AC-01 / AC-06, RED before w4)', () =>
|
|
|
366
370
|
|
|
367
371
|
// AC-01: diffCount>0 -- the two frames must differ (instances=N spreads
|
|
368
372
|
// to distinct positions, instances=1 renders at entity origin only).
|
|
369
|
-
// RED before w4: all N copies collapse to entity origin, so both frames
|
|
370
|
-
// render the same cube at the same position -> diffCount===0.
|
|
371
|
-
// Currently RED: diffCount===0 because shader doesn't read @group(3)
|
|
372
373
|
expect(diffCount).toBeGreaterThan(0);
|
|
373
374
|
// Also verify the N-instance frame has substantial non-clear pixels
|
|
374
375
|
// (proves instances rendered, not just an empty frame)
|
|
@@ -377,7 +378,7 @@ describe('w2 -- PBR dual-state dawn smoke (AC-01 / AC-06, RED before w4)', () =>
|
|
|
377
378
|
});
|
|
378
379
|
|
|
379
380
|
// w5 -- unlit dual-state: N unlit instances at distinct NDC positions (AC-02)
|
|
380
|
-
it('unlit Instances=N vs instances=1: frames differ
|
|
381
|
+
it('unlit Instances=N vs instances=1: frames differ', async () => {
|
|
381
382
|
const dawnAvailable_2 = typeof globalThis.navigator?.gpu?.requestAdapter === 'function';
|
|
382
383
|
if (!dawnAvailable_2) {
|
|
383
384
|
throw new Error('dawn-node navigator.gpu not injected');
|
|
@@ -3,9 +3,22 @@ import { fileURLToPath } from 'node:url';
|
|
|
3
3
|
import { describe, expect, it } from 'vitest';
|
|
4
4
|
|
|
5
5
|
type CookedRecord = {
|
|
6
|
-
readonly
|
|
7
|
-
readonly
|
|
8
|
-
readonly
|
|
6
|
+
readonly specializationKey: string;
|
|
7
|
+
readonly artifactDigest: string;
|
|
8
|
+
readonly artifact: { readonly digest: string; readonly bytes: readonly number[] };
|
|
9
|
+
readonly resolved?: {
|
|
10
|
+
readonly values?: unknown;
|
|
11
|
+
};
|
|
12
|
+
readonly receipt?: {
|
|
13
|
+
readonly identity?: {
|
|
14
|
+
readonly layoutIdentity?: string;
|
|
15
|
+
readonly programIdentity?: string;
|
|
16
|
+
readonly pipelineIdentity?: string;
|
|
17
|
+
readonly cookIdentity?: string;
|
|
18
|
+
readonly compilerFingerprint?: string;
|
|
19
|
+
};
|
|
20
|
+
readonly schemaVersion?: string;
|
|
21
|
+
};
|
|
9
22
|
};
|
|
10
23
|
|
|
11
24
|
type MaterialRow = {
|
|
@@ -34,9 +47,29 @@ describe('custom-shader cooked MaterialAsset fixture', () => {
|
|
|
34
47
|
const derived = fixture.assets.find((asset) => asset.payload.role === 'derived');
|
|
35
48
|
expect(root?.payload.cooked).toBeDefined();
|
|
36
49
|
expect(derived?.payload.cooked).toBeDefined();
|
|
37
|
-
expect(derived?.payload.cooked?.
|
|
38
|
-
|
|
39
|
-
|
|
50
|
+
expect(derived?.payload.cooked?.specializationKey).toBe(
|
|
51
|
+
root?.payload.cooked?.specializationKey,
|
|
52
|
+
);
|
|
53
|
+
expect(derived?.payload.cooked?.artifactDigest).toBe(root?.payload.cooked?.artifactDigest);
|
|
54
|
+
expect(derived?.payload.cooked?.artifact.bytes).toEqual(root?.payload.cooked?.artifact.bytes);
|
|
55
|
+
expect(derived?.payload.cooked?.resolved?.values).toEqual(
|
|
56
|
+
root?.payload.cooked?.resolved?.values,
|
|
57
|
+
);
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it('keeps cooked layout identity and authored coordinate transforms', () => {
|
|
61
|
+
const root = fixture.assets.find((asset) => asset.payload.role === 'root');
|
|
62
|
+
const cooked = root?.payload.cooked;
|
|
63
|
+
expect(cooked?.receipt?.schemaVersion).toBe('material-cook/3');
|
|
64
|
+
expect(cooked?.receipt?.identity?.layoutIdentity).toMatch(/^sha256-/);
|
|
65
|
+
expect(cooked?.receipt?.identity?.programIdentity).toMatch(/^sha256:/);
|
|
66
|
+
expect(cooked?.receipt?.identity?.pipelineIdentity).toMatch(/^sha256:/);
|
|
67
|
+
expect(cooked?.receipt?.identity?.cookIdentity).toMatch(/^sha256:/);
|
|
68
|
+
expect(cooked?.receipt?.identity?.compilerFingerprint).toMatch(/^sha256-/);
|
|
69
|
+
expect(cooked?.resolved?.values).toMatchObject({
|
|
70
|
+
baseColorUvTransform: [0, 0, 1, 1],
|
|
71
|
+
normalUvTransform: [0.125, 0.25, 2, 2],
|
|
72
|
+
});
|
|
40
73
|
});
|
|
41
74
|
|
|
42
75
|
it('runs the real Dawn path for exactly 300 frames without unexpected RHI errors', () => {
|
|
@@ -418,14 +418,30 @@ type RuntimeLayerError = RenderError | AssetRuntimeError | SkinError;
|
|
|
418
418
|
return 'recovery failed';
|
|
419
419
|
case 'cleanup-failed':
|
|
420
420
|
return 'cleanup failed';
|
|
421
|
+
case 'scene-data-unavailable':
|
|
422
|
+
return 'scene data unavailable';
|
|
421
423
|
case 'frame-receipt-stale':
|
|
422
424
|
return 'frame receipt stale';
|
|
423
425
|
case 'renderer-contract-failed':
|
|
424
426
|
return 'renderer contract failed';
|
|
425
427
|
case 'observation-unavailable':
|
|
426
428
|
return 'observation unavailable';
|
|
429
|
+
case 'taa-unavailable':
|
|
430
|
+
return 'taa unavailable';
|
|
427
431
|
case 'shadow-invalid-config':
|
|
428
432
|
return 'shadow invalid config';
|
|
433
|
+
case 'environment-source-conflict':
|
|
434
|
+
return 'environment source conflict';
|
|
435
|
+
case 'fog-cardinality':
|
|
436
|
+
return 'fog cardinality';
|
|
437
|
+
case 'taa-caps-insufficient':
|
|
438
|
+
return 'taa caps insufficient';
|
|
439
|
+
case 'environment-generation-failed':
|
|
440
|
+
return 'environment generation failed';
|
|
441
|
+
case 'atmosphere-invalid-parameter':
|
|
442
|
+
return 'atmosphere invalid parameter';
|
|
443
|
+
case 'owner-stage-failed':
|
|
444
|
+
return 'owner stage failed';
|
|
429
445
|
case 'skin-joint-count-exceeded':
|
|
430
446
|
return 'skin joint count exceeded';
|
|
431
447
|
case 'skin-joint-despawned':
|
|
@@ -500,6 +516,20 @@ type RuntimeLayerError = RenderError | AssetRuntimeError | SkinError;
|
|
|
500
516
|
return 'render feature prepared state mismatch';
|
|
501
517
|
case 'render-feature-draw-recording-failed':
|
|
502
518
|
return 'render feature draw recording failed';
|
|
519
|
+
case 'points-lines-invalid-style':
|
|
520
|
+
return 'points lines invalid style';
|
|
521
|
+
case 'points-lines-topology-mismatch':
|
|
522
|
+
return 'points lines topology mismatch';
|
|
523
|
+
case 'points-lines-style-unsupported':
|
|
524
|
+
return 'points lines style unsupported';
|
|
525
|
+
case 'points-lines-material-unsupported':
|
|
526
|
+
return 'points lines material unsupported';
|
|
527
|
+
case 'points-lines-budget-exceeded':
|
|
528
|
+
return 'points lines budget exceeded';
|
|
529
|
+
case 'points-lines-prepare-failed':
|
|
530
|
+
return 'points lines prepare failed';
|
|
531
|
+
case 'transmission-capability-missing':
|
|
532
|
+
return 'transmission capability missing';
|
|
503
533
|
}
|
|
504
534
|
}
|
|
505
535
|
expect(exhaustive('equirect-projection-failed')).toBe('equirect projection failed');
|
|
@@ -550,14 +580,30 @@ type RuntimeLayerError = RenderError | AssetRuntimeError | SkinError;
|
|
|
550
580
|
return 'ok';
|
|
551
581
|
case 'cleanup-failed':
|
|
552
582
|
return 'ok';
|
|
583
|
+
case 'scene-data-unavailable':
|
|
584
|
+
return 'ok';
|
|
553
585
|
case 'frame-receipt-stale':
|
|
554
586
|
return 'ok';
|
|
555
587
|
case 'renderer-contract-failed':
|
|
556
588
|
return 'ok';
|
|
557
589
|
case 'observation-unavailable':
|
|
558
590
|
return 'ok';
|
|
591
|
+
case 'taa-unavailable':
|
|
592
|
+
return 'ok';
|
|
559
593
|
case 'shadow-invalid-config':
|
|
560
594
|
return 'ok';
|
|
595
|
+
case 'environment-source-conflict':
|
|
596
|
+
return 'ok';
|
|
597
|
+
case 'fog-cardinality':
|
|
598
|
+
return 'ok';
|
|
599
|
+
case 'taa-caps-insufficient':
|
|
600
|
+
return 'ok';
|
|
601
|
+
case 'environment-generation-failed':
|
|
602
|
+
return 'ok';
|
|
603
|
+
case 'atmosphere-invalid-parameter':
|
|
604
|
+
return 'ok';
|
|
605
|
+
case 'owner-stage-failed':
|
|
606
|
+
return 'ok';
|
|
561
607
|
case 'skin-joint-count-exceeded':
|
|
562
608
|
return 'ok';
|
|
563
609
|
case 'skin-joint-despawned':
|
|
@@ -620,6 +666,20 @@ type RuntimeLayerError = RenderError | AssetRuntimeError | SkinError;
|
|
|
620
666
|
return 'ok';
|
|
621
667
|
case 'render-feature-draw-recording-failed':
|
|
622
668
|
return 'ok';
|
|
669
|
+
case 'points-lines-invalid-style':
|
|
670
|
+
return 'ok';
|
|
671
|
+
case 'points-lines-topology-mismatch':
|
|
672
|
+
return 'ok';
|
|
673
|
+
case 'points-lines-style-unsupported':
|
|
674
|
+
return 'ok';
|
|
675
|
+
case 'points-lines-material-unsupported':
|
|
676
|
+
return 'ok';
|
|
677
|
+
case 'points-lines-budget-exceeded':
|
|
678
|
+
return 'ok';
|
|
679
|
+
case 'points-lines-prepare-failed':
|
|
680
|
+
return 'ok';
|
|
681
|
+
case 'transmission-capability-missing':
|
|
682
|
+
return 'ok';
|
|
623
683
|
}
|
|
624
684
|
}
|
|
625
685
|
expect(exhaustive('hdrp-deferred-caps-insufficient')).toBe('ok');
|
|
@@ -12,16 +12,15 @@
|
|
|
12
12
|
// not actually happen — the 4th texture (heightTexture) would silently fall
|
|
13
13
|
// through.
|
|
14
14
|
//
|
|
15
|
-
// Scope of the gate — the three
|
|
15
|
+
// Scope of the gate — the three user-authored base texture fields:
|
|
16
16
|
// baseColorTexture / metallicRoughnessTexture / normalTexture
|
|
17
17
|
// These are the fields `derive(default-standard-pbr).textureFieldNames`
|
|
18
18
|
// produces and that w7/w8 route through iteration.
|
|
19
19
|
//
|
|
20
20
|
// Deliberately NOT gated (legitimate residual naming):
|
|
21
|
-
// - emissiveTexture / occlusionTexture:
|
|
22
|
-
//
|
|
23
|
-
//
|
|
24
|
-
// them there is the engine-managed region, not user-region hardcoding.
|
|
21
|
+
// - emissiveTexture / occlusionTexture: legacy engine-owned snapshot fields
|
|
22
|
+
// still have named reads, while the production Standard BGL no longer adds
|
|
23
|
+
// a duplicate lightmap region.
|
|
25
24
|
// - USER_REGION_TEXTURE_FIELDS in derive-paramschema.ts: the 3-field
|
|
26
25
|
// register-time under-declaration validator (charter P3 safety net from
|
|
27
26
|
// the 4.3 blending regression). Orthogonal to binding; lives in a
|