@flighthq/effects-wgpu 0.5.1-next.650.5d3df0b → 0.5.1-next.658.9cb44d7

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 CHANGED
@@ -13,5 +13,5 @@ Import the supported application-facing API from `@flighthq/effects-wgpu`. The `
13
13
  This package is part of the locked-version Flight SDK graph. Applications may instead install and import `@flighthq/sdk` when package-level tree shaking is sufficient.
14
14
 
15
15
  - [Flight project](https://github.com/flighthq/flight)
16
- - [Source for @flighthq/effects-wgpu@0.5.1-next.650.5d3df0b](https://github.com/flighthq/flight/tree/5d3df0b3bd7071e51898ec6ca5f733b81cb94a54/packages/effects-wgpu)
17
- - [License](https://github.com/flighthq/flight/blob/5d3df0b3bd7071e51898ec6ca5f733b81cb94a54/LICENSE.md)
16
+ - [Source for @flighthq/effects-wgpu@0.5.1-next.658.9cb44d7](https://github.com/flighthq/flight/tree/9cb44d76b981adad2503d5e62207be99adb35c55/packages/effects-wgpu)
17
+ - [License](https://github.com/flighthq/flight/blob/9cb44d76b981adad2503d5e62207be99adb35c55/LICENSE.md)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flighthq/effects-wgpu",
3
- "version": "0.5.1-next.650.5d3df0b",
3
+ "version": "0.5.1-next.658.9cb44d7",
4
4
  "author": "Joshua Granick and other contributors",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -38,14 +38,14 @@
38
38
  "clean:dist": "tsx ../../scripts/clean-package-dist.ts"
39
39
  },
40
40
  "dependencies": {
41
- "@flighthq/adjustments": "0.5.1-next.650.5d3df0b",
42
- "@flighthq/color": "0.5.1-next.650.5d3df0b",
43
- "@flighthq/effects": "0.5.1-next.650.5d3df0b",
44
- "@flighthq/geometry": "0.5.1-next.650.5d3df0b",
45
- "@flighthq/log": "0.5.1-next.650.5d3df0b",
46
- "@flighthq/render-wgpu": "0.5.1-next.650.5d3df0b",
47
- "@flighthq/registry": "0.5.1-next.650.5d3df0b",
48
- "@flighthq/types": "0.5.1-next.650.5d3df0b"
41
+ "@flighthq/adjustments": "0.5.1-next.658.9cb44d7",
42
+ "@flighthq/color": "0.5.1-next.658.9cb44d7",
43
+ "@flighthq/effects": "0.5.1-next.658.9cb44d7",
44
+ "@flighthq/geometry": "0.5.1-next.658.9cb44d7",
45
+ "@flighthq/log": "0.5.1-next.658.9cb44d7",
46
+ "@flighthq/render-wgpu": "0.5.1-next.658.9cb44d7",
47
+ "@flighthq/registry": "0.5.1-next.658.9cb44d7",
48
+ "@flighthq/types": "0.5.1-next.658.9cb44d7"
49
49
  },
50
50
  "peerDependencies": {
51
51
  "@webgpu/types": "^0.1.70"
@@ -1,71 +1,83 @@
1
+ import * as renderWgpuContractModule from '@flighthq/render-wgpu/contract';
1
2
  import { createWgpuRenderStateForTest, installWgpuMock } from '@flighthq/render-wgpu/contract';
2
3
  import type { BevelEffect, WgpuRenderState, WgpuRenderTarget, WgpuRenderTargetPool } from '@flighthq/types/contract';
3
4
 
4
- const passMock = vi.hoisted(() => ({
5
- clearWgpuEffectTarget: vi.fn(),
6
- createWgpuDualSourceEffectPipeline: vi.fn(() => ({ pipeline: {} })),
7
- drawWgpuDualSourceEffectPass: vi.fn(
8
- (
9
- _state: unknown,
10
- _field: unknown,
11
- _source: unknown,
12
- _dest: unknown,
13
- _pipeline: unknown,
14
- setUniforms: (f32: Float32Array) => void,
15
- ) => {
16
- const f32 = new Float32Array(12);
17
- setUniforms(f32);
18
- recorded.composites.push([...f32]);
19
- },
20
- ),
21
- }));
22
- const blitMock = vi.hoisted(() => ({
23
- applyWgpuEffectBlitPass: vi.fn(() => recorded.calls.push('blit')),
24
- applyWgpuEffectErasePass: vi.fn(() => recorded.calls.push('erase')),
25
- }));
26
- const blurMock = vi.hoisted(() => ({
27
- applyWgpuEffectBoxBlur: vi.fn((_state: unknown, _s: unknown, _d: unknown, _t: unknown, options: unknown) => {
28
- recorded.blurs.push(options);
29
- }),
30
- }));
31
- const tintMock = vi.hoisted(() => ({
32
- applyWgpuEffectTintPass: vi.fn(
33
- (_state: unknown, _source: unknown, _dest: unknown, color: number, alpha: number, strength: number) => {
34
- recorded.tints.push([color, alpha, strength]);
35
- },
36
- ),
37
- }));
38
- const targetMock = vi.hoisted(() => ({
39
- acquireWgpuRenderTarget: vi.fn((_state: unknown, _pool: unknown, descriptor: unknown) => {
40
- const target = { ...(descriptor as object), id: `scratch-${recorded.acquired.length}`, view: {} };
41
- recorded.acquired.push(target);
42
- return target;
43
- }),
44
- releaseWgpuRenderTarget: vi.fn((_pool: unknown, target: unknown) => recorded.released.push(target)),
45
- }));
46
- const recorded = vi.hoisted(() => ({
5
+ import { applyBevelEffectToWgpu, defaultWgpuBevelEffectRunner, registerWgpuBevelEffect } from './wgpuBevelEffect';
6
+ import * as wgpuEffectBlitShaderModule from './wgpuEffectBlitShader';
7
+ import * as wgpuEffectBoxBlurModule from './wgpuEffectBoxBlur';
8
+ import * as wgpuEffectPassModule from './wgpuEffectPass';
9
+ import * as wgpuEffectTintShaderModule from './wgpuEffectTintShader';
10
+ import { getWgpuRenderEffectRunner } from './wgpuRenderEffectRegistry';
11
+
12
+ const recorded = {
47
13
  acquired: [] as unknown[],
48
14
  blurs: [] as unknown[],
49
15
  calls: [] as string[],
50
16
  composites: [] as number[][],
51
17
  released: [] as unknown[],
52
18
  tints: [] as (number | undefined)[][],
53
- }));
19
+ };
54
20
 
55
- vi.mock('./wgpuEffectBlitShader', () => blitMock);
56
- vi.mock('./wgpuEffectBoxBlur', () => blurMock);
57
- vi.mock('./wgpuEffectPass', () => passMock);
58
- vi.mock('./wgpuEffectTintShader', () => tintMock);
21
+ beforeAll(() => installWgpuMock());
59
22
 
60
- vi.mock('@flighthq/render-wgpu/contract', async () => {
61
- const actual = (await vi.importActual('@flighthq/render-wgpu/contract')) as Record<string, unknown>;
62
- return { ...actual, ...targetMock };
23
+ beforeEach(() => {
24
+ vi.spyOn(wgpuEffectPassModule, 'clearWgpuEffectTarget').mockImplementation((() => {}) as never);
25
+ vi.spyOn(wgpuEffectPassModule, 'createWgpuDualSourceEffectPipeline').mockImplementation((() => ({
26
+ pipeline: {},
27
+ })) as never);
28
+ vi.spyOn(wgpuEffectPassModule, 'drawWgpuDualSourceEffectPass').mockImplementation(((
29
+ _state: unknown,
30
+ _field: unknown,
31
+ _source: unknown,
32
+ _dest: unknown,
33
+ _pipeline: unknown,
34
+ setUniforms: (f32: Float32Array) => void,
35
+ ) => {
36
+ const f32 = new Float32Array(12);
37
+ setUniforms(f32);
38
+ recorded.composites.push([...f32]);
39
+ }) as never);
40
+
41
+ vi.spyOn(wgpuEffectBlitShaderModule, 'applyWgpuEffectBlitPass').mockImplementation((() =>
42
+ recorded.calls.push('blit')) as never);
43
+ vi.spyOn(wgpuEffectBlitShaderModule, 'applyWgpuEffectErasePass').mockImplementation((() =>
44
+ recorded.calls.push('erase')) as never);
45
+
46
+ vi.spyOn(wgpuEffectBoxBlurModule, 'applyWgpuEffectBoxBlur').mockImplementation(((
47
+ _state: unknown,
48
+ _s: unknown,
49
+ _d: unknown,
50
+ _t: unknown,
51
+ options: unknown,
52
+ ) => {
53
+ recorded.blurs.push(options);
54
+ }) as never);
55
+
56
+ vi.spyOn(wgpuEffectTintShaderModule, 'applyWgpuEffectTintPass').mockImplementation(((
57
+ _state: unknown,
58
+ _source: unknown,
59
+ _dest: unknown,
60
+ color: number,
61
+ alpha: number,
62
+ strength: number,
63
+ ) => {
64
+ recorded.tints.push([color, alpha, strength]);
65
+ }) as never);
66
+
67
+ vi.spyOn(renderWgpuContractModule, 'acquireWgpuRenderTarget').mockImplementation(((
68
+ _state: unknown,
69
+ _pool: unknown,
70
+ descriptor: unknown,
71
+ ) => {
72
+ const target = { ...(descriptor as object), id: `scratch-${recorded.acquired.length}`, view: {} };
73
+ recorded.acquired.push(target);
74
+ return target;
75
+ }) as never);
76
+ vi.spyOn(renderWgpuContractModule, 'releaseWgpuRenderTarget').mockImplementation(((_pool: unknown, target: unknown) =>
77
+ recorded.released.push(target)) as never);
63
78
  });
64
79
 
65
- import { applyBevelEffectToWgpu, defaultWgpuBevelEffectRunner, registerWgpuBevelEffect } from './wgpuBevelEffect';
66
- import { getWgpuRenderEffectRunner } from './wgpuRenderEffectRegistry';
67
-
68
- beforeAll(() => installWgpuMock());
80
+ afterEach(() => vi.restoreAllMocks());
69
81
 
70
82
  const SOURCE_WIDTH = 100;
71
83
  const SOURCE_HEIGHT = 50;
@@ -1,11 +1,10 @@
1
1
  import { installWgpuMock } from '@flighthq/render-wgpu/contract';
2
2
  import type { ColorLut, WgpuColorLutTextureCache, WgpuRenderState, WgpuRenderTarget } from '@flighthq/types/contract';
3
3
 
4
- const passStateMock = vi.hoisted(() => ({
5
- EFFECT_VERTEX_WGSL: 'VERTEX_WGSL\n',
6
- getWgpuEffectPassState: vi.fn(() => passState),
7
- }));
8
- const passState = vi.hoisted(() => ({
4
+ import { applyColorLutPassToWgpu } from './wgpuColorLutPass';
5
+ import * as wgpuEffectPassModule from './wgpuEffectPass';
6
+
7
+ const passState = {
9
8
  acquireSlot: vi.fn(() => 256),
10
9
  beginPass: vi.fn((_dest: unknown, loadOp: string) => {
11
10
  recorded.loadOps.push(loadOp);
@@ -25,24 +24,28 @@ const passState = vi.hoisted(() => ({
25
24
  write(f32);
26
25
  recorded.uniforms.push([...f32]);
27
26
  }),
28
- }));
29
- const recorded = vi.hoisted(() => ({
27
+ };
28
+ const recorded = {
30
29
  bindGroups: [] as { group: unknown; index: number }[],
31
30
  draws: [] as number[],
32
31
  loadOps: [] as string[],
33
32
  pipelines: [] as unknown[],
34
33
  shaderCode: [] as string[],
35
34
  uniforms: [] as number[][],
36
- }));
37
-
38
- vi.mock('./wgpuEffectPass', () => passStateMock);
39
-
40
- import { applyColorLutPassToWgpu } from './wgpuColorLutPass';
35
+ };
41
36
 
42
37
  // The WebGPU flag enums are type-level only in @webgpu/types, so jsdom has no runtime values for the
43
38
  // usage and visibility bits this module ORs together.
44
39
  beforeAll(() => installWgpuMock());
45
40
 
41
+ beforeEach(() => {
42
+ vi.spyOn(wgpuEffectPassModule, 'getWgpuEffectPassState').mockReturnValue(passState as never);
43
+ // eslint-disable-next-line no-import-assign -- replacing a non-function export for test; works on Vite SSR namespaces
44
+ Object.defineProperty(wgpuEffectPassModule, 'EFFECT_VERTEX_WGSL', { value: 'VERTEX_WGSL\n', configurable: true });
45
+ });
46
+
47
+ afterEach(() => vi.restoreAllMocks());
48
+
46
49
  function createHarness(): {
47
50
  createTexture: ReturnType<typeof vi.fn>;
48
51
  destroyed: string[];
@@ -1,33 +1,37 @@
1
1
  import type { WgpuRenderState, WgpuRenderTarget } from '@flighthq/types/contract';
2
2
 
3
- const passMock = vi.hoisted(() => ({
4
- drawWgpuEffectPass: vi.fn(
5
- (
6
- _state: unknown,
7
- _source: unknown,
8
- _dest: unknown,
9
- _pipeline: unknown,
10
- setUniforms: (f32: Float32Array) => void,
11
- ) => {
12
- const f32 = new Float32Array(20);
13
- setUniforms(f32);
14
- uniformState.uploads.push([...f32]);
15
- },
16
- ),
17
- }));
18
- const pipelineMock = vi.hoisted(() => ({
19
- getWgpuEffectPipeline: vi.fn((_state: unknown, _key: string, _wgsl: string, _blend: string) => ({ pipeline: {} })),
20
- }));
21
- const uniformState = vi.hoisted(() => ({ uploads: [] as number[][] }));
22
-
23
- vi.mock('./wgpuEffectPass', () => passMock);
24
- vi.mock('./wgpuEffectProgramCache', () => pipelineMock);
25
-
26
3
  import { applyColorMatrixPassToWgpu } from './wgpuColorMatrixPass';
4
+ import * as wgpuEffectPassModule from './wgpuEffectPass';
5
+ import * as wgpuEffectProgramCacheModule from './wgpuEffectProgramCache';
6
+
7
+ const uniformState = { uploads: [] as number[][] };
8
+
9
+ beforeEach(() => {
10
+ vi.spyOn(wgpuEffectPassModule, 'drawWgpuEffectPass').mockImplementation(((
11
+ _state: unknown,
12
+ _source: unknown,
13
+ _dest: unknown,
14
+ _pipeline: unknown,
15
+ setUniforms: (f32: Float32Array) => void,
16
+ ) => {
17
+ const f32 = new Float32Array(20);
18
+ setUniforms(f32);
19
+ uniformState.uploads.push([...f32]);
20
+ }) as never);
21
+
22
+ vi.spyOn(wgpuEffectProgramCacheModule, 'getWgpuEffectPipeline').mockImplementation(((
23
+ _state: unknown,
24
+ _key: string,
25
+ _wgsl: string,
26
+ _blend: string,
27
+ ) => ({ pipeline: {} })) as never);
28
+ });
29
+
30
+ afterEach(() => vi.restoreAllMocks());
27
31
 
28
32
  function packed(matrix: ReadonlyArray<number>): readonly number[] {
29
33
  uniformState.uploads.length = 0;
30
- pipelineMock.getWgpuEffectPipeline.mockClear();
34
+ vi.mocked(wgpuEffectProgramCacheModule.getWgpuEffectPipeline).mockClear();
31
35
  const target = {} as unknown as WgpuRenderTarget;
32
36
  applyColorMatrixPassToWgpu({} as unknown as WgpuRenderState, target, target, matrix);
33
37
  return uniformState.uploads[0]!;
@@ -96,7 +100,7 @@ describe('applyColorMatrixPassToWgpu', () => {
96
100
  it('compiles one pipeline for every matrix, in replace blend', () => {
97
101
  packed(IDENTITY);
98
102
 
99
- const call = pipelineMock.getWgpuEffectPipeline.mock.calls[0]!;
103
+ const call = vi.mocked(wgpuEffectProgramCacheModule.getWgpuEffectPipeline).mock.calls[0]!;
100
104
  expect(call[1]).toBe('adjustment.colorMatrix');
101
105
  expect(call[3]).toBe('replace');
102
106
  });
@@ -1,5 +1,3 @@
1
- vi.mock('./wgpuSsaoEffect', () => ({ applySsaoEffectToWgpu: vi.fn() }));
2
-
3
1
  import { createWgpuRenderStateForTest, installWgpuMock } from '@flighthq/render-wgpu/contract';
4
2
 
5
3
  import {
@@ -8,12 +6,18 @@ import {
8
6
  registerWgpuContactShadowsEffect,
9
7
  } from './wgpuContactShadowsEffect';
10
8
  import { getWgpuRenderEffectRunner } from './wgpuRenderEffectRegistry';
11
- import { applySsaoEffectToWgpu } from './wgpuSsaoEffect';
9
+ import * as wgpuSsaoEffectMod from './wgpuSsaoEffect';
12
10
 
13
11
  beforeAll(() => {
14
12
  installWgpuMock();
15
13
  });
16
14
 
15
+ beforeEach(() => {
16
+ vi.spyOn(wgpuSsaoEffectMod, 'applySsaoEffectToWgpu').mockImplementation((() => {}) as never);
17
+ });
18
+
19
+ afterEach(() => vi.restoreAllMocks());
20
+
17
21
  describe('applyContactShadowsEffectToWgpu', () => {
18
22
  it('maps the contact descriptor into the shared local-occlusion realization', () => {
19
23
  applyContactShadowsEffectToWgpu({} as never, {} as never, {} as never, {
@@ -23,12 +27,17 @@ describe('applyContactShadowsEffectToWgpu', () => {
23
27
  samples: 24,
24
28
  });
25
29
 
26
- expect(applySsaoEffectToWgpu).toHaveBeenCalledWith(expect.anything(), expect.anything(), expect.anything(), {
27
- intensity: 0.75,
28
- kind: 'SsaoEffect',
29
- radius: 3,
30
- samples: 24,
31
- });
30
+ expect(wgpuSsaoEffectMod.applySsaoEffectToWgpu).toHaveBeenCalledWith(
31
+ expect.anything(),
32
+ expect.anything(),
33
+ expect.anything(),
34
+ {
35
+ intensity: 0.75,
36
+ kind: 'SsaoEffect',
37
+ radius: 3,
38
+ samples: 24,
39
+ },
40
+ );
32
41
  });
33
42
  });
34
43
 
@@ -1,39 +1,43 @@
1
- vi.mock('@flighthq/render-wgpu/contract', () => {
2
- let nextTargetId = 0;
3
- return {
4
- acquireWgpuRenderTarget: vi.fn((_state, _pool, descriptor) => ({
5
- ...descriptor,
6
- id: `scratch-${nextTargetId++}`,
7
- texture: {},
8
- })),
9
- releaseWgpuRenderTarget: vi.fn(),
10
- };
11
- });
12
-
13
- vi.mock('./wgpuEffectBlitShader', () => ({
14
- applyWgpuEffectBlitOffsetPass: vi.fn(),
15
- applyWgpuEffectBlitPass: vi.fn(),
16
- applyWgpuEffectErasePass: vi.fn(),
17
- }));
18
-
19
- vi.mock('./wgpuEffectBoxBlur', () => ({
20
- applyWgpuEffectBoxBlur: vi.fn(),
21
- }));
22
-
23
- vi.mock('./wgpuEffectPass', () => ({
24
- clearWgpuEffectTarget: vi.fn(),
25
- }));
26
-
27
- vi.mock('./wgpuEffectTintShader', () => ({
28
- applyWgpuEffectTintPass: vi.fn(),
29
- }));
1
+ import * as renderWgpuContract from '@flighthq/render-wgpu/contract';
30
2
 
31
3
  import {
32
4
  applyDropShadowEffectToWgpu,
33
5
  defaultWgpuDropShadowEffectRunner,
34
6
  registerWgpuDropShadowEffect,
35
7
  } from './wgpuDropShadowEffect';
36
- import { applyWgpuEffectBlitPass, applyWgpuEffectErasePass } from './wgpuEffectBlitShader';
8
+ import * as wgpuEffectBlitShaderMod from './wgpuEffectBlitShader';
9
+ import * as wgpuEffectBoxBlurMod from './wgpuEffectBoxBlur';
10
+ import * as wgpuEffectPassMod from './wgpuEffectPass';
11
+ import * as wgpuEffectTintShaderMod from './wgpuEffectTintShader';
12
+
13
+ let nextTargetId = 0;
14
+
15
+ beforeEach(() => {
16
+ nextTargetId = 0;
17
+
18
+ vi.spyOn(renderWgpuContract, 'acquireWgpuRenderTarget').mockImplementation(((
19
+ _state: unknown,
20
+ _pool: unknown,
21
+ descriptor: Record<string, unknown>,
22
+ ) => ({
23
+ ...descriptor,
24
+ id: `scratch-${nextTargetId++}`,
25
+ texture: {},
26
+ })) as never);
27
+ vi.spyOn(renderWgpuContract, 'releaseWgpuRenderTarget').mockImplementation((() => {}) as never);
28
+
29
+ vi.spyOn(wgpuEffectBlitShaderMod, 'applyWgpuEffectBlitOffsetPass').mockImplementation((() => {}) as never);
30
+ vi.spyOn(wgpuEffectBlitShaderMod, 'applyWgpuEffectBlitPass').mockImplementation((() => {}) as never);
31
+ vi.spyOn(wgpuEffectBlitShaderMod, 'applyWgpuEffectErasePass').mockImplementation((() => {}) as never);
32
+
33
+ vi.spyOn(wgpuEffectBoxBlurMod, 'applyWgpuEffectBoxBlur').mockImplementation((() => {}) as never);
34
+
35
+ vi.spyOn(wgpuEffectPassMod, 'clearWgpuEffectTarget').mockImplementation((() => {}) as never);
36
+
37
+ vi.spyOn(wgpuEffectTintShaderMod, 'applyWgpuEffectTintPass').mockImplementation((() => {}) as never);
38
+ });
39
+
40
+ afterEach(() => vi.restoreAllMocks());
37
41
 
38
42
  describe('applyDropShadowEffectToWgpu', () => {
39
43
  it('is a function', () => {
@@ -46,8 +50,8 @@ describe('applyDropShadowEffectToWgpu', () => {
46
50
 
47
51
  applyDropShadowEffectToWgpu(createState(), source, dest, createPool(), { kind: 'DropShadowEffect' });
48
52
 
49
- expect(applyWgpuEffectBlitPass).toHaveBeenCalledWith(expect.anything(), source, dest);
50
- expect(applyWgpuEffectErasePass).not.toHaveBeenCalled();
53
+ expect(wgpuEffectBlitShaderMod.applyWgpuEffectBlitPass).toHaveBeenCalledWith(expect.anything(), source, dest);
54
+ expect(wgpuEffectBlitShaderMod.applyWgpuEffectErasePass).not.toHaveBeenCalled();
51
55
  });
52
56
 
53
57
  it('hides the source when sourceMode is hide', () => {
@@ -59,8 +63,8 @@ describe('applyDropShadowEffectToWgpu', () => {
59
63
  sourceMode: 'hide',
60
64
  });
61
65
 
62
- expect(applyWgpuEffectBlitPass).not.toHaveBeenCalledWith(expect.anything(), source, dest);
63
- expect(applyWgpuEffectErasePass).not.toHaveBeenCalled();
66
+ expect(wgpuEffectBlitShaderMod.applyWgpuEffectBlitPass).not.toHaveBeenCalledWith(expect.anything(), source, dest);
67
+ expect(wgpuEffectBlitShaderMod.applyWgpuEffectErasePass).not.toHaveBeenCalled();
64
68
  });
65
69
 
66
70
  it('erases the source silhouette when sourceMode is knockout', () => {
@@ -72,8 +76,8 @@ describe('applyDropShadowEffectToWgpu', () => {
72
76
  sourceMode: 'knockout',
73
77
  });
74
78
 
75
- expect(applyWgpuEffectBlitPass).not.toHaveBeenCalledWith(expect.anything(), source, dest);
76
- expect(applyWgpuEffectErasePass).toHaveBeenCalledWith(expect.anything(), source, dest);
79
+ expect(wgpuEffectBlitShaderMod.applyWgpuEffectBlitPass).not.toHaveBeenCalledWith(expect.anything(), source, dest);
80
+ expect(wgpuEffectBlitShaderMod.applyWgpuEffectErasePass).toHaveBeenCalledWith(expect.anything(), source, dest);
77
81
  });
78
82
  });
79
83
 
@@ -83,10 +87,6 @@ describe('defaultWgpuDropShadowEffectRunner', () => {
83
87
  });
84
88
  });
85
89
 
86
- beforeEach(() => {
87
- vi.clearAllMocks();
88
- });
89
-
90
90
  function createState(): never {
91
91
  return {} as never;
92
92
  }
@@ -1,30 +1,42 @@
1
1
  import type { WgpuRenderState, WgpuRenderTarget } from '@flighthq/types/contract';
2
2
 
3
- const passMock = vi.hoisted(() => ({
4
- createWgpuEffectPipeline: vi.fn((_state: unknown, wgsl: string, blend?: string) => ({ blend, wgsl })),
5
- drawWgpuEffectPass: vi.fn(
6
- (_state: unknown, source: unknown, dest: unknown, pipeline: unknown, setUniforms: (f32: Float32Array) => void) => {
7
- const f32 = new Float32Array(4);
8
- setUniforms(f32);
9
- recorded.draws.push({ dest, pipeline, source, uniforms: [...f32] });
10
- },
11
- ),
12
- }));
13
- const recorded = vi.hoisted(() => ({
14
- draws: [] as { dest: unknown; pipeline: unknown; source: unknown; uniforms: number[] }[],
15
- }));
16
-
17
- vi.mock('./wgpuEffectPass', () => passMock);
18
-
19
3
  import {
20
4
  applyWgpuEffectBlitOffsetPass,
21
5
  applyWgpuEffectBlitPass,
22
6
  applyWgpuEffectErasePass,
23
7
  } from './wgpuEffectBlitShader';
8
+ import * as wgpuEffectPassMod from './wgpuEffectPass';
9
+
10
+ const recorded = {
11
+ draws: [] as { dest: unknown; pipeline: unknown; source: unknown; uniforms: number[] }[],
12
+ };
24
13
 
25
14
  const SOURCE_WIDTH = 64;
26
15
  const SOURCE_HEIGHT = 32;
27
16
 
17
+ beforeEach(() => {
18
+ recorded.draws.length = 0;
19
+
20
+ vi.spyOn(wgpuEffectPassMod, 'createWgpuEffectPipeline').mockImplementation(((
21
+ _state: unknown,
22
+ wgsl: string,
23
+ blend?: string,
24
+ ) => ({ blend, wgsl })) as never);
25
+ vi.spyOn(wgpuEffectPassMod, 'drawWgpuEffectPass').mockImplementation(((
26
+ _state: unknown,
27
+ source: unknown,
28
+ dest: unknown,
29
+ pipeline: unknown,
30
+ setUniforms: (f32: Float32Array) => void,
31
+ ) => {
32
+ const f32 = new Float32Array(4);
33
+ setUniforms(f32);
34
+ recorded.draws.push({ dest, pipeline, source, uniforms: [...f32] });
35
+ }) as never);
36
+ });
37
+
38
+ afterEach(() => vi.restoreAllMocks());
39
+
28
40
  function createState(): WgpuRenderState {
29
41
  return {} as unknown as WgpuRenderState;
30
42
  }
@@ -35,7 +47,7 @@ function createTarget(id: string): WgpuRenderTarget {
35
47
 
36
48
  function reset(): void {
37
49
  recorded.draws.length = 0;
38
- passMock.createWgpuEffectPipeline.mockClear();
50
+ vi.mocked(wgpuEffectPassMod.createWgpuEffectPipeline).mockClear();
39
51
  }
40
52
 
41
53
  function offsetFor(dx: number, dy: number): readonly number[] {
@@ -99,7 +111,7 @@ describe('applyWgpuEffectBlitOffsetPass', () => {
99
111
  applyWgpuEffectBlitOffsetPass(state, source, dest, 1, 1);
100
112
  applyWgpuEffectBlitOffsetPass(state, source, dest, 2, 2);
101
113
 
102
- expect(passMock.createWgpuEffectPipeline).toHaveBeenCalledTimes(1);
114
+ expect(wgpuEffectPassMod.createWgpuEffectPipeline).toHaveBeenCalledTimes(1);
103
115
  });
104
116
  });
105
117
 
@@ -127,7 +139,7 @@ describe('applyWgpuEffectBlitPass', () => {
127
139
  applyWgpuEffectBlitOffsetPass(state, source, dest, 1, 1);
128
140
 
129
141
  expect(new Set(recorded.draws.map((draw) => draw.pipeline)).size).toBe(3);
130
- expect(passMock.createWgpuEffectPipeline).toHaveBeenCalledTimes(3);
142
+ expect(wgpuEffectPassMod.createWgpuEffectPipeline).toHaveBeenCalledTimes(3);
131
143
  });
132
144
  });
133
145
 
@@ -140,7 +152,7 @@ describe('applyWgpuEffectErasePass', () => {
140
152
 
141
153
  applyWgpuEffectErasePass(createState(), createTarget('source'), createTarget('dest'));
142
154
 
143
- expect(passMock.createWgpuEffectPipeline.mock.calls[0]![2]).toBe('erase');
155
+ expect(vi.mocked(wgpuEffectPassMod.createWgpuEffectPipeline).mock.calls[0]![2]).toBe('erase');
144
156
  });
145
157
 
146
158
  it('binds the mask as its source', () => {
@@ -1,19 +1,30 @@
1
- const mockState = vi.hoisted(() => ({
2
- uniformSnapshots: [] as number[][],
3
- }));
1
+ import { applyWgpuEffectBoxBlur } from './wgpuEffectBoxBlur';
2
+ import * as wgpuEffectPassMod from './wgpuEffectPass';
3
+
4
+ const uniformSnapshots: number[][] = [];
4
5
 
5
- vi.mock('./wgpuEffectPass', () => ({
6
- createWgpuEffectPipeline: vi.fn(() => ({ blendMode: 'replace', pipeline: {} })),
7
- drawWgpuEffectPass: vi.fn((_state, _source, _dest, _pipeline, setUniforms) => {
6
+ beforeEach(() => {
7
+ uniformSnapshots.length = 0;
8
+
9
+ vi.spyOn(wgpuEffectPassMod, 'createWgpuEffectPipeline').mockReturnValue({
10
+ blendMode: 'replace',
11
+ pipeline: {},
12
+ } as never);
13
+ vi.spyOn(wgpuEffectPassMod, 'drawWgpuEffectPass').mockImplementation(((
14
+ _state: unknown,
15
+ _source: unknown,
16
+ _dest: unknown,
17
+ _pipeline: unknown,
18
+ setUniforms: Function,
19
+ ) => {
8
20
  const f32 = new Float32Array(16);
9
21
  const i32 = new Int32Array(f32.buffer);
10
22
  setUniforms(f32, i32);
11
- mockState.uniformSnapshots.push(Array.from(f32));
12
- }),
13
- }));
23
+ uniformSnapshots.push(Array.from(f32));
24
+ }) as never);
25
+ });
14
26
 
15
- import { applyWgpuEffectBoxBlur } from './wgpuEffectBoxBlur';
16
- import { createWgpuEffectPipeline, drawWgpuEffectPass } from './wgpuEffectPass';
27
+ afterEach(() => vi.restoreAllMocks());
17
28
 
18
29
  describe('applyWgpuEffectBoxBlur', () => {
19
30
  it('is a function', () => {
@@ -28,12 +39,16 @@ describe('applyWgpuEffectBoxBlur', () => {
28
39
  passes: 1,
29
40
  });
30
41
 
31
- expect(createWgpuEffectPipeline).toHaveBeenCalledWith(expect.anything(), expect.any(String), 'replace');
32
- expect(mockState.uniformSnapshots[0]![4]).toBeCloseTo(0.1);
33
- expect(mockState.uniformSnapshots[0]![5]).toBeCloseTo(0.2);
34
- expect(mockState.uniformSnapshots[0]![6]).toBeCloseTo(0.3);
35
- expect(mockState.uniformSnapshots[0]![7]).toBeCloseTo(0.4);
36
- expect(mockState.uniformSnapshots[0]![9]).toBe(1);
42
+ expect(wgpuEffectPassMod.createWgpuEffectPipeline).toHaveBeenCalledWith(
43
+ expect.anything(),
44
+ expect.any(String),
45
+ 'replace',
46
+ );
47
+ expect(uniformSnapshots[0]![4]).toBeCloseTo(0.1);
48
+ expect(uniformSnapshots[0]![5]).toBeCloseTo(0.2);
49
+ expect(uniformSnapshots[0]![6]).toBeCloseTo(0.3);
50
+ expect(uniformSnapshots[0]![7]).toBeCloseTo(0.4);
51
+ expect(uniformSnapshots[0]![9]).toBe(1);
37
52
  });
38
53
 
39
54
  it('uses the replacement blur pipeline for zero-radius copies', () => {
@@ -45,18 +60,13 @@ describe('applyWgpuEffectBoxBlur', () => {
45
60
  passes: 1,
46
61
  });
47
62
 
48
- expect(drawWgpuEffectPass).toHaveBeenCalledTimes(1);
49
- expect(vi.mocked(drawWgpuEffectPass).mock.calls[0]![2]).toBe(dest);
50
- expect(mockState.uniformSnapshots[0]![8]).toBe(0);
51
- expect(mockState.uniformSnapshots[0]![9]).toBe(0);
63
+ expect(wgpuEffectPassMod.drawWgpuEffectPass).toHaveBeenCalledTimes(1);
64
+ expect(vi.mocked(wgpuEffectPassMod.drawWgpuEffectPass).mock.calls[0]![2]).toBe(dest);
65
+ expect(uniformSnapshots[0]![8]).toBe(0);
66
+ expect(uniformSnapshots[0]![9]).toBe(0);
52
67
  });
53
68
  });
54
69
 
55
- beforeEach(() => {
56
- vi.clearAllMocks();
57
- mockState.uniformSnapshots.length = 0;
58
- });
59
-
60
70
  function createState(): never {
61
71
  return {} as never;
62
72
  }