@flighthq/scene2d-wgpu 0.3.0 → 0.3.1-next.1041.35b950c
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/dist/enableWgpuColorAdjustmentGuards.d.ts.map +1 -1
- package/dist/enableWgpuColorAdjustmentGuards.js +13 -5
- package/dist/enableWgpuColorAdjustmentGuards.js.map +1 -1
- package/dist/enableWgpuStrokePathTessellation.d.ts.map +1 -1
- package/dist/enableWgpuStrokePathTessellation.js +7 -1
- package/dist/enableWgpuStrokePathTessellation.js.map +1 -1
- package/dist/wgpuCache.d.ts.map +1 -1
- package/dist/wgpuCache.js +30 -10
- package/dist/wgpuCache.js.map +1 -1
- package/dist/wgpuClipContours.d.ts.map +1 -1
- package/dist/wgpuClipContours.js +3 -2
- package/dist/wgpuClipContours.js.map +1 -1
- package/dist/wgpuColorAdjustmentMaterialFeature.d.ts.map +1 -1
- package/dist/wgpuColorAdjustmentMaterialFeature.js +9 -1
- package/dist/wgpuColorAdjustmentMaterialFeature.js.map +1 -1
- package/dist/wgpuMeshShapeRenderer.d.ts.map +1 -1
- package/dist/wgpuMeshShapeRenderer.js +3 -2
- package/dist/wgpuMeshShapeRenderer.js.map +1 -1
- package/dist/wgpuParticleEmitter2D.d.ts.map +1 -1
- package/dist/wgpuParticleEmitter2D.js +3 -3
- package/dist/wgpuParticleEmitter2D.js.map +1 -1
- package/dist/wgpuQuadBatchWriter.d.ts.map +1 -1
- package/dist/wgpuQuadBatchWriter.js +7 -5
- package/dist/wgpuQuadBatchWriter.js.map +1 -1
- package/dist/wgpuRichText.d.ts.map +1 -1
- package/dist/wgpuRichText.js +9 -6
- package/dist/wgpuRichText.js.map +1 -1
- package/dist/wgpuScale9Shape.d.ts.map +1 -1
- package/dist/wgpuScale9Shape.js +5 -2
- package/dist/wgpuScale9Shape.js.map +1 -1
- package/dist/wgpuShapeMesh.d.ts.map +1 -1
- package/dist/wgpuShapeMesh.js +6 -10
- package/dist/wgpuShapeMesh.js.map +1 -1
- package/dist/wgpuShapeRasterizer.d.ts.map +1 -1
- package/dist/wgpuShapeRasterizer.js +9 -2
- package/dist/wgpuShapeRasterizer.js.map +1 -1
- package/dist/wgpuSprite.d.ts.map +1 -1
- package/dist/wgpuSprite.js +2 -2
- package/dist/wgpuSprite.js.map +1 -1
- package/dist/wgpuTextLabel.js +2 -2
- package/dist/wgpuTextLabel.js.map +1 -1
- package/dist/wgpuVelocity.d.ts.map +1 -1
- package/dist/wgpuVelocity.js +11 -12
- package/dist/wgpuVelocity.js.map +1 -1
- package/package.json +22 -18
- package/src/enableWgpuColorAdjustmentGuards.test.ts +13 -8
- package/src/enableWgpuStrokePathTessellation.test.ts +10 -3
- package/src/wgpuCache.test.ts +154 -7
- package/src/wgpuColorAdjustmentMaterialFeature.test.ts +7 -6
- package/src/wgpuParticleEmitter2D.test.ts +20 -14
- package/src/wgpuShapeRasterizer.test.ts +11 -1
- package/src/wgpuTextLabel.test.ts +18 -2
- package/src/wgpuVelocity.test.ts +23 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@flighthq/scene2d-wgpu",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.1-next.1041.35b950c",
|
|
4
4
|
"author": "Joshua Granick and other contributors",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -38,23 +38,27 @@
|
|
|
38
38
|
"clean:dist": "tsx ../../scripts/clean-package-dist.ts"
|
|
39
39
|
},
|
|
40
40
|
"dependencies": {
|
|
41
|
-
"@flighthq/color": "0.3.
|
|
42
|
-
"@flighthq/scene2d": "0.3.
|
|
43
|
-
"@flighthq/scene2d-canvas": "0.3.
|
|
44
|
-
"@flighthq/geometry": "0.3.
|
|
45
|
-
"@flighthq/image": "0.3.
|
|
46
|
-
"@flighthq/log": "0.3.
|
|
47
|
-
"@flighthq/node": "0.3.
|
|
48
|
-
"@flighthq/path": "0.3.
|
|
49
|
-
"@flighthq/
|
|
50
|
-
"@flighthq/render
|
|
51
|
-
"@flighthq/
|
|
52
|
-
"@flighthq/
|
|
53
|
-
"@flighthq/
|
|
54
|
-
"@flighthq/
|
|
55
|
-
"@flighthq/
|
|
56
|
-
"@flighthq/
|
|
57
|
-
"@flighthq/
|
|
41
|
+
"@flighthq/color": "0.3.1-next.1041.35b950c",
|
|
42
|
+
"@flighthq/scene2d": "0.3.1-next.1041.35b950c",
|
|
43
|
+
"@flighthq/scene2d-canvas": "0.3.1-next.1041.35b950c",
|
|
44
|
+
"@flighthq/geometry": "0.3.1-next.1041.35b950c",
|
|
45
|
+
"@flighthq/image": "0.3.1-next.1041.35b950c",
|
|
46
|
+
"@flighthq/log": "0.3.1-next.1041.35b950c",
|
|
47
|
+
"@flighthq/node": "0.3.1-next.1041.35b950c",
|
|
48
|
+
"@flighthq/path": "0.3.1-next.1041.35b950c",
|
|
49
|
+
"@flighthq/registry": "0.3.1-next.1041.35b950c",
|
|
50
|
+
"@flighthq/render": "0.3.1-next.1041.35b950c",
|
|
51
|
+
"@flighthq/render-wgpu": "0.3.1-next.1041.35b950c",
|
|
52
|
+
"@flighthq/shape": "0.3.1-next.1041.35b950c",
|
|
53
|
+
"@flighthq/text": "0.3.1-next.1041.35b950c",
|
|
54
|
+
"@flighthq/textinput": "0.3.1-next.1041.35b950c",
|
|
55
|
+
"@flighthq/textlayout": "0.3.1-next.1041.35b950c",
|
|
56
|
+
"@flighthq/texture": "0.3.1-next.1041.35b950c",
|
|
57
|
+
"@flighthq/types": "0.3.1-next.1041.35b950c",
|
|
58
|
+
"@flighthq/velocity": "0.3.1-next.1041.35b950c"
|
|
59
|
+
},
|
|
60
|
+
"peerDependencies": {
|
|
61
|
+
"@webgpu/types": "^0.1.70"
|
|
58
62
|
},
|
|
59
63
|
"devDependencies": {
|
|
60
64
|
"@flighthq/bitmaptext": "*",
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import { addLogSink, createMemoryLogSink, getMemoryLogSinkEntries, removeLogSink } from '@flighthq/log/contract';
|
|
2
|
-
import { getWgpuRenderStateRuntime } from '@flighthq/render-wgpu/contract';
|
|
3
2
|
import { createWgpuRenderStateForTest, installWgpuMock } from '@flighthq/render-wgpu/contract';
|
|
3
|
+
import { getWgpuRenderStateRuntime } from '@flighthq/render-wgpu/contract';
|
|
4
4
|
import type { ColorScaleBias } from '@flighthq/types/contract';
|
|
5
|
+
import { RegistryEntryState } from '@flighthq/types/contract';
|
|
5
6
|
|
|
6
7
|
import {
|
|
7
8
|
areWgpuColorAdjustmentGuardsEnabled,
|
|
8
9
|
enableWgpuColorAdjustmentGuards,
|
|
9
10
|
} from './enableWgpuColorAdjustmentGuards';
|
|
11
|
+
import { registerWgpuColorAdjustmentMaterialFeature } from './wgpuColorAdjustmentMaterialFeature';
|
|
10
12
|
import { recordWgpuQuadBatchColorScaleBias } from './wgpuQuadBatchWriter';
|
|
11
13
|
|
|
12
14
|
beforeAll(() => {
|
|
@@ -32,6 +34,15 @@ describe('areWgpuColorAdjustmentGuardsEnabled', () => {
|
|
|
32
34
|
expect(areWgpuColorAdjustmentGuardsEnabled(state)).toBe(false);
|
|
33
35
|
enableWgpuColorAdjustmentGuards(state);
|
|
34
36
|
expect(areWgpuColorAdjustmentGuardsEnabled(state)).toBe(true);
|
|
37
|
+
const table = getWgpuRenderStateRuntime(state).registries.colorAdjustmentFeatureGuard;
|
|
38
|
+
expect(table).toMatchObject({
|
|
39
|
+
entry: { state: RegistryEntryState.Bound },
|
|
40
|
+
onMiss: 'Disabled',
|
|
41
|
+
registry: 'WgpuColorAdjustmentFeatureGuard',
|
|
42
|
+
shape: 'slot',
|
|
43
|
+
});
|
|
44
|
+
enableWgpuColorAdjustmentGuards(state);
|
|
45
|
+
expect(getWgpuRenderStateRuntime(state).registries.colorAdjustmentFeatureGuard).toBe(table);
|
|
35
46
|
});
|
|
36
47
|
});
|
|
37
48
|
|
|
@@ -67,17 +78,11 @@ describe('enableWgpuColorAdjustmentGuards', () => {
|
|
|
67
78
|
|
|
68
79
|
it('does not warn when the guard slot is present but color adjustment is also enabled', async () => {
|
|
69
80
|
const state = await createWgpuRenderStateForTest();
|
|
70
|
-
const runtime = getWgpuRenderStateRuntime(state);
|
|
71
81
|
const sink = createMemoryLogSink(8);
|
|
72
82
|
addLogSink(sink.sink);
|
|
73
83
|
try {
|
|
74
84
|
enableWgpuColorAdjustmentGuards(state);
|
|
75
|
-
|
|
76
|
-
fragmentShaderChunk: '',
|
|
77
|
-
matrixFragmentShaderChunk: '',
|
|
78
|
-
record: () => {},
|
|
79
|
-
resolveFlush: () => null,
|
|
80
|
-
};
|
|
85
|
+
registerWgpuColorAdjustmentMaterialFeature(state);
|
|
81
86
|
recordWgpuQuadBatchColorScaleBias(state, ct(), 0);
|
|
82
87
|
expect(getMemoryLogSinkEntries(sink).length).toBe(0);
|
|
83
88
|
} finally {
|
|
@@ -4,6 +4,7 @@ import {
|
|
|
4
4
|
getWgpuRenderStateRuntime,
|
|
5
5
|
installWgpuMock,
|
|
6
6
|
} from '@flighthq/render-wgpu/contract';
|
|
7
|
+
import { RegistryEntryState } from '@flighthq/types/contract';
|
|
7
8
|
|
|
8
9
|
import { enableWgpuStrokePathTessellation } from './enableWgpuStrokePathTessellation';
|
|
9
10
|
|
|
@@ -12,12 +13,18 @@ beforeAll(() => {
|
|
|
12
13
|
});
|
|
13
14
|
|
|
14
15
|
describe('enableWgpuStrokePathTessellation', () => {
|
|
15
|
-
it('
|
|
16
|
+
it('replaces the full stroke-tessellator policy slot', async () => {
|
|
16
17
|
const state = await createWgpuRenderStateForTest();
|
|
17
|
-
|
|
18
|
+
const runtime = getWgpuRenderStateRuntime(state);
|
|
19
|
+
const before = runtime.registries.strokeTessellator;
|
|
20
|
+
expect(before.entry).toBeNull();
|
|
18
21
|
|
|
19
22
|
enableWgpuStrokePathTessellation(state);
|
|
20
23
|
|
|
21
|
-
expect(
|
|
24
|
+
expect(runtime.registries.strokeTessellator).not.toBe(before);
|
|
25
|
+
expect(runtime.registries.strokeTessellator.entry).toEqual({
|
|
26
|
+
state: RegistryEntryState.Bound,
|
|
27
|
+
value: tessellateStrokePath,
|
|
28
|
+
});
|
|
22
29
|
});
|
|
23
30
|
});
|
package/src/wgpuCache.test.ts
CHANGED
|
@@ -1,9 +1,24 @@
|
|
|
1
1
|
import { createMatrix } from '@flighthq/geometry/contract';
|
|
2
|
+
import { getRegistryTableEntry } from '@flighthq/registry/contract';
|
|
2
3
|
import type * as WgpuRenderWgpuModule from '@flighthq/render-wgpu/contract';
|
|
3
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
createRenderCache,
|
|
6
|
+
createRenderState,
|
|
7
|
+
enableColorAdjustmentGuards,
|
|
8
|
+
getColorAdjustmentUnsupportedGuard,
|
|
9
|
+
RenderCacheKind,
|
|
10
|
+
useRenderCache,
|
|
11
|
+
} from '@flighthq/render/contract';
|
|
4
12
|
import { createDisplayObject } from '@flighthq/scene2d/contract';
|
|
5
|
-
import type {
|
|
6
|
-
|
|
13
|
+
import type {
|
|
14
|
+
WgpuColorAdjustmentMaterialFeature,
|
|
15
|
+
WgpuColorAdjustmentMaterialFeatureGuard,
|
|
16
|
+
WgpuMaterialRenderer,
|
|
17
|
+
WgpuRenderState,
|
|
18
|
+
RenderRootGuard,
|
|
19
|
+
WgpuRenderTarget,
|
|
20
|
+
} from '@flighthq/types/contract';
|
|
21
|
+
import { EntityRuntimeKey, RegistryEntryState } from '@flighthq/types/contract';
|
|
7
22
|
|
|
8
23
|
import { scopeModuleMocks } from './moduleMockTestHelper';
|
|
9
24
|
import type * as WgpuCacheModule from './wgpuCache';
|
|
@@ -28,6 +43,9 @@ let refreshWgpuRenderCache: typeof WgpuCacheModule.refreshWgpuRenderCache;
|
|
|
28
43
|
let releaseWgpuRenderCache: typeof WgpuCacheModule.releaseWgpuRenderCache;
|
|
29
44
|
let createWgpuRenderStateRuntime: typeof WgpuRenderWgpuModule.createWgpuRenderStateRuntime;
|
|
30
45
|
let getWgpuRenderStateRuntime: typeof WgpuRenderWgpuModule.getWgpuRenderStateRuntime;
|
|
46
|
+
let getWgpuMaterialRenderer: typeof WgpuRenderWgpuModule.getWgpuMaterialRenderer;
|
|
47
|
+
let registerWgpuMaterialRenderer: typeof WgpuRenderWgpuModule.registerWgpuMaterialRenderer;
|
|
48
|
+
let resolveWgpuApplyBlendMode: typeof WgpuRenderWgpuModule.resolveWgpuApplyBlendMode;
|
|
31
49
|
let beginWgpuFrame: typeof WgpuRenderWgpuModule.beginWgpuFrame;
|
|
32
50
|
let destroyWgpuRenderTarget: typeof WgpuRenderWgpuModule.destroyWgpuRenderTarget;
|
|
33
51
|
let drawWgpuRenderTargetResult: typeof WgpuRenderWgpuModule.drawWgpuRenderTargetResult;
|
|
@@ -92,7 +110,10 @@ beforeAll(async () => {
|
|
|
92
110
|
createWgpuRenderStateRuntime,
|
|
93
111
|
destroyWgpuRenderTarget,
|
|
94
112
|
drawWgpuRenderTargetResult,
|
|
113
|
+
getWgpuMaterialRenderer,
|
|
95
114
|
getWgpuRenderStateRuntime,
|
|
115
|
+
registerWgpuMaterialRenderer,
|
|
116
|
+
resolveWgpuApplyBlendMode,
|
|
96
117
|
submitWgpuRenderPass,
|
|
97
118
|
} = await import('@flighthq/render-wgpu/contract'));
|
|
98
119
|
({ flushWgpuQuadBatchWriter } = await import('./wgpuQuadBatchWriter'));
|
|
@@ -124,18 +145,141 @@ function makeCacheNode(source: unknown): any {
|
|
|
124
145
|
}
|
|
125
146
|
|
|
126
147
|
describe('createWgpuCacheState', () => {
|
|
148
|
+
it('resolves late screen blend-mode wiring explicitly until locally overridden', () => {
|
|
149
|
+
const screen = fakeScreen();
|
|
150
|
+
screen.applyBlendMode = null;
|
|
151
|
+
const cacheState = createWgpuCacheState(screen);
|
|
152
|
+
const screenHook = vi.fn();
|
|
153
|
+
const laterScreenHook = vi.fn();
|
|
154
|
+
const cacheHook = vi.fn();
|
|
155
|
+
|
|
156
|
+
expect(cacheState.applyBlendMode).toBeNull();
|
|
157
|
+
expect(Object.getOwnPropertyDescriptor(cacheState, 'applyBlendMode')?.get).toBeUndefined();
|
|
158
|
+
expect(resolveWgpuApplyBlendMode(cacheState)).toBeNull();
|
|
159
|
+
screen.applyBlendMode = screenHook;
|
|
160
|
+
expect(cacheState.applyBlendMode).toBeNull();
|
|
161
|
+
expect(resolveWgpuApplyBlendMode(cacheState)).toBe(screenHook);
|
|
162
|
+
|
|
163
|
+
cacheState.applyBlendMode = cacheHook;
|
|
164
|
+
screen.applyBlendMode = laterScreenHook;
|
|
165
|
+
expect(resolveWgpuApplyBlendMode(cacheState)).toBe(cacheHook);
|
|
166
|
+
});
|
|
167
|
+
|
|
127
168
|
it('copies renderers and shares the GPU device but keeps its own node map', () => {
|
|
128
169
|
const screen = fakeScreen();
|
|
129
170
|
const resolver = vi.fn();
|
|
130
|
-
|
|
171
|
+
const colorAdjustmentFeature: WgpuColorAdjustmentMaterialFeature = {
|
|
172
|
+
fragmentShaderChunk: '',
|
|
173
|
+
matrixFragmentShaderChunk: '',
|
|
174
|
+
record: vi.fn(),
|
|
175
|
+
resolveFlush: vi.fn(() => null),
|
|
176
|
+
};
|
|
177
|
+
const colorAdjustmentFeatureGuard: WgpuColorAdjustmentMaterialFeatureGuard = vi.fn();
|
|
178
|
+
const renderRootGuard: RenderRootGuard = vi.fn();
|
|
179
|
+
const screenRuntime = getWgpuRenderStateRuntime(screen);
|
|
180
|
+
screenRuntime.registries.colorAdjustments = {
|
|
181
|
+
entry: { state: RegistryEntryState.Bound, value: resolver },
|
|
182
|
+
onMiss: 'Disabled',
|
|
183
|
+
registry: 'ColorAdjustments',
|
|
184
|
+
shape: 'slot',
|
|
185
|
+
};
|
|
186
|
+
screenRuntime.registries.colorAdjustmentFeature = {
|
|
187
|
+
entry: { state: RegistryEntryState.Bound, value: colorAdjustmentFeature },
|
|
188
|
+
onMiss: 'Disabled',
|
|
189
|
+
registry: 'WgpuColorAdjustmentFeature',
|
|
190
|
+
shape: 'slot',
|
|
191
|
+
};
|
|
192
|
+
screenRuntime.registries.colorAdjustmentFeatureGuard = {
|
|
193
|
+
entry: { state: RegistryEntryState.Bound, value: colorAdjustmentFeatureGuard },
|
|
194
|
+
onMiss: 'Disabled',
|
|
195
|
+
registry: 'WgpuColorAdjustmentFeatureGuard',
|
|
196
|
+
shape: 'slot',
|
|
197
|
+
};
|
|
198
|
+
screenRuntime.registries.renderRootGuard = {
|
|
199
|
+
entry: { state: RegistryEntryState.Bound, value: renderRootGuard },
|
|
200
|
+
onMiss: 'Disabled',
|
|
201
|
+
registry: 'RenderRootGuard',
|
|
202
|
+
shape: 'slot',
|
|
203
|
+
};
|
|
204
|
+
enableColorAdjustmentGuards(screen);
|
|
131
205
|
enableWgpuRenderCache(screen);
|
|
132
206
|
const cacheState = createWgpuCacheState(screen);
|
|
133
|
-
expect(getWgpuRenderStateRuntime(cacheState).
|
|
207
|
+
expect(getWgpuRenderStateRuntime(cacheState).registries.renderers.entries.get(RenderCacheKind)).toEqual({
|
|
208
|
+
state: 'bound',
|
|
209
|
+
value: defaultWgpuRenderCacheRenderer,
|
|
210
|
+
});
|
|
134
211
|
expect((cacheState as any).device).toBe((screen as any).device);
|
|
135
212
|
expect(getWgpuRenderStateRuntime(cacheState).renderProxyMap).not.toBe(
|
|
136
213
|
getWgpuRenderStateRuntime(screen).renderProxyMap,
|
|
137
214
|
);
|
|
138
|
-
expect(getWgpuRenderStateRuntime(cacheState).
|
|
215
|
+
expect(getWgpuRenderStateRuntime(cacheState).registries.colorAdjustments).toBe(
|
|
216
|
+
screenRuntime.registries.colorAdjustments,
|
|
217
|
+
);
|
|
218
|
+
expect(getWgpuRenderStateRuntime(cacheState).registries.colorAdjustmentFeature).toBe(
|
|
219
|
+
screenRuntime.registries.colorAdjustmentFeature,
|
|
220
|
+
);
|
|
221
|
+
const cacheRuntime = getWgpuRenderStateRuntime(cacheState);
|
|
222
|
+
expect(cacheRuntime.registries.colorAdjustmentFeatureGuard).toBe(
|
|
223
|
+
screenRuntime.registries.colorAdjustmentFeatureGuard,
|
|
224
|
+
);
|
|
225
|
+
const sharedColorFeatureGuard = cacheRuntime.registries.colorAdjustmentFeatureGuard;
|
|
226
|
+
screenRuntime.registries.colorAdjustmentFeatureGuard = undefined;
|
|
227
|
+
expect(cacheRuntime.registries.colorAdjustmentFeatureGuard).toBe(sharedColorFeatureGuard);
|
|
228
|
+
expect(cacheRuntime.registries.colorAdjustmentUnsupportedGuard).toBe(
|
|
229
|
+
screenRuntime.registries.colorAdjustmentUnsupportedGuard,
|
|
230
|
+
);
|
|
231
|
+
expect(getColorAdjustmentUnsupportedGuard(cacheState)).not.toBeNull();
|
|
232
|
+
const sharedUnsupportedGuard = cacheRuntime.registries.colorAdjustmentUnsupportedGuard;
|
|
233
|
+
screenRuntime.registries.colorAdjustmentUnsupportedGuard = undefined;
|
|
234
|
+
expect(getColorAdjustmentUnsupportedGuard(screen)).toBeNull();
|
|
235
|
+
expect(cacheRuntime.registries.colorAdjustmentUnsupportedGuard).toBe(sharedUnsupportedGuard);
|
|
236
|
+
expect(getColorAdjustmentUnsupportedGuard(cacheState)).not.toBeNull();
|
|
237
|
+
expect(cacheRuntime.registries.renderRootGuard).toBe(screenRuntime.registries.renderRootGuard);
|
|
238
|
+
expect(
|
|
239
|
+
getRegistryTableEntry(
|
|
240
|
+
cacheRuntime.registries.renderRootGuard!,
|
|
241
|
+
cacheRuntime.registries.renderRootGuard!.registry,
|
|
242
|
+
),
|
|
243
|
+
).toBe(renderRootGuard);
|
|
244
|
+
const sharedRootGuard = cacheRuntime.registries.renderRootGuard;
|
|
245
|
+
screenRuntime.registries.renderRootGuard = undefined;
|
|
246
|
+
expect(screenRuntime.registries.renderRootGuard).toBeUndefined();
|
|
247
|
+
expect(cacheRuntime.registries.renderRootGuard).toBe(sharedRootGuard);
|
|
248
|
+
expect(
|
|
249
|
+
getRegistryTableEntry(
|
|
250
|
+
cacheRuntime.registries.renderRootGuard!,
|
|
251
|
+
cacheRuntime.registries.renderRootGuard!.registry,
|
|
252
|
+
),
|
|
253
|
+
).toBe(renderRootGuard);
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
it('shares persistent registration snapshots through a distinct aggregate and then diverges', () => {
|
|
257
|
+
const screen = fakeScreen();
|
|
258
|
+
const first: WgpuMaterialRenderer = { instanceFloatCount: 0, getShaderModule: vi.fn() };
|
|
259
|
+
const replacement: WgpuMaterialRenderer = { instanceFloatCount: 0, getShaderModule: vi.fn() };
|
|
260
|
+
registerWgpuMaterialRenderer(screen, 'acme.Material', first);
|
|
261
|
+
|
|
262
|
+
const cacheState = createWgpuCacheState(screen);
|
|
263
|
+
const screenRuntime = getWgpuRenderStateRuntime(screen);
|
|
264
|
+
const cacheRuntime = getWgpuRenderStateRuntime(cacheState);
|
|
265
|
+
expect(cacheRuntime.registries).not.toBe(screenRuntime.registries);
|
|
266
|
+
expect(cacheRuntime.registries.colorAdjustments).toBe(screenRuntime.registries.colorAdjustments);
|
|
267
|
+
expect(cacheRuntime.registries.compressedTextureDecoder).toBe(screenRuntime.registries.compressedTextureDecoder);
|
|
268
|
+
expect(cacheRuntime.registries.compressedTextureUpload).toBe(screenRuntime.registries.compressedTextureUpload);
|
|
269
|
+
expect(cacheRuntime.registries.customMaterialShaders).toBe(screenRuntime.registries.customMaterialShaders);
|
|
270
|
+
expect(cacheRuntime.registries.materialRenderers).toBe(screenRuntime.registries.materialRenderers);
|
|
271
|
+
expect(cacheRuntime.registries.meshMaterialRenderers).toBe(screenRuntime.registries.meshMaterialRenderers);
|
|
272
|
+
expect(cacheRuntime.registries.renderEffects).toBe(screenRuntime.registries.renderEffects);
|
|
273
|
+
expect(cacheRuntime.registries.shapeRasterizer).toBe(screenRuntime.registries.shapeRasterizer);
|
|
274
|
+
expect(cacheRuntime.registries.strokeTessellator).toBe(screenRuntime.registries.strokeTessellator);
|
|
275
|
+
expect(cacheRuntime.registries.textureResolvers).toBe(screenRuntime.registries.textureResolvers);
|
|
276
|
+
expect(cacheRuntime.registries.velocityWriters).toBe(screenRuntime.registries.velocityWriters);
|
|
277
|
+
expect(getWgpuMaterialRenderer(cacheState, 'acme.Material')).toBe(first);
|
|
278
|
+
|
|
279
|
+
registerWgpuMaterialRenderer(screen, 'acme.Material', replacement);
|
|
280
|
+
|
|
281
|
+
expect(getWgpuMaterialRenderer(screen, 'acme.Material')).toBe(replacement);
|
|
282
|
+
expect(getWgpuMaterialRenderer(cacheState, 'acme.Material')).toBe(first);
|
|
139
283
|
});
|
|
140
284
|
});
|
|
141
285
|
|
|
@@ -177,7 +321,10 @@ describe('enableWgpuRenderCache', () => {
|
|
|
177
321
|
it('registers the renderer for the render cache kind', () => {
|
|
178
322
|
const state = fakeScreen();
|
|
179
323
|
enableWgpuRenderCache(state);
|
|
180
|
-
expect(getWgpuRenderStateRuntime(state).
|
|
324
|
+
expect(getWgpuRenderStateRuntime(state).registries.renderers.entries.get(RenderCacheKind)).toEqual({
|
|
325
|
+
state: 'bound',
|
|
326
|
+
value: defaultWgpuRenderCacheRenderer,
|
|
327
|
+
});
|
|
181
328
|
});
|
|
182
329
|
});
|
|
183
330
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { renderWgpuBackground, submitWgpuRenderPass } from '@flighthq/render-wgpu/contract';
|
|
2
|
-
import { getWgpuRenderStateRuntime } from '@flighthq/render-wgpu/contract';
|
|
2
|
+
import { getWgpuColorAdjustmentMaterialFeature, getWgpuRenderStateRuntime } from '@flighthq/render-wgpu/contract';
|
|
3
3
|
import { createWgpuRenderStateForTest, installWgpuMock } from '@flighthq/render-wgpu/contract';
|
|
4
4
|
import { areColorAdjustmentsEnabled } from '@flighthq/render/contract';
|
|
5
5
|
import type { ColorScaleBias } from '@flighthq/types/contract';
|
|
@@ -51,18 +51,19 @@ describe('registerWgpuColorAdjustmentMaterialFeature', () => {
|
|
|
51
51
|
const runtime = getWgpuRenderStateRuntime(state);
|
|
52
52
|
registerWgpuColorAdjustmentMaterialFeature(state);
|
|
53
53
|
expect(areColorAdjustmentsEnabled(state)).toBe(true);
|
|
54
|
-
expect(runtime.
|
|
55
|
-
expect(
|
|
56
|
-
expect(runtime.wgpuColorAdjustmentMaterialFeature?.drawShapeMeshes).toBeTypeOf('function');
|
|
54
|
+
expect(runtime.registries.colorAdjustmentFeature).toBeDefined();
|
|
55
|
+
expect(getWgpuColorAdjustmentMaterialFeature(state)?.drawShapeMeshes).toBeTypeOf('function');
|
|
57
56
|
});
|
|
58
57
|
|
|
59
58
|
it('is idempotent', async () => {
|
|
60
59
|
const state = await createWgpuRenderStateForTest();
|
|
61
60
|
const runtime = getWgpuRenderStateRuntime(state);
|
|
62
61
|
registerWgpuColorAdjustmentMaterialFeature(state);
|
|
63
|
-
const
|
|
62
|
+
const table = runtime.registries.colorAdjustmentFeature;
|
|
63
|
+
const fold = getWgpuColorAdjustmentMaterialFeature(state);
|
|
64
64
|
registerWgpuColorAdjustmentMaterialFeature(state);
|
|
65
|
-
expect(runtime.
|
|
65
|
+
expect(runtime.registries.colorAdjustmentFeature).toBe(table);
|
|
66
|
+
expect(getWgpuColorAdjustmentMaterialFeature(state)).toBe(fold);
|
|
66
67
|
});
|
|
67
68
|
|
|
68
69
|
it('stays untinted (mode NONE) when no instance carries a color adjustment', async () => {
|
|
@@ -9,7 +9,7 @@ import { createWgpuRenderStateForTest, installWgpuMock } from '@flighthq/render-
|
|
|
9
9
|
import { getRenderProxy2D, prepareScene2DRender } from '@flighthq/render/contract';
|
|
10
10
|
import { createTexture } from '@flighthq/texture/contract';
|
|
11
11
|
import type { CompressedImage, RenderProxy2D } from '@flighthq/types/contract';
|
|
12
|
-
import { CompressedImageTextureSourceKind } from '@flighthq/types/contract';
|
|
12
|
+
import { CompressedImageTextureSourceKind, RegistryEntryState } from '@flighthq/types/contract';
|
|
13
13
|
|
|
14
14
|
import { defaultWgpuParticleEmitter2DRenderer, drawWgpuParticleEmitter2D } from './wgpuParticleEmitter2D';
|
|
15
15
|
|
|
@@ -53,19 +53,25 @@ describe('drawWgpuParticleEmitter2D', () => {
|
|
|
53
53
|
version: 1,
|
|
54
54
|
width: 4,
|
|
55
55
|
} as unknown as CompressedImage;
|
|
56
|
-
runtime.compressedTextureUpload =
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
56
|
+
runtime.registries.compressedTextureUpload = {
|
|
57
|
+
...runtime.registries.compressedTextureUpload,
|
|
58
|
+
entry: {
|
|
59
|
+
state: RegistryEntryState.Bound,
|
|
60
|
+
value: () => {
|
|
61
|
+
const texture = state.device.createTexture({
|
|
62
|
+
size: [4, 4],
|
|
63
|
+
format: 'bc3-rgba-unorm',
|
|
64
|
+
usage: GPUTextureUsage.TEXTURE_BINDING,
|
|
65
|
+
});
|
|
66
|
+
const view = texture.createView();
|
|
67
|
+
return {
|
|
68
|
+
bindGroup: state.device.createBindGroup({ layout: runtime.textureBindGroupLayout, entries: [] }),
|
|
69
|
+
straightAlpha: true,
|
|
70
|
+
texture,
|
|
71
|
+
view,
|
|
72
|
+
};
|
|
73
|
+
},
|
|
74
|
+
},
|
|
69
75
|
};
|
|
70
76
|
const renderProxy = {
|
|
71
77
|
alpha: 1,
|
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
createWgpuRenderStateForTest,
|
|
3
|
+
getWgpuRenderStateRuntime,
|
|
4
|
+
installWgpuMock,
|
|
5
|
+
} from '@flighthq/render-wgpu/contract';
|
|
2
6
|
import { createRenderState, enableRenderRegistryGuards, explainRenderRegistryMisses } from '@flighthq/render/contract';
|
|
3
7
|
import { RenderRegistry } from '@flighthq/types/contract';
|
|
4
8
|
|
|
@@ -19,18 +23,24 @@ describe('registerWgpuShapeRasterizer', () => {
|
|
|
19
23
|
it('installs the rasterizer the shape path draws non-solid fills through', async () => {
|
|
20
24
|
const state = await createWgpuRenderStateForTest();
|
|
21
25
|
const rasterizer = (): void => {};
|
|
26
|
+
const before = getWgpuRenderStateRuntime(state).registries.shapeRasterizer;
|
|
22
27
|
|
|
23
28
|
registerWgpuShapeRasterizer(state, rasterizer);
|
|
24
29
|
|
|
25
30
|
expect(getWgpuShapeRasterizer(state)).toBe(rasterizer);
|
|
31
|
+
expect(getWgpuRenderStateRuntime(state).registries.shapeRasterizer).not.toBe(before);
|
|
32
|
+
expect(before.entry).toBeNull();
|
|
26
33
|
});
|
|
27
34
|
|
|
28
35
|
it('removes one again, so a state can drop back to tessellation only', async () => {
|
|
29
36
|
const state = await createWgpuRenderStateForTest();
|
|
30
37
|
registerWgpuShapeRasterizer(state, (): void => {});
|
|
38
|
+
const before = getWgpuRenderStateRuntime(state).registries.shapeRasterizer;
|
|
31
39
|
|
|
32
40
|
registerWgpuShapeRasterizer(state, null);
|
|
33
41
|
|
|
34
42
|
expect(getWgpuShapeRasterizer(state)).toBeNull();
|
|
43
|
+
expect(getWgpuRenderStateRuntime(state).registries.shapeRasterizer).not.toBe(before);
|
|
44
|
+
expect(before.entry?.state).toBe('bound');
|
|
35
45
|
});
|
|
36
46
|
});
|
|
@@ -24,14 +24,14 @@ beforeAll(async () => {
|
|
|
24
24
|
const actual = (await importOriginal()) as Record<string, unknown>;
|
|
25
25
|
return {
|
|
26
26
|
...actual,
|
|
27
|
-
computeTextLayout: vi.fn((result: { groups: object[] }) => {
|
|
27
|
+
computeTextLayout: vi.fn((result: { groups: object[] }, params: { formatRanges: Array<{ format: object }> }) => {
|
|
28
28
|
result.groups.push({
|
|
29
29
|
offsetX: 0,
|
|
30
30
|
offsetY: 0,
|
|
31
31
|
width: 50,
|
|
32
32
|
ascent: 12,
|
|
33
33
|
descent: 4,
|
|
34
|
-
format: {},
|
|
34
|
+
format: params.formatRanges[0]?.format ?? {},
|
|
35
35
|
startIndex: 0,
|
|
36
36
|
endIndex: 5,
|
|
37
37
|
});
|
|
@@ -107,6 +107,22 @@ describe('drawWgpuTextLabel', () => {
|
|
|
107
107
|
submitWgpuRenderPass(state);
|
|
108
108
|
});
|
|
109
109
|
|
|
110
|
+
it('rasterizes packed run alpha into the canvas color', async () => {
|
|
111
|
+
const state = await createWgpuRenderStateForTest();
|
|
112
|
+
renderWgpuBackground(state);
|
|
113
|
+
registerWgpuStandardMaterial(state);
|
|
114
|
+
const data = makeTextData();
|
|
115
|
+
const proxy = makeTextProxy('hello', data);
|
|
116
|
+
(proxy.source as ReturnType<typeof createTextLabel>).data.textFormat = { color: 0xff000080 };
|
|
117
|
+
const styles: Array<string | CanvasGradient | CanvasPattern> = [];
|
|
118
|
+
vi.spyOn(data.ctx, 'fillText').mockImplementation(() => styles.push(data.ctx.fillStyle));
|
|
119
|
+
|
|
120
|
+
drawWgpuTextLabel(state, proxy);
|
|
121
|
+
|
|
122
|
+
expect(styles).toEqual(['rgba(255, 0, 0, 0.5019607843137255)']);
|
|
123
|
+
submitWgpuRenderPass(state);
|
|
124
|
+
});
|
|
125
|
+
|
|
110
126
|
it('does not re-rasterize when only alpha changes (content version unchanged)', async () => {
|
|
111
127
|
const state = await createWgpuRenderStateForTest();
|
|
112
128
|
renderWgpuBackground(state);
|
package/src/wgpuVelocity.test.ts
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import { createParticleEmitter2D, reserveParticleEmitter2D } from '@flighthq/particleemitter/contract';
|
|
2
2
|
import { createQuadBatch, getQuadBatchRuntime } from '@flighthq/quadbatch/contract';
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
createWgpuOffscreenRenderState,
|
|
5
|
+
getWgpuRenderStateRuntime,
|
|
6
|
+
renderWgpuBackground,
|
|
7
|
+
} from '@flighthq/render-wgpu/contract';
|
|
4
8
|
import { createWgpuRenderStateForTest, installWgpuMock } from '@flighthq/render-wgpu/contract';
|
|
5
9
|
import { createDisplayObject } from '@flighthq/scene2d/contract';
|
|
6
10
|
import type { QuadBatchRuntime, TextureAtlas, TextureAtlasRegion } from '@flighthq/types/contract';
|
|
@@ -119,6 +123,24 @@ describe('registerWgpuVelocityWriter', () => {
|
|
|
119
123
|
registerWgpuVelocityWriter(state, root.kind, defaultWgpuNode2DVelocityWriter);
|
|
120
124
|
expect(getWgpuVelocityWriter(state, root.kind)).toBe(defaultWgpuNode2DVelocityWriter);
|
|
121
125
|
});
|
|
126
|
+
|
|
127
|
+
it('replaces persistent snapshots and preserves a derived pipeline snapshot', async () => {
|
|
128
|
+
const state = await createWgpuRenderStateForTest();
|
|
129
|
+
const kind = 'acme.Velocity';
|
|
130
|
+
const replacement = vi.fn();
|
|
131
|
+
const before = getWgpuRenderStateRuntime(state).registries.velocityWriters;
|
|
132
|
+
|
|
133
|
+
registerWgpuVelocityWriter(state, kind, defaultWgpuNode2DVelocityWriter);
|
|
134
|
+
const registered = getWgpuRenderStateRuntime(state).registries.velocityWriters;
|
|
135
|
+
const offscreen = createWgpuOffscreenRenderState(state);
|
|
136
|
+
registerWgpuVelocityWriter(state, kind, replacement);
|
|
137
|
+
|
|
138
|
+
expect(registered).not.toBe(before);
|
|
139
|
+
expect(before.entries.has(kind)).toBe(false);
|
|
140
|
+
expect(registered.entries.get(kind)).toEqual({ state: 'bound', value: defaultWgpuNode2DVelocityWriter });
|
|
141
|
+
expect(getWgpuVelocityWriter(state, kind)).toBe(replacement);
|
|
142
|
+
expect(getWgpuVelocityWriter(offscreen, kind)).toBe(defaultWgpuNode2DVelocityWriter);
|
|
143
|
+
});
|
|
122
144
|
});
|
|
123
145
|
|
|
124
146
|
describe('renderWgpuVelocity', () => {
|