@forgeax/engine-runtime 0.1.19 → 0.1.21
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 +102 -0
- package/dist/.tsbuildinfo +1 -1
- package/dist/__tests__/create-renderer-gpu-pass-timing.unit.test.d.ts +2 -0
- package/dist/__tests__/create-renderer-gpu-pass-timing.unit.test.d.ts.map +1 -0
- package/dist/__tests__/helpers/tilemap-assets.d.ts.map +1 -1
- package/dist/__tests__/lights-preservation.fixup.test.d.ts +2 -0
- package/dist/__tests__/lights-preservation.fixup.test.d.ts.map +1 -0
- package/dist/__tests__/material-texture-dimension-mismatch.unit.test.d.ts +2 -0
- package/dist/__tests__/material-texture-dimension-mismatch.unit.test.d.ts.map +1 -0
- package/dist/__tests__/render-error-exhaustive.test-d.d.ts.map +1 -1
- package/dist/__tests__/texture-dimensions.browser.test.d.ts +2 -0
- package/dist/__tests__/texture-dimensions.browser.test.d.ts.map +1 -0
- package/dist/__tests__/volumetric-fog-record-recovery.integration.test.d.ts +2 -0
- package/dist/__tests__/volumetric-fog-record-recovery.integration.test.d.ts.map +1 -0
- package/dist/createRenderer.d.ts.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.mjs +3 -1
- package/dist/index.mjs.map +1 -1
- package/package.json +30 -30
- package/src/__tests__/active-camera.unit.test.ts +6 -8
- package/src/__tests__/asset-registry.recursive.spec.ts +13 -19
- package/src/__tests__/asset.unit.test.ts +28 -25
- package/src/__tests__/basis-catalog-dispatch.integration.test.ts +10 -9
- package/src/__tests__/clamp-to-last.e2e.browser.test.ts +2 -2
- package/src/__tests__/components.test-d.ts +10 -3
- package/src/__tests__/components.unit.test.ts +13 -7
- package/src/__tests__/compressed-texture-physical-extent.integration.test.ts +12 -10
- package/src/__tests__/create-renderer-assembly.integration.test.ts +24 -0
- package/src/__tests__/create-renderer-gpu-pass-timing.unit.test.ts +32 -0
- package/src/__tests__/createRenderer.browser-no-webgpu.test.ts +66 -0
- package/src/__tests__/dawn/hello-sprite-nineslice-section.dawn.test.ts +11 -4
- package/src/__tests__/dawn/instances-shadow.dawn.test.ts +15 -2
- package/src/__tests__/dawn/material-alpha.dawn.test.ts +2 -3
- package/src/__tests__/dawn/mipmap-srgb-linear.dawn.test.ts +2 -3
- package/src/__tests__/dawn/per-entity-material-texture-isolation.dawn.test.ts +2 -3
- package/src/__tests__/dawn/sprite-nineslice-mesh-bind.dawn.test.ts +2 -3
- package/src/__tests__/dawn/upload-texture.dawn.test.ts +4 -6
- package/src/__tests__/derive-bgl-integration.test.ts +11 -0
- package/src/__tests__/equirect-bc6h.integration.test.ts +6 -4
- package/src/__tests__/errors.unit.test.ts +71 -20
- package/src/__tests__/extract-frames-merge.test.ts +48 -40
- package/src/__tests__/extract-skin-mismatch.unit.test.ts +6 -2
- package/src/__tests__/four-path-compression.integration.test.ts +2 -2
- package/src/__tests__/frame-targets-shadow-regression.unit.test.ts +13 -0
- package/src/__tests__/geometry.unit.test.ts +7 -10
- package/src/__tests__/gpu-resource-cow-survivor.test.ts +2 -3
- package/src/__tests__/helpers/tilemap-assets.ts +3 -4
- package/src/__tests__/light-gpu-byte-neutral.unit.test.ts +6 -3
- package/src/__tests__/light-snapshot.test-d.ts +8 -0
- package/src/__tests__/lights-preservation.fixup.test.ts +127 -0
- package/src/__tests__/lights.unit.test.ts +75 -2214
- package/src/__tests__/loadbyguid-texture-intern.unit.test.ts +3 -4
- package/src/__tests__/loader-name-survival.test.ts +2 -3
- package/src/__tests__/material-texture-dimension-mismatch.unit.test.ts +18 -0
- package/src/__tests__/material-texture-uv-scale.unit.test.ts +10 -2
- package/src/__tests__/mip-gate.unit.test.ts +11 -8
- package/src/__tests__/msaa-sprite-pixel-diff.dawn.test.ts +2 -3
- package/src/__tests__/new-kind-refs-contract.test.ts +2 -3
- package/src/__tests__/pbr-pipeline.unit.test.ts +29 -5
- package/src/__tests__/pipeline.unit.test.ts +66 -221
- package/src/__tests__/point-light-shadow.browser.test.ts +208 -83
- package/src/__tests__/point-light-shadow.unit.test.ts +67 -9
- package/src/__tests__/render-error-exhaustive.test-d.ts +92 -9
- package/src/__tests__/render-system-extract.test.ts +4 -6
- package/src/__tests__/render-system-mega.test.ts +30 -41
- package/src/__tests__/render-system-record-multi-material-textureview.test.ts +8 -7
- package/src/__tests__/render-system-record-per-submesh-transparency.test.ts +6 -4
- package/src/__tests__/render-system-skin-bg.unit.test.ts +14 -9
- package/src/__tests__/renderer-recover.unit.test.ts +8 -0
- package/src/__tests__/renderer-surface.unit.test.ts +229 -3
- package/src/__tests__/shadow-csm-atlas.test.ts +41 -0
- package/src/__tests__/shadow-csm-component.test.ts +31 -24
- package/src/__tests__/shadow-csm-extract.test.ts +156 -47
- package/src/__tests__/shadow-csm-runtime-vary.dawn.test.ts +72 -0
- package/src/__tests__/shadow-csm-shader.dawn.test.ts +19 -0
- package/src/__tests__/shadow-csm-ubo.test.ts +41 -45
- package/src/__tests__/shadow-csm-viewport.browser.test.ts +29 -0
- package/src/__tests__/shadow-fields-observable.dawn.test.ts +140 -58
- package/src/__tests__/skinned-shadow-mixed.dawn.test.ts +6 -2
- package/src/__tests__/skylight-lazy-projection.test.ts +8 -5
- package/src/__tests__/sprite-cullmode-flip.dawn.test.ts +4 -6
- package/src/__tests__/sprite-lit-bgl-byte-identical.test.ts +4 -2
- package/src/__tests__/ssao-bgl.test.ts +10 -16
- package/src/__tests__/ssao-passes.test.ts +19 -2
- package/src/__tests__/systems.unit.test.ts +59 -33
- package/src/__tests__/texture-dimensions.browser.test.ts +127 -0
- package/src/__tests__/transcode-fallback.unit.test.ts +5 -1
- package/src/__tests__/view-ubo-layout.browser.test.ts +20 -10
- package/src/__tests__/volumetric-fog-record-recovery.integration.test.ts +180 -0
- package/src/createRenderer.ts +4 -0
- package/src/index.ts +1 -2
|
@@ -64,13 +64,12 @@ function registerQuadMesh(world: World): Handle<'MeshAsset', 'shared'> {
|
|
|
64
64
|
function textureAsset(red = 255): TextureAsset {
|
|
65
65
|
return {
|
|
66
66
|
kind: 'texture',
|
|
67
|
-
width: 1,
|
|
68
|
-
height: 1,
|
|
67
|
+
shape: { viewDimension: '2d', extent: { width: 1, height: 1 } },
|
|
69
68
|
format: 'rgba8unorm',
|
|
70
69
|
data: new Uint8Array([red, 255, 255, 255]),
|
|
71
70
|
colorSpace: 'linear',
|
|
72
|
-
|
|
73
|
-
}
|
|
71
|
+
mips: { kind: 'none' },
|
|
72
|
+
};
|
|
74
73
|
}
|
|
75
74
|
|
|
76
75
|
// Build a loadByGuid-shaped scene: the material's baseColorTexture paramValue is
|
|
@@ -77,11 +77,10 @@ function makeSharedPack(): unknown {
|
|
|
77
77
|
|
|
78
78
|
const TEX_METADATA = {
|
|
79
79
|
kind: 'texture',
|
|
80
|
-
width: 1,
|
|
81
|
-
height: 1,
|
|
80
|
+
shape: { viewDimension: '2d', extent: { width: 1, height: 1 } },
|
|
82
81
|
format: 'rgba8unorm',
|
|
83
82
|
colorSpace: 'srgb',
|
|
84
|
-
|
|
83
|
+
mips: { kind: 'none' },
|
|
85
84
|
};
|
|
86
85
|
|
|
87
86
|
// `includeNames=false` is the FALSIFY variant (entry.name stripped).
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { derive } from '@forgeax/engine-types';
|
|
2
|
+
import { describe, expect, it } from 'vitest';
|
|
3
|
+
|
|
4
|
+
describe('material texture dimension mismatch contract', () => {
|
|
5
|
+
it('carries the authored array view dimension into the material binding interface', () => {
|
|
6
|
+
const derived = derive([{ name: 'layers', type: 'texture2d_array' }]);
|
|
7
|
+
|
|
8
|
+
expect(derived.coordinateRecords[0]?.parameter).toBe('layers');
|
|
9
|
+
expect(derived.bglEntries[2]?.texture?.viewDimension).toBe('2d-array');
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
it('carries the authored volume view dimension without changing the submit boundary', () => {
|
|
13
|
+
const derived = derive([{ name: 'volume', type: 'texture3d' }]);
|
|
14
|
+
|
|
15
|
+
expect(derived.bglEntries[2]?.texture?.viewDimension).toBe('3d');
|
|
16
|
+
expect(derived.resourceBindings).toHaveLength(2);
|
|
17
|
+
});
|
|
18
|
+
});
|
|
@@ -10,7 +10,10 @@ import {
|
|
|
10
10
|
|
|
11
11
|
describe('material texture UV scale [w37]', () => {
|
|
12
12
|
it('maps a non-aligned BC7 logical edge below padded physical storage', () => {
|
|
13
|
-
const scale = materialTextureUvScale({
|
|
13
|
+
const scale = materialTextureUvScale({
|
|
14
|
+
shape: { viewDimension: '2d', extent: { width: 2085, height: 1573 } },
|
|
15
|
+
format: 'bc7-rgba-unorm',
|
|
16
|
+
});
|
|
14
17
|
expect(scale).toEqual([2085 / 2088, 1573 / 1576]);
|
|
15
18
|
expect(scale[0]).toBeLessThan(1);
|
|
16
19
|
expect(scale[1]).toBeLessThan(1);
|
|
@@ -18,7 +21,12 @@ describe('material texture UV scale [w37]', () => {
|
|
|
18
21
|
|
|
19
22
|
it('uses identity scale for uncompressed and fallback texture bindings', () => {
|
|
20
23
|
expect(materialTextureUvScale(undefined)).toEqual([1, 1]);
|
|
21
|
-
expect(
|
|
24
|
+
expect(
|
|
25
|
+
materialTextureUvScale({
|
|
26
|
+
shape: { viewDimension: '2d', extent: { width: 17, height: 9 } },
|
|
27
|
+
format: 'rgba8unorm',
|
|
28
|
+
}),
|
|
29
|
+
).toEqual([1, 1]);
|
|
22
30
|
});
|
|
23
31
|
|
|
24
32
|
it('keeps compatibility param schemas compact when they have no textures', () => {
|
|
@@ -27,19 +27,20 @@ import { deriveRenderDataTexture } from '../../../render/src/render-data';
|
|
|
27
27
|
function tex(overrides: Partial<TextureAsset>): TextureAsset {
|
|
28
28
|
return {
|
|
29
29
|
kind: 'texture',
|
|
30
|
-
width: 8,
|
|
31
|
-
height: 8,
|
|
30
|
+
shape: { viewDimension: '2d', extent: { width: 8, height: 8 } },
|
|
32
31
|
format: 'rgba8unorm',
|
|
33
32
|
data: new Uint8Array(8 * 8 * 4),
|
|
34
33
|
colorSpace: 'linear',
|
|
35
|
-
|
|
34
|
+
mips: { kind: 'none' },
|
|
36
35
|
...overrides,
|
|
37
36
|
};
|
|
38
37
|
}
|
|
39
38
|
|
|
40
39
|
describe('deriveRenderDataTexture -- mip gate on compressed formats (w30, AC-09)', () => {
|
|
41
40
|
it('compressed format + mipmap:true (runtime mip-gen requested) -> error', () => {
|
|
42
|
-
const res = deriveRenderDataTexture(
|
|
41
|
+
const res = deriveRenderDataTexture(
|
|
42
|
+
tex({ format: 'bc7-rgba-unorm', mips: { kind: 'generate' } }),
|
|
43
|
+
);
|
|
43
44
|
expect(res.ok).toBe(false);
|
|
44
45
|
if (!res.ok) {
|
|
45
46
|
expect(res.error.code).toBe('mipgen-unsupported-compressed-format');
|
|
@@ -50,7 +51,9 @@ describe('deriveRenderDataTexture -- mip gate on compressed formats (w30, AC-09)
|
|
|
50
51
|
});
|
|
51
52
|
|
|
52
53
|
it('mip-gate error fires for an ETC2 compressed format too', () => {
|
|
53
|
-
const res = deriveRenderDataTexture(
|
|
54
|
+
const res = deriveRenderDataTexture(
|
|
55
|
+
tex({ format: 'etc2-rgba8unorm', mips: { kind: 'generate' } }),
|
|
56
|
+
);
|
|
54
57
|
expect(res.ok).toBe(false);
|
|
55
58
|
if (!res.ok) expect(res.error.code).toBe('mipgen-unsupported-compressed-format');
|
|
56
59
|
});
|
|
@@ -59,20 +62,20 @@ describe('deriveRenderDataTexture -- mip gate on compressed formats (w30, AC-09)
|
|
|
59
62
|
// The KTX2 loader baked the mip chain offline; this is the normal
|
|
60
63
|
// compressed-upload path and must NOT trip the runtime-mip-gen gate.
|
|
61
64
|
const res = deriveRenderDataTexture(
|
|
62
|
-
tex({ format: 'bc7-rgba-unorm',
|
|
65
|
+
tex({ format: 'bc7-rgba-unorm', mips: { kind: 'packed', levelCount: 4 } }),
|
|
63
66
|
);
|
|
64
67
|
expect(res.ok).toBe(true);
|
|
65
68
|
if (res.ok) expect(res.value.mipLevelCount).toBe(4);
|
|
66
69
|
});
|
|
67
70
|
|
|
68
71
|
it('compressed format + mipmap:false -> ok (single level)', () => {
|
|
69
|
-
const res = deriveRenderDataTexture(tex({ format: 'bc7-rgba-unorm',
|
|
72
|
+
const res = deriveRenderDataTexture(tex({ format: 'bc7-rgba-unorm', mips: { kind: 'none' } }));
|
|
70
73
|
expect(res.ok).toBe(true);
|
|
71
74
|
if (res.ok) expect(res.value.mipLevelCount).toBe(1);
|
|
72
75
|
});
|
|
73
76
|
|
|
74
77
|
it('uncompressed format + mipmap:true -> ok (existing runtime mip-gen path unchanged)', () => {
|
|
75
|
-
const res = deriveRenderDataTexture(tex({ format: 'rgba8unorm',
|
|
78
|
+
const res = deriveRenderDataTexture(tex({ format: 'rgba8unorm', mips: { kind: 'generate' } }));
|
|
76
79
|
expect(res.ok).toBe(true);
|
|
77
80
|
if (res.ok) expect(res.value.mipLevelCount).toBeGreaterThan(1);
|
|
78
81
|
});
|
|
@@ -260,12 +260,11 @@ describe('feat-20260604-msaa M2 w9 [F-1]: LDR sprite + MSAA split sub-pass cover
|
|
|
260
260
|
const synth = buildSyntheticRgba();
|
|
261
261
|
const synthPod = {
|
|
262
262
|
kind: 'texture' as const,
|
|
263
|
-
width: synth.width,
|
|
264
|
-
height: synth.height,
|
|
263
|
+
shape: { viewDimension: '2d' as const, extent: { width: synth.width, height: synth.height } },
|
|
265
264
|
format: 'rgba8unorm-srgb' as const,
|
|
266
265
|
data: synth.data,
|
|
267
266
|
colorSpace: 'srgb' as const,
|
|
268
|
-
|
|
267
|
+
mips: { kind: 'none' as const },
|
|
269
268
|
};
|
|
270
269
|
const TEX_GUID = '00000000-0000-7000-8000-0000000005a1';
|
|
271
270
|
const SAMPLER_GUID = '00000000-0000-7000-8000-0000000005a2';
|
|
@@ -62,12 +62,11 @@ describe('AC-07 — a new reference appears in the load graph via envelope.refs'
|
|
|
62
62
|
// new reference field whose GUID it dropped into refs[]".
|
|
63
63
|
reg.catalog(parseGuid(EXTRA_REF_GUID), {
|
|
64
64
|
kind: 'texture',
|
|
65
|
-
width: 1,
|
|
66
|
-
height: 1,
|
|
65
|
+
shape: { viewDimension: '2d', extent: { width: 1, height: 1 } },
|
|
67
66
|
format: 'rgba8unorm',
|
|
68
67
|
data: new Uint8Array(4),
|
|
69
68
|
colorSpace: 'srgb',
|
|
70
|
-
|
|
69
|
+
mips: { kind: 'none' },
|
|
71
70
|
});
|
|
72
71
|
|
|
73
72
|
const packIndex = [
|
|
@@ -44,7 +44,7 @@ function makeSpec(): PipelineSpec {
|
|
|
44
44
|
|
|
45
45
|
describe('buildBindGroupLayoutDescriptor — pbr-pipeline 6 sites byte-equiv', () => {
|
|
46
46
|
describe('pbr-view', () => {
|
|
47
|
-
it('storageBuffer=true:
|
|
47
|
+
it('storageBuffer=true: 12 entries with read-only-storage on bindings 1+2 and projector bindings 11+12', () => {
|
|
48
48
|
const spec = makeSpec();
|
|
49
49
|
const out = buildBindGroupLayoutDescriptor(spec, {
|
|
50
50
|
kind: 'pbr-view',
|
|
@@ -60,11 +60,15 @@ describe('buildBindGroupLayoutDescriptor — pbr-pipeline 6 sites byte-equiv', (
|
|
|
60
60
|
// Points/Lines viewport UBO occupies binding 10, while w25 (scope-amend
|
|
61
61
|
// webkit-fallback) folded the former binding 9 spotLightViewProj matrices
|
|
62
62
|
// UBO into the View UBO (`view.spotLightViewProj`), so the BGL stays at 9
|
|
63
|
-
// entries (bindings 0..8 plus
|
|
64
|
-
// buffer count <= 11
|
|
65
|
-
|
|
63
|
+
// entries (bindings 0..8 plus optional projector 11+12 and binding 10)
|
|
64
|
+
// — keeping the WebGL2 fallback fragment uniform-buffer count <= 11
|
|
65
|
+
// (GLES 3.0), while the projector remains available on the default
|
|
66
|
+
// WebGPU path.
|
|
67
|
+
expect(out.entries.length).toBe(12);
|
|
66
68
|
expect(out.entries.find((entry) => entry.binding === 9)).toBeUndefined();
|
|
67
69
|
expect(out.entries.find((entry) => entry.binding === 10)?.buffer?.type).toBe('uniform');
|
|
70
|
+
expect(out.entries.find((entry) => entry.binding === 11)?.texture?.viewDimension).toBe('2d');
|
|
71
|
+
expect(out.entries.find((entry) => entry.binding === 12)?.sampler?.type).toBe('filtering');
|
|
68
72
|
});
|
|
69
73
|
|
|
70
74
|
it('storageBuffer=false: bindings 1+2 fall back to uniform', () => {
|
|
@@ -79,6 +83,21 @@ describe('buildBindGroupLayoutDescriptor — pbr-pipeline 6 sites byte-equiv', (
|
|
|
79
83
|
};
|
|
80
84
|
expect(out).toEqual(expected);
|
|
81
85
|
});
|
|
86
|
+
|
|
87
|
+
it('projectorAvailable=false: omits optional projector bindings for the 16-texture limit', () => {
|
|
88
|
+
const spec = makeSpec();
|
|
89
|
+
const out = buildBindGroupLayoutDescriptor(spec, {
|
|
90
|
+
kind: 'pbr-view',
|
|
91
|
+
caps: { storageBuffer: true, projectorAvailable: false },
|
|
92
|
+
});
|
|
93
|
+
expect(out).toEqual({
|
|
94
|
+
label: 'pbr-view-bgl',
|
|
95
|
+
entries: buildPbrViewBglEntries({ storageBuffer: true, projectorAvailable: false }),
|
|
96
|
+
});
|
|
97
|
+
expect(out.entries.find((entry) => entry.binding === 11)).toBeUndefined();
|
|
98
|
+
expect(out.entries.find((entry) => entry.binding === 12)).toBeUndefined();
|
|
99
|
+
expect(out.entries.find((entry) => entry.binding === 10)?.buffer?.type).toBe('uniform');
|
|
100
|
+
});
|
|
82
101
|
});
|
|
83
102
|
|
|
84
103
|
describe('pbr-material-merged', () => {
|
|
@@ -160,7 +179,7 @@ describe('buildBindGroupLayoutDescriptor — pbr-pipeline 6 sites byte-equiv', (
|
|
|
160
179
|
});
|
|
161
180
|
|
|
162
181
|
describe('pbr-skin-mesh-array', () => {
|
|
163
|
-
it('storageBuffer=true:
|
|
182
|
+
it('storageBuffer=true: 3 entries, all dynamic offset', () => {
|
|
164
183
|
const spec = makeSpec();
|
|
165
184
|
const out = buildBindGroupLayoutDescriptor(spec, {
|
|
166
185
|
kind: 'pbr-skin-mesh-array',
|
|
@@ -179,6 +198,11 @@ describe('buildBindGroupLayoutDescriptor — pbr-pipeline 6 sites byte-equiv', (
|
|
|
179
198
|
visibility: 0x1,
|
|
180
199
|
buffer: { type: 'read-only-storage', hasDynamicOffset: true },
|
|
181
200
|
},
|
|
201
|
+
{
|
|
202
|
+
binding: 2,
|
|
203
|
+
visibility: 0x1,
|
|
204
|
+
buffer: { type: 'read-only-storage', hasDynamicOffset: true },
|
|
205
|
+
},
|
|
182
206
|
],
|
|
183
207
|
});
|
|
184
208
|
});
|