@flighthq/scene2d-wgpu 0.3.0-next.906.07cea63 → 0.3.0
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/contract.d.ts +8 -6
- package/dist/contract.d.ts.map +1 -1
- package/dist/contract.js +8 -6
- package/dist/contract.js.map +1 -1
- package/dist/enableWgpuColorAdjustmentGuards.js +2 -2
- package/dist/enableWgpuColorAdjustmentGuards.js.map +1 -1
- package/dist/enableWgpuStrokePathTessellation.d.ts +3 -0
- package/dist/enableWgpuStrokePathTessellation.d.ts.map +1 -0
- package/dist/enableWgpuStrokePathTessellation.js +8 -0
- package/dist/enableWgpuStrokePathTessellation.js.map +1 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/wgpuBitmapText.d.ts.map +1 -1
- package/dist/wgpuBitmapText.js +20 -16
- package/dist/wgpuBitmapText.js.map +1 -1
- package/dist/wgpuCache.d.ts.map +1 -1
- package/dist/wgpuCache.js +19 -16
- package/dist/wgpuCache.js.map +1 -1
- package/dist/wgpuClipContours.js +3 -3
- package/dist/wgpuClipContours.js.map +1 -1
- package/dist/wgpuClipRectangle.js +3 -3
- package/dist/wgpuClipRectangle.js.map +1 -1
- package/dist/wgpuColorAdjustmentMaterialFeature.d.ts.map +1 -1
- package/dist/wgpuColorAdjustmentMaterialFeature.js +156 -67
- package/dist/wgpuColorAdjustmentMaterialFeature.js.map +1 -1
- package/dist/wgpuMeshShapeRenderer.d.ts +4 -0
- package/dist/wgpuMeshShapeRenderer.d.ts.map +1 -0
- package/dist/wgpuMeshShapeRenderer.js +92 -0
- package/dist/wgpuMeshShapeRenderer.js.map +1 -0
- package/dist/wgpuNode2D.js +2 -2
- package/dist/wgpuNode2D.js.map +1 -1
- package/dist/wgpuParticleEmitter2D.d.ts.map +1 -1
- package/dist/wgpuParticleEmitter2D.js +26 -10
- package/dist/wgpuParticleEmitter2D.js.map +1 -1
- package/dist/wgpuQuadBatch.d.ts +1 -1
- package/dist/wgpuQuadBatch.d.ts.map +1 -1
- package/dist/wgpuQuadBatch.js +18 -13
- package/dist/wgpuQuadBatch.js.map +1 -1
- package/dist/wgpuQuadBatchWriter.d.ts +12 -0
- package/dist/wgpuQuadBatchWriter.d.ts.map +1 -0
- package/dist/{wgpuSpriteBatch.js → wgpuQuadBatchWriter.js} +97 -72
- package/dist/wgpuQuadBatchWriter.js.map +1 -0
- package/dist/wgpuRasterShapeRenderer.d.ts +4 -0
- package/dist/wgpuRasterShapeRenderer.d.ts.map +1 -0
- package/dist/wgpuRasterShapeRenderer.js +110 -0
- package/dist/wgpuRasterShapeRenderer.js.map +1 -0
- package/dist/wgpuRichText.d.ts.map +1 -1
- package/dist/wgpuRichText.js +7 -4
- package/dist/wgpuRichText.js.map +1 -1
- package/dist/wgpuScale9Shape.d.ts +1 -3
- package/dist/wgpuScale9Shape.d.ts.map +1 -1
- package/dist/wgpuScale9Shape.js +36 -33
- package/dist/wgpuScale9Shape.js.map +1 -1
- package/dist/wgpuShape.d.ts +2 -1
- package/dist/wgpuShape.d.ts.map +1 -1
- package/dist/wgpuShape.js +19 -153
- package/dist/wgpuShape.js.map +1 -1
- package/dist/wgpuShapeData.d.ts +6 -0
- package/dist/wgpuShapeData.d.ts.map +1 -0
- package/dist/wgpuShapeData.js +81 -0
- package/dist/wgpuShapeData.js.map +1 -0
- package/dist/wgpuShapeMesh.d.ts +2 -1
- package/dist/wgpuShapeMesh.d.ts.map +1 -1
- package/dist/wgpuShapeMesh.js +74 -62
- package/dist/wgpuShapeMesh.js.map +1 -1
- package/dist/wgpuShapeRasterizer.d.ts +4 -0
- package/dist/wgpuShapeRasterizer.d.ts.map +1 -0
- package/dist/wgpuShapeRasterizer.js +11 -0
- package/dist/wgpuShapeRasterizer.js.map +1 -0
- package/dist/wgpuSprite.d.ts +3 -2
- package/dist/wgpuSprite.d.ts.map +1 -1
- package/dist/wgpuSprite.js +67 -25
- package/dist/wgpuSprite.js.map +1 -1
- package/dist/wgpuStandardMaterial.d.ts +1 -1
- package/dist/wgpuStandardMaterial.js +3 -3
- package/dist/wgpuStandardMaterial.js.map +1 -1
- package/dist/wgpuTextLabel.d.ts.map +1 -1
- package/dist/wgpuTextLabel.js +15 -12
- package/dist/wgpuTextLabel.js.map +1 -1
- package/dist/wgpuTilemap.d.ts.map +1 -1
- package/dist/wgpuTilemap.js +19 -18
- package/dist/wgpuTilemap.js.map +1 -1
- package/package.json +22 -18
- package/src/enableWgpuColorAdjustmentGuards.test.ts +4 -4
- package/src/enableWgpuStrokePathTessellation.test.ts +23 -0
- package/src/wgpuBitmapText.test.ts +2 -2
- package/src/wgpuCache.test.ts +14 -11
- package/src/wgpuColorAdjustmentMaterialFeature.test.ts +52 -46
- package/src/wgpuMeshShapeRenderer.test.ts +167 -0
- package/src/wgpuParticleEmitter2D.test.ts +16 -7
- package/src/wgpuQuadBatch.test.ts +3 -3
- package/src/{wgpuSpriteBatch.test.ts → wgpuQuadBatchWriter.test.ts} +79 -70
- package/src/wgpuRasterShapeRenderer.test.ts +156 -0
- package/src/wgpuScale9Shape.test.ts +0 -13
- package/src/wgpuShape.test.ts +169 -15
- package/src/wgpuShapeData.test.ts +97 -0
- package/src/wgpuShapeMesh.test.ts +170 -15
- package/src/wgpuShapeRasterizer.test.ts +36 -0
- package/src/wgpuSprite.test.ts +45 -10
- package/src/wgpuStandardMaterial.test.ts +3 -3
- package/src/wgpuTextLabel.test.ts +7 -7
- package/src/wgpuTilemap.test.ts +4 -4
- package/src/wgpuVelocity.test.ts +3 -3
- package/dist/wgpuBitmap.d.ts +0 -4
- package/dist/wgpuBitmap.d.ts.map +0 -1
- package/dist/wgpuBitmap.js +0 -84
- package/dist/wgpuBitmap.js.map +0 -1
- package/dist/wgpuRenderTargetNode2D.d.ts +0 -11
- package/dist/wgpuRenderTargetNode2D.d.ts.map +0 -1
- package/dist/wgpuRenderTargetNode2D.js +0 -100
- package/dist/wgpuRenderTargetNode2D.js.map +0 -1
- package/dist/wgpuSpriteBatch.d.ts +0 -12
- package/dist/wgpuSpriteBatch.d.ts.map +0 -1
- package/dist/wgpuSpriteBatch.js.map +0 -1
- package/dist/wgpuSpriteRenderer.d.ts +0 -3
- package/dist/wgpuSpriteRenderer.d.ts.map +0 -1
- package/dist/wgpuSpriteRenderer.js +0 -55
- package/dist/wgpuSpriteRenderer.js.map +0 -1
- package/dist/wgpuVideo.d.ts +0 -6
- package/dist/wgpuVideo.d.ts.map +0 -1
- package/dist/wgpuVideo.js +0 -63
- package/dist/wgpuVideo.js.map +0 -1
- package/src/wgpuBitmap.test.ts +0 -40
- package/src/wgpuRenderTargetNode2D.test.ts +0 -267
- package/src/wgpuSpriteRenderer.test.ts +0 -63
- package/src/wgpuVideo.test.ts +0 -59
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
import type * as FlightNodeModule from '@flighthq/node/contract';
|
|
2
|
+
import { getWgpuRenderStateRuntime } from '@flighthq/render-wgpu/contract';
|
|
3
|
+
import { createWgpuRenderStateForTest, installWgpuMock, renderWgpuBackground } from '@flighthq/render-wgpu/contract';
|
|
4
|
+
import { enableRenderRegistryGuards, explainRenderRegistryMisses } from '@flighthq/render/contract';
|
|
5
|
+
import {
|
|
6
|
+
appendShapeBeginFill,
|
|
7
|
+
appendShapeBeginGradientFill,
|
|
8
|
+
appendShapeEndFill,
|
|
9
|
+
appendShapeRectangle,
|
|
10
|
+
createShape,
|
|
11
|
+
} from '@flighthq/shape/contract';
|
|
12
|
+
import type { RenderProxy2D } from '@flighthq/types/contract';
|
|
13
|
+
import { BatchFormat, RenderRegistry } from '@flighthq/types/contract';
|
|
14
|
+
|
|
15
|
+
import { scopeModuleMocks } from './moduleMockTestHelper';
|
|
16
|
+
import type * as WgpuMeshShapeModule from './wgpuMeshShapeRenderer';
|
|
17
|
+
import { registerWgpuShapeRasterizer } from './wgpuShapeRasterizer';
|
|
18
|
+
|
|
19
|
+
let defaultWgpuMeshShapeRenderer: typeof WgpuMeshShapeModule.defaultWgpuMeshShapeRenderer;
|
|
20
|
+
let drawWgpuMeshShape: typeof WgpuMeshShapeModule.drawWgpuMeshShape;
|
|
21
|
+
|
|
22
|
+
scopeModuleMocks(['@flighthq/node']);
|
|
23
|
+
|
|
24
|
+
beforeAll(async () => {
|
|
25
|
+
vi.doMock('@flighthq/node/contract', async (importOriginal) => ({
|
|
26
|
+
...(await importOriginal<typeof FlightNodeModule>()),
|
|
27
|
+
getNodeLocalBoundsRectangle: () => ({ x: 0, y: 0, width: 64, height: 48 }),
|
|
28
|
+
getNodeLocalContentRevision: (source: any) => source?.data?.version ?? 0,
|
|
29
|
+
}));
|
|
30
|
+
({ defaultWgpuMeshShapeRenderer, drawWgpuMeshShape } = await import('./wgpuMeshShapeRenderer'));
|
|
31
|
+
installWgpuMock();
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
function makeShapeData() {
|
|
35
|
+
return {
|
|
36
|
+
surface: null,
|
|
37
|
+
lastContentId: -1,
|
|
38
|
+
lastPixelRatio: 0,
|
|
39
|
+
lastW: 0,
|
|
40
|
+
lastH: 0,
|
|
41
|
+
meshVersion: -1,
|
|
42
|
+
meshes: null,
|
|
43
|
+
meshBuffers: {
|
|
44
|
+
vertexBuffers: [],
|
|
45
|
+
vertexCapacities: [],
|
|
46
|
+
indexBuffers: [],
|
|
47
|
+
indexCapacities: [],
|
|
48
|
+
uniformBuffers: [],
|
|
49
|
+
bindGroups: [],
|
|
50
|
+
colorScaleBiasUniformBuffers: [],
|
|
51
|
+
colorScaleBiasBindGroups: [],
|
|
52
|
+
},
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function makeShapeProxy(data: Record<string, unknown>, rendererData: unknown = makeShapeData()): RenderProxy2D {
|
|
57
|
+
return {
|
|
58
|
+
source: { data: { commands: [], version: 0, ...data } },
|
|
59
|
+
blendMode: 0,
|
|
60
|
+
alpha: 1,
|
|
61
|
+
material: null,
|
|
62
|
+
materialData: null,
|
|
63
|
+
transform2D: { a: 1, b: 0, c: 0, d: 1, tx: 0, ty: 0 },
|
|
64
|
+
rendererData,
|
|
65
|
+
} as unknown as RenderProxy2D;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function makeMeshPassSpy(): GPURenderPassEncoder {
|
|
69
|
+
return {
|
|
70
|
+
setPipeline: vi.fn(),
|
|
71
|
+
setBindGroup: vi.fn(),
|
|
72
|
+
setVertexBuffer: vi.fn(),
|
|
73
|
+
setIndexBuffer: vi.fn(),
|
|
74
|
+
setStencilReference: vi.fn(),
|
|
75
|
+
draw: vi.fn(),
|
|
76
|
+
drawIndexed: vi.fn(),
|
|
77
|
+
end: vi.fn(),
|
|
78
|
+
} as unknown as GPURenderPassEncoder;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function gradientShape() {
|
|
82
|
+
const shape = createShape();
|
|
83
|
+
appendShapeBeginGradientFill(shape, 'linear', [0xff0000, 0x0000ff], [1, 1], [0, 255], null);
|
|
84
|
+
appendShapeRectangle(shape, 8, 8, 32, 24);
|
|
85
|
+
appendShapeEndFill(shape);
|
|
86
|
+
return shape;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
describe('defaultWgpuMeshShapeRenderer', () => {
|
|
90
|
+
it('declares BatchFormat.Quad and the shared shape data lifecycle', () => {
|
|
91
|
+
expect(defaultWgpuMeshShapeRenderer.format).toBe(BatchFormat.Quad);
|
|
92
|
+
expect(typeof defaultWgpuMeshShapeRenderer.createData).toBe('function');
|
|
93
|
+
expect(typeof defaultWgpuMeshShapeRenderer.destroyData).toBe('function');
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
it('never rasterizes, even with a rasterizer registered and a fill that cannot tessellate', async () => {
|
|
97
|
+
const state = await createWgpuRenderStateForTest();
|
|
98
|
+
renderWgpuBackground(state);
|
|
99
|
+
getWgpuRenderStateRuntime(state).renderPass = makeMeshPassSpy();
|
|
100
|
+
const rasterizer = vi.fn();
|
|
101
|
+
registerWgpuShapeRasterizer(state, rasterizer);
|
|
102
|
+
|
|
103
|
+
defaultWgpuMeshShapeRenderer.submit!(
|
|
104
|
+
state,
|
|
105
|
+
makeShapeProxy({ commands: gradientShape().data.commands, version: 1 }),
|
|
106
|
+
);
|
|
107
|
+
|
|
108
|
+
expect(rasterizer).not.toHaveBeenCalled();
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
it('reports a ShapeRasterizer miss rather than silently dropping an untessellatable fill', async () => {
|
|
112
|
+
const state = await createWgpuRenderStateForTest();
|
|
113
|
+
renderWgpuBackground(state);
|
|
114
|
+
getWgpuRenderStateRuntime(state).renderPass = makeMeshPassSpy();
|
|
115
|
+
enableRenderRegistryGuards(state);
|
|
116
|
+
|
|
117
|
+
defaultWgpuMeshShapeRenderer.submit!(
|
|
118
|
+
state,
|
|
119
|
+
makeShapeProxy({ commands: gradientShape().data.commands, version: 1 }),
|
|
120
|
+
);
|
|
121
|
+
|
|
122
|
+
expect(explainRenderRegistryMisses(state).misses).toContainEqual({
|
|
123
|
+
kind: 'Shape',
|
|
124
|
+
registry: RenderRegistry.ShapeRasterizer,
|
|
125
|
+
});
|
|
126
|
+
});
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
describe('drawWgpuMeshShape', () => {
|
|
130
|
+
it('draws a solid fill as a GPU mesh and reports that it drew', async () => {
|
|
131
|
+
const state = await createWgpuRenderStateForTest();
|
|
132
|
+
renderWgpuBackground(state);
|
|
133
|
+
const pass = makeMeshPassSpy();
|
|
134
|
+
getWgpuRenderStateRuntime(state).renderPass = pass;
|
|
135
|
+
const shape = createShape();
|
|
136
|
+
appendShapeBeginFill(shape, 0x00cc00);
|
|
137
|
+
appendShapeRectangle(shape, 8, 8, 32, 24);
|
|
138
|
+
appendShapeEndFill(shape);
|
|
139
|
+
|
|
140
|
+
expect(drawWgpuMeshShape(state, makeShapeProxy({ commands: shape.data.commands, version: 1 }))).toBe(true);
|
|
141
|
+
expect(pass.drawIndexed).toHaveBeenCalled();
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
it('reports false for a fill with no tessellated form, which is the hybrid fall-through signal', async () => {
|
|
145
|
+
const state = await createWgpuRenderStateForTest();
|
|
146
|
+
renderWgpuBackground(state);
|
|
147
|
+
getWgpuRenderStateRuntime(state).renderPass = makeMeshPassSpy();
|
|
148
|
+
expect(drawWgpuMeshShape(state, makeShapeProxy({ commands: gradientShape().data.commands, version: 1 }))).toBe(
|
|
149
|
+
false,
|
|
150
|
+
);
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
it('reports false with no render pass, an empty command list, or absent renderer data', async () => {
|
|
154
|
+
const state = await createWgpuRenderStateForTest();
|
|
155
|
+
renderWgpuBackground(state);
|
|
156
|
+
const shape = createShape();
|
|
157
|
+
appendShapeBeginFill(shape, 0x00cc00);
|
|
158
|
+
appendShapeRectangle(shape, 8, 8, 32, 24);
|
|
159
|
+
appendShapeEndFill(shape);
|
|
160
|
+
|
|
161
|
+
getWgpuRenderStateRuntime(state).renderPass = null;
|
|
162
|
+
expect(drawWgpuMeshShape(state, makeShapeProxy({ commands: shape.data.commands, version: 1 }))).toBe(false);
|
|
163
|
+
getWgpuRenderStateRuntime(state).renderPass = makeMeshPassSpy();
|
|
164
|
+
expect(drawWgpuMeshShape(state, makeShapeProxy({ commands: [], version: 1 }))).toBe(false);
|
|
165
|
+
expect(drawWgpuMeshShape(state, makeShapeProxy({ commands: shape.data.commands, version: 1 }, null))).toBe(false);
|
|
166
|
+
});
|
|
167
|
+
});
|
|
@@ -1,8 +1,15 @@
|
|
|
1
1
|
import { createParticleEmitter2D } from '@flighthq/particleemitter/contract';
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
getWgpuRenderStateRuntime,
|
|
4
|
+
registerWgpuCompressedImageTextureResolver,
|
|
5
|
+
renderWgpuBackground,
|
|
6
|
+
submitWgpuRenderPass,
|
|
7
|
+
} from '@flighthq/render-wgpu/contract';
|
|
3
8
|
import { createWgpuRenderStateForTest, installWgpuMock } from '@flighthq/render-wgpu/contract';
|
|
4
9
|
import { getRenderProxy2D, prepareScene2DRender } from '@flighthq/render/contract';
|
|
5
|
-
import
|
|
10
|
+
import { createTexture } from '@flighthq/texture/contract';
|
|
11
|
+
import type { CompressedImage, RenderProxy2D } from '@flighthq/types/contract';
|
|
12
|
+
import { CompressedImageTextureSourceKind } from '@flighthq/types/contract';
|
|
6
13
|
|
|
7
14
|
import { defaultWgpuParticleEmitter2DRenderer, drawWgpuParticleEmitter2D } from './wgpuParticleEmitter2D';
|
|
8
15
|
|
|
@@ -36,17 +43,16 @@ describe('drawWgpuParticleEmitter2D', () => {
|
|
|
36
43
|
it('threads a native compressed atlas straight-alpha flag through the particle uniform', async () => {
|
|
37
44
|
const state = await createWgpuRenderStateForTest();
|
|
38
45
|
const runtime = getWgpuRenderStateRuntime(state);
|
|
46
|
+
registerWgpuCompressedImageTextureResolver(state);
|
|
39
47
|
renderWgpuBackground(state);
|
|
40
48
|
const before = runtime.uniformOffset;
|
|
41
49
|
const image = {
|
|
42
|
-
alphaType: 'straight',
|
|
43
50
|
compressed: { container: {}, payload: new Uint8Array() },
|
|
44
|
-
data: null,
|
|
45
51
|
height: 4,
|
|
46
|
-
|
|
52
|
+
kind: CompressedImageTextureSourceKind,
|
|
47
53
|
version: 1,
|
|
48
54
|
width: 4,
|
|
49
|
-
} as unknown as
|
|
55
|
+
} as unknown as CompressedImage;
|
|
50
56
|
runtime.compressedTextureUpload = () => {
|
|
51
57
|
const texture = state.device.createTexture({
|
|
52
58
|
size: [4, 4],
|
|
@@ -67,7 +73,10 @@ describe('drawWgpuParticleEmitter2D', () => {
|
|
|
67
73
|
source: {
|
|
68
74
|
data: {
|
|
69
75
|
alphas: new Float32Array([1]),
|
|
70
|
-
atlas: {
|
|
76
|
+
atlas: {
|
|
77
|
+
regions: [{ height: 4, width: 4, x: 0, y: 0 }],
|
|
78
|
+
texture: createTexture({ dimension: '2d', source: image }),
|
|
79
|
+
},
|
|
71
80
|
colors: new Float32Array([1, 1, 1]),
|
|
72
81
|
ids: new Uint16Array([0]),
|
|
73
82
|
particleCount: 1,
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
+
import { createQuadBatch } from '@flighthq/quadbatch/contract';
|
|
1
2
|
import { renderWgpuBackground, submitWgpuRenderPass } from '@flighthq/render-wgpu/contract';
|
|
2
3
|
import { createWgpuRenderStateForTest, installWgpuMock } from '@flighthq/render-wgpu/contract';
|
|
3
4
|
import { getRenderProxy2D, prepareScene2DRender } from '@flighthq/render/contract';
|
|
4
|
-
import { createQuadBatch } from '@flighthq/sprite/contract';
|
|
5
5
|
|
|
6
6
|
import { defaultWgpuQuadBatchRenderer, ensureWgpuQuadBatchResources, getWgpuQuadBatchPipeline } from './wgpuQuadBatch';
|
|
7
|
-
import {
|
|
7
|
+
import { flushWgpuQuadBatchWriter } from './wgpuQuadBatchWriter';
|
|
8
8
|
|
|
9
9
|
beforeAll(() => {
|
|
10
10
|
installWgpuMock();
|
|
@@ -31,7 +31,7 @@ describe('defaultWgpuQuadBatchRenderer.submit', () => {
|
|
|
31
31
|
|
|
32
32
|
expect(() => {
|
|
33
33
|
defaultWgpuQuadBatchRenderer.submit(state, renderProxy);
|
|
34
|
-
|
|
34
|
+
flushWgpuQuadBatchWriter(state as any);
|
|
35
35
|
}).not.toThrow();
|
|
36
36
|
submitWgpuRenderPass(state);
|
|
37
37
|
});
|
|
@@ -1,21 +1,20 @@
|
|
|
1
|
-
import { createImageResource } from '@flighthq/image/contract';
|
|
2
1
|
import { renderWgpuBackground, submitWgpuRenderPass } from '@flighthq/render-wgpu/contract';
|
|
3
2
|
import { getWgpuRenderStateRuntime } from '@flighthq/render-wgpu/contract';
|
|
4
3
|
import { createWgpuRenderStateForTest, installWgpuMock } from '@flighthq/render-wgpu/contract';
|
|
5
|
-
import type { ColorScaleBias, Material } from '@flighthq/types/contract';
|
|
4
|
+
import type { ColorScaleBias, Material, WgpuTextureEntry } from '@flighthq/types/contract';
|
|
6
5
|
import { BlendMode } from '@flighthq/types/contract';
|
|
7
6
|
|
|
8
7
|
import { registerWgpuColorAdjustmentMaterialFeature } from './wgpuColorAdjustmentMaterialFeature';
|
|
9
8
|
import {
|
|
10
9
|
ensureWgpuQuadBatchResources,
|
|
11
|
-
|
|
10
|
+
flushWgpuQuadBatchWriter,
|
|
12
11
|
getWgpuQuadBatchPipeline,
|
|
13
12
|
getWgpuQuadBatchPreludeWGSL,
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
} from './
|
|
13
|
+
packWgpuQuadBatchMaterialInstance,
|
|
14
|
+
prepareWgpuQuadBatchWrite,
|
|
15
|
+
recordWgpuQuadBatchColorScaleBias,
|
|
16
|
+
resetWgpuQuadBatchWriterBufferPool,
|
|
17
|
+
} from './wgpuQuadBatchWriter';
|
|
19
18
|
import { standardWgpuMaterialRenderer } from './wgpuStandardMaterial';
|
|
20
19
|
|
|
21
20
|
beforeAll(() => {
|
|
@@ -26,6 +25,14 @@ function makeMaterial(): Material {
|
|
|
26
25
|
return { kind: 'TestMaterial' } as Material;
|
|
27
26
|
}
|
|
28
27
|
|
|
28
|
+
function makeTexture(): WgpuTextureEntry {
|
|
29
|
+
return {
|
|
30
|
+
bindGroup: {} as GPUBindGroup,
|
|
31
|
+
texture: {} as GPUTexture,
|
|
32
|
+
view: {} as GPUTextureView,
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
|
|
29
36
|
function ct(
|
|
30
37
|
redScale = 1,
|
|
31
38
|
greenScale = 1,
|
|
@@ -70,11 +77,11 @@ describe('ensureWgpuQuadBatchResources', () => {
|
|
|
70
77
|
});
|
|
71
78
|
});
|
|
72
79
|
|
|
73
|
-
describe('
|
|
80
|
+
describe('flushWgpuQuadBatchWriter', () => {
|
|
74
81
|
it('does nothing when batch count is zero', async () => {
|
|
75
82
|
const state = await createWgpuRenderStateForTest();
|
|
76
83
|
renderWgpuBackground(state);
|
|
77
|
-
expect(() =>
|
|
84
|
+
expect(() => flushWgpuQuadBatchWriter(state)).not.toThrow();
|
|
78
85
|
submitWgpuRenderPass(state);
|
|
79
86
|
});
|
|
80
87
|
|
|
@@ -82,16 +89,16 @@ describe('flushWgpuSpriteBatch', () => {
|
|
|
82
89
|
const state = await createWgpuRenderStateForTest();
|
|
83
90
|
renderWgpuBackground(state);
|
|
84
91
|
const runtime = getWgpuRenderStateRuntime(state);
|
|
85
|
-
const tex =
|
|
92
|
+
const tex = makeTexture();
|
|
86
93
|
|
|
87
|
-
|
|
88
|
-
runtime.
|
|
89
|
-
|
|
94
|
+
prepareWgpuQuadBatchWrite(state, tex, null, null, null, standardWgpuMaterialRenderer, 1);
|
|
95
|
+
runtime.quadBatchWriterCount = 1;
|
|
96
|
+
flushWgpuQuadBatchWriter(state);
|
|
90
97
|
|
|
91
|
-
expect(runtime.
|
|
92
|
-
expect(runtime.
|
|
93
|
-
expect(runtime.
|
|
94
|
-
expect(runtime.
|
|
98
|
+
expect(runtime.quadBatchWriterCount).toBe(0);
|
|
99
|
+
expect(runtime.quadBatchWriterTexture).toBeNull();
|
|
100
|
+
expect(runtime.quadBatchWriterBlendMode).toBeNull();
|
|
101
|
+
expect(runtime.quadBatchWriterMaterial).toBeNull();
|
|
95
102
|
submitWgpuRenderPass(state);
|
|
96
103
|
});
|
|
97
104
|
|
|
@@ -101,20 +108,22 @@ describe('flushWgpuSpriteBatch', () => {
|
|
|
101
108
|
const state = await createWgpuRenderStateForTest();
|
|
102
109
|
renderWgpuBackground(state);
|
|
103
110
|
const runtime = getWgpuRenderStateRuntime(state);
|
|
104
|
-
const tex1 =
|
|
105
|
-
const tex2 =
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
runtime.
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
runtime.
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
expect(runtime.
|
|
116
|
-
expect(runtime.
|
|
117
|
-
expect(runtime.
|
|
111
|
+
const tex1 = makeTexture();
|
|
112
|
+
const tex2 = makeTexture();
|
|
113
|
+
|
|
114
|
+
prepareWgpuQuadBatchWrite(state, tex1, null, null, null, standardWgpuMaterialRenderer, 1);
|
|
115
|
+
runtime.quadBatchWriterCount = 1;
|
|
116
|
+
flushWgpuQuadBatchWriter(state);
|
|
117
|
+
|
|
118
|
+
prepareWgpuQuadBatchWrite(state, tex2, null, null, null, standardWgpuMaterialRenderer, 1);
|
|
119
|
+
runtime.quadBatchWriterCount = 1;
|
|
120
|
+
flushWgpuQuadBatchWriter(state);
|
|
121
|
+
|
|
122
|
+
expect(runtime.quadBatchWriterBufferCursor).toBe(2);
|
|
123
|
+
expect(runtime.quadBatchWriterBufferPool[0].instanceBuffer).not.toBeNull();
|
|
124
|
+
expect(runtime.quadBatchWriterBufferPool[0].instanceBuffer).not.toBe(
|
|
125
|
+
runtime.quadBatchWriterBufferPool[1].instanceBuffer,
|
|
126
|
+
);
|
|
118
127
|
submitWgpuRenderPass(state);
|
|
119
128
|
});
|
|
120
129
|
});
|
|
@@ -166,19 +175,19 @@ describe('getWgpuQuadBatchPreludeWGSL', () => {
|
|
|
166
175
|
});
|
|
167
176
|
});
|
|
168
177
|
|
|
169
|
-
describe('
|
|
178
|
+
describe('packWgpuQuadBatchMaterialInstance', () => {
|
|
170
179
|
it('is a no-op when no per-instance material data is active', async () => {
|
|
171
180
|
const state = await createWgpuRenderStateForTest();
|
|
172
|
-
expect(() =>
|
|
181
|
+
expect(() => packWgpuQuadBatchMaterialInstance(state, null, 0)).not.toThrow();
|
|
173
182
|
});
|
|
174
183
|
});
|
|
175
184
|
|
|
176
|
-
describe('
|
|
185
|
+
describe('prepareWgpuQuadBatchWrite', () => {
|
|
177
186
|
it('returns float index 0 for an empty batch', async () => {
|
|
178
187
|
const state = await createWgpuRenderStateForTest();
|
|
179
|
-
const tex =
|
|
188
|
+
const tex = makeTexture();
|
|
180
189
|
|
|
181
|
-
const base =
|
|
190
|
+
const base = prepareWgpuQuadBatchWrite(state, tex, null, null, null, standardWgpuMaterialRenderer, 1);
|
|
182
191
|
expect(base).toBe(0);
|
|
183
192
|
});
|
|
184
193
|
|
|
@@ -186,15 +195,15 @@ describe('prepareWgpuSpriteBatchWrite', () => {
|
|
|
186
195
|
const state = await createWgpuRenderStateForTest();
|
|
187
196
|
renderWgpuBackground(state);
|
|
188
197
|
const runtime = getWgpuRenderStateRuntime(state);
|
|
189
|
-
const tex1 =
|
|
190
|
-
const tex2 =
|
|
198
|
+
const tex1 = makeTexture();
|
|
199
|
+
const tex2 = makeTexture();
|
|
191
200
|
|
|
192
|
-
|
|
193
|
-
runtime.
|
|
194
|
-
|
|
201
|
+
prepareWgpuQuadBatchWrite(state, tex1, null, null, null, standardWgpuMaterialRenderer, 1);
|
|
202
|
+
runtime.quadBatchWriterCount = 1;
|
|
203
|
+
prepareWgpuQuadBatchWrite(state, tex2, null, null, null, standardWgpuMaterialRenderer, 1);
|
|
195
204
|
|
|
196
|
-
expect(runtime.
|
|
197
|
-
expect(runtime.
|
|
205
|
+
expect(runtime.quadBatchWriterTexture).toBe(tex2);
|
|
206
|
+
expect(runtime.quadBatchWriterCount).toBe(0);
|
|
198
207
|
submitWgpuRenderPass(state);
|
|
199
208
|
});
|
|
200
209
|
|
|
@@ -202,41 +211,41 @@ describe('prepareWgpuSpriteBatchWrite', () => {
|
|
|
202
211
|
const state = await createWgpuRenderStateForTest();
|
|
203
212
|
renderWgpuBackground(state);
|
|
204
213
|
const runtime = getWgpuRenderStateRuntime(state);
|
|
205
|
-
const tex =
|
|
214
|
+
const tex = makeTexture();
|
|
206
215
|
const materialA = makeMaterial();
|
|
207
216
|
const materialB = makeMaterial();
|
|
208
217
|
|
|
209
|
-
|
|
210
|
-
runtime.
|
|
211
|
-
|
|
218
|
+
prepareWgpuQuadBatchWrite(state, tex, null, null, materialA, standardWgpuMaterialRenderer, 1);
|
|
219
|
+
runtime.quadBatchWriterCount = 1;
|
|
220
|
+
prepareWgpuQuadBatchWrite(state, tex, null, null, materialB, standardWgpuMaterialRenderer, 1);
|
|
212
221
|
|
|
213
|
-
expect(runtime.
|
|
214
|
-
expect(runtime.
|
|
222
|
+
expect(runtime.quadBatchWriterMaterial).toBe(materialB);
|
|
223
|
+
expect(runtime.quadBatchWriterCount).toBe(0);
|
|
215
224
|
submitWgpuRenderPass(state);
|
|
216
225
|
});
|
|
217
226
|
});
|
|
218
227
|
|
|
219
|
-
describe('
|
|
228
|
+
describe('recordWgpuQuadBatchColorScaleBias', () => {
|
|
220
229
|
it('skips the tint and records no fold state when color adjustment is not enabled', async () => {
|
|
221
230
|
const state = await createWgpuRenderStateForTest();
|
|
222
231
|
const runtime = getWgpuRenderStateRuntime(state);
|
|
223
|
-
|
|
224
|
-
expect(runtime.
|
|
232
|
+
recordWgpuQuadBatchColorScaleBias(state, ct(0.5), 0);
|
|
233
|
+
expect(runtime.quadBatchWriterColorScaleBiasMode ?? CT_MODE_NONE).toBe(CT_MODE_NONE);
|
|
225
234
|
});
|
|
226
235
|
|
|
227
236
|
it('is a no-op for an untinted instance whether or not the fold is enabled', async () => {
|
|
228
237
|
const state = await createWgpuRenderStateForTest();
|
|
229
238
|
const runtime = getWgpuRenderStateRuntime(state);
|
|
230
|
-
expect(() =>
|
|
231
|
-
expect(runtime.
|
|
239
|
+
expect(() => recordWgpuQuadBatchColorScaleBias(state, null, 0)).not.toThrow();
|
|
240
|
+
expect(runtime.quadBatchWriterColorScaleBiasMode ?? CT_MODE_NONE).toBe(CT_MODE_NONE);
|
|
232
241
|
});
|
|
233
242
|
|
|
234
243
|
it('delegates to the installed fold when color adjustment is enabled', async () => {
|
|
235
244
|
const state = await createWgpuRenderStateForTest();
|
|
236
245
|
const runtime = getWgpuRenderStateRuntime(state);
|
|
237
246
|
registerWgpuColorAdjustmentMaterialFeature(state);
|
|
238
|
-
|
|
239
|
-
expect(runtime.
|
|
247
|
+
recordWgpuQuadBatchColorScaleBias(state, ct(0.5), 0);
|
|
248
|
+
expect(runtime.quadBatchWriterColorScaleBiasMode).toBe(CT_MODE_UNIFORM);
|
|
240
249
|
});
|
|
241
250
|
|
|
242
251
|
it('an untinted batch on flush uses the lean material module (no fold)', async () => {
|
|
@@ -244,29 +253,29 @@ describe('recordWgpuSpriteBatchColorScaleBias', () => {
|
|
|
244
253
|
registerWgpuColorAdjustmentMaterialFeature(state);
|
|
245
254
|
renderWgpuBackground(state);
|
|
246
255
|
const runtime = getWgpuRenderStateRuntime(state);
|
|
247
|
-
const tex =
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
runtime.
|
|
251
|
-
expect(() =>
|
|
256
|
+
const tex = makeTexture();
|
|
257
|
+
prepareWgpuQuadBatchWrite(state, tex, null, null, null, standardWgpuMaterialRenderer, 1);
|
|
258
|
+
recordWgpuQuadBatchColorScaleBias(state, null, 0);
|
|
259
|
+
runtime.quadBatchWriterCount = 1;
|
|
260
|
+
expect(() => flushWgpuQuadBatchWriter(state)).not.toThrow();
|
|
252
261
|
submitWgpuRenderPass(state);
|
|
253
262
|
});
|
|
254
263
|
});
|
|
255
264
|
|
|
256
|
-
describe('
|
|
265
|
+
describe('resetWgpuQuadBatchWriterBufferPool', () => {
|
|
257
266
|
it('rewinds the pool cursor so slots are reclaimed next frame', async () => {
|
|
258
267
|
const state = await createWgpuRenderStateForTest();
|
|
259
268
|
renderWgpuBackground(state);
|
|
260
269
|
const runtime = getWgpuRenderStateRuntime(state);
|
|
261
|
-
const tex =
|
|
270
|
+
const tex = makeTexture();
|
|
262
271
|
|
|
263
|
-
|
|
264
|
-
runtime.
|
|
265
|
-
|
|
266
|
-
expect(runtime.
|
|
272
|
+
prepareWgpuQuadBatchWrite(state, tex, null, null, null, standardWgpuMaterialRenderer, 1);
|
|
273
|
+
runtime.quadBatchWriterCount = 1;
|
|
274
|
+
flushWgpuQuadBatchWriter(state);
|
|
275
|
+
expect(runtime.quadBatchWriterBufferCursor).toBe(1);
|
|
267
276
|
|
|
268
|
-
|
|
269
|
-
expect(runtime.
|
|
277
|
+
resetWgpuQuadBatchWriterBufferPool(state);
|
|
278
|
+
expect(runtime.quadBatchWriterBufferCursor).toBe(0);
|
|
270
279
|
submitWgpuRenderPass(state);
|
|
271
280
|
});
|
|
272
281
|
});
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import type * as FlightNodeModule from '@flighthq/node/contract';
|
|
2
|
+
import { getWgpuRenderStateRuntime } from '@flighthq/render-wgpu/contract';
|
|
3
|
+
import { createWgpuRenderStateForTest, installWgpuMock, renderWgpuBackground } from '@flighthq/render-wgpu/contract';
|
|
4
|
+
import { enableRenderRegistryGuards, explainRenderRegistryMisses } from '@flighthq/render/contract';
|
|
5
|
+
import { appendShapeBeginFill, appendShapeEndFill, appendShapeRectangle, createShape } from '@flighthq/shape/contract';
|
|
6
|
+
import type { RenderProxy2D } from '@flighthq/types/contract';
|
|
7
|
+
import { BatchFormat, RenderRegistry } from '@flighthq/types/contract';
|
|
8
|
+
|
|
9
|
+
import { scopeModuleMocks } from './moduleMockTestHelper';
|
|
10
|
+
import type * as WgpuRasterShapeModule from './wgpuRasterShapeRenderer';
|
|
11
|
+
import { registerWgpuShapeRasterizer } from './wgpuShapeRasterizer';
|
|
12
|
+
import { registerWgpuStandardMaterial } from './wgpuStandardMaterial';
|
|
13
|
+
|
|
14
|
+
let defaultWgpuRasterShapeRenderer: typeof WgpuRasterShapeModule.defaultWgpuRasterShapeRenderer;
|
|
15
|
+
let drawWgpuRasterShape: typeof WgpuRasterShapeModule.drawWgpuRasterShape;
|
|
16
|
+
|
|
17
|
+
scopeModuleMocks(['@flighthq/node']);
|
|
18
|
+
|
|
19
|
+
beforeAll(async () => {
|
|
20
|
+
vi.doMock('@flighthq/node/contract', async (importOriginal) => ({
|
|
21
|
+
...(await importOriginal<typeof FlightNodeModule>()),
|
|
22
|
+
getNodeLocalBoundsRectangle: () => ({ x: 0, y: 0, width: 64, height: 48 }),
|
|
23
|
+
getNodeLocalContentRevision: (source: any) => source?.data?.version ?? 0,
|
|
24
|
+
}));
|
|
25
|
+
({ defaultWgpuRasterShapeRenderer, drawWgpuRasterShape } = await import('./wgpuRasterShapeRenderer'));
|
|
26
|
+
installWgpuMock();
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
function makeShapeData() {
|
|
30
|
+
return {
|
|
31
|
+
surface: null,
|
|
32
|
+
lastContentId: -1,
|
|
33
|
+
lastPixelRatio: 0,
|
|
34
|
+
lastW: 0,
|
|
35
|
+
lastH: 0,
|
|
36
|
+
meshVersion: -1,
|
|
37
|
+
meshes: null,
|
|
38
|
+
meshBuffers: {
|
|
39
|
+
vertexBuffers: [],
|
|
40
|
+
vertexCapacities: [],
|
|
41
|
+
indexBuffers: [],
|
|
42
|
+
indexCapacities: [],
|
|
43
|
+
uniformBuffers: [],
|
|
44
|
+
bindGroups: [],
|
|
45
|
+
colorScaleBiasUniformBuffers: [],
|
|
46
|
+
colorScaleBiasBindGroups: [],
|
|
47
|
+
},
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function makeShapeProxy(data: Record<string, unknown>, rendererData: unknown = makeShapeData()): RenderProxy2D {
|
|
52
|
+
return {
|
|
53
|
+
source: { data: { commands: [], version: 0, ...data } },
|
|
54
|
+
blendMode: 0,
|
|
55
|
+
alpha: 1,
|
|
56
|
+
material: null,
|
|
57
|
+
materialData: null,
|
|
58
|
+
transform2D: { a: 1, b: 0, c: 0, d: 1, tx: 0, ty: 0 },
|
|
59
|
+
rendererData,
|
|
60
|
+
} as unknown as RenderProxy2D;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function makeMeshPassSpy(): GPURenderPassEncoder {
|
|
64
|
+
return {
|
|
65
|
+
setPipeline: vi.fn(),
|
|
66
|
+
setBindGroup: vi.fn(),
|
|
67
|
+
setVertexBuffer: vi.fn(),
|
|
68
|
+
setIndexBuffer: vi.fn(),
|
|
69
|
+
setStencilReference: vi.fn(),
|
|
70
|
+
draw: vi.fn(),
|
|
71
|
+
drawIndexed: vi.fn(),
|
|
72
|
+
end: vi.fn(),
|
|
73
|
+
} as unknown as GPURenderPassEncoder;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// A plain solid rectangle — precisely the shape the mesh strategy would tessellate.
|
|
77
|
+
function solidShape() {
|
|
78
|
+
const shape = createShape();
|
|
79
|
+
appendShapeBeginFill(shape, 0x00cc00);
|
|
80
|
+
appendShapeRectangle(shape, 8, 8, 32, 24);
|
|
81
|
+
appendShapeEndFill(shape);
|
|
82
|
+
return shape;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
describe('defaultWgpuRasterShapeRenderer', () => {
|
|
86
|
+
it('declares BatchFormat.Quad and the shared shape data lifecycle', () => {
|
|
87
|
+
expect(defaultWgpuRasterShapeRenderer.format).toBe(BatchFormat.Quad);
|
|
88
|
+
expect(typeof defaultWgpuRasterShapeRenderer.createData).toBe('function');
|
|
89
|
+
expect(typeof defaultWgpuRasterShapeRenderer.destroyData).toBe('function');
|
|
90
|
+
expect(defaultWgpuRasterShapeRenderer.submit).toBe(drawWgpuRasterShape);
|
|
91
|
+
});
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
describe('drawWgpuRasterShape', () => {
|
|
95
|
+
it('rasterizes a fill the mesh path could have tessellated, which is what pinning this strategy means', async () => {
|
|
96
|
+
const state = await createWgpuRenderStateForTest();
|
|
97
|
+
renderWgpuBackground(state);
|
|
98
|
+
registerWgpuStandardMaterial(state);
|
|
99
|
+
const pass = makeMeshPassSpy();
|
|
100
|
+
getWgpuRenderStateRuntime(state).renderPass = pass;
|
|
101
|
+
const rasterizer = vi.fn();
|
|
102
|
+
registerWgpuShapeRasterizer(state, rasterizer);
|
|
103
|
+
|
|
104
|
+
drawWgpuRasterShape(state, makeShapeProxy({ commands: solidShape().data.commands, version: 1 }));
|
|
105
|
+
|
|
106
|
+
expect(rasterizer).toHaveBeenCalledTimes(1);
|
|
107
|
+
expect(pass.drawIndexed).not.toHaveBeenCalled();
|
|
108
|
+
expect(getWgpuRenderStateRuntime(state).quadBatchWriterCount).toBe(1);
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
it('replays the whole command stream, not the subset a mesh path could not express', async () => {
|
|
112
|
+
const state = await createWgpuRenderStateForTest();
|
|
113
|
+
renderWgpuBackground(state);
|
|
114
|
+
registerWgpuStandardMaterial(state);
|
|
115
|
+
getWgpuRenderStateRuntime(state).renderPass = makeMeshPassSpy();
|
|
116
|
+
const shape = solidShape();
|
|
117
|
+
let replayed: readonly unknown[] = [];
|
|
118
|
+
registerWgpuShapeRasterizer(state, (_ctx, commands) => {
|
|
119
|
+
replayed = commands;
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
drawWgpuRasterShape(state, makeShapeProxy({ commands: shape.data.commands, version: 1 }));
|
|
123
|
+
|
|
124
|
+
expect(replayed).toEqual(shape.data.commands);
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
it('reports a ShapeRasterizer miss when no rasterizer is registered', async () => {
|
|
128
|
+
const state = await createWgpuRenderStateForTest();
|
|
129
|
+
renderWgpuBackground(state);
|
|
130
|
+
getWgpuRenderStateRuntime(state).renderPass = makeMeshPassSpy();
|
|
131
|
+
enableRenderRegistryGuards(state);
|
|
132
|
+
|
|
133
|
+
drawWgpuRasterShape(state, makeShapeProxy({ commands: solidShape().data.commands, version: 1 }));
|
|
134
|
+
|
|
135
|
+
expect(explainRenderRegistryMisses(state).misses).toContainEqual({
|
|
136
|
+
kind: 'Shape',
|
|
137
|
+
registry: RenderRegistry.ShapeRasterizer,
|
|
138
|
+
});
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
it('does nothing without a render pass, for an empty command list, or with absent renderer data', async () => {
|
|
142
|
+
const state = await createWgpuRenderStateForTest();
|
|
143
|
+
renderWgpuBackground(state);
|
|
144
|
+
registerWgpuStandardMaterial(state);
|
|
145
|
+
const rasterizer = vi.fn();
|
|
146
|
+
registerWgpuShapeRasterizer(state, rasterizer);
|
|
147
|
+
|
|
148
|
+
getWgpuRenderStateRuntime(state).renderPass = null;
|
|
149
|
+
drawWgpuRasterShape(state, makeShapeProxy({ commands: solidShape().data.commands, version: 1 }));
|
|
150
|
+
getWgpuRenderStateRuntime(state).renderPass = makeMeshPassSpy();
|
|
151
|
+
drawWgpuRasterShape(state, makeShapeProxy({ commands: [], version: 1 }));
|
|
152
|
+
drawWgpuRasterShape(state, makeShapeProxy({ commands: solidShape().data.commands, version: 1 }, null));
|
|
153
|
+
|
|
154
|
+
expect(rasterizer).not.toHaveBeenCalled();
|
|
155
|
+
});
|
|
156
|
+
});
|