@flighthq/scene2d-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/scene2d-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/scene2d-wgpu@0.5.1-next.650.5d3df0b](https://github.com/flighthq/flight/tree/5d3df0b3bd7071e51898ec6ca5f733b81cb94a54/packages/scene2d-wgpu)
17
- - [License](https://github.com/flighthq/flight/blob/5d3df0b3bd7071e51898ec6ca5f733b81cb94a54/LICENSE.md)
16
+ - [Source for @flighthq/scene2d-wgpu@0.5.1-next.658.9cb44d7](https://github.com/flighthq/flight/tree/9cb44d76b981adad2503d5e62207be99adb35c55/packages/scene2d-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/scene2d-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,25 +38,25 @@
38
38
  "clean:dist": "tsx ../../scripts/clean-package-dist.ts"
39
39
  },
40
40
  "dependencies": {
41
- "@flighthq/color": "0.5.1-next.650.5d3df0b",
42
- "@flighthq/entity": "0.5.1-next.650.5d3df0b",
43
- "@flighthq/scene2d": "0.5.1-next.650.5d3df0b",
44
- "@flighthq/scene2d-canvas": "0.5.1-next.650.5d3df0b",
45
- "@flighthq/geometry": "0.5.1-next.650.5d3df0b",
46
- "@flighthq/image": "0.5.1-next.650.5d3df0b",
47
- "@flighthq/log": "0.5.1-next.650.5d3df0b",
48
- "@flighthq/node": "0.5.1-next.650.5d3df0b",
49
- "@flighthq/path": "0.5.1-next.650.5d3df0b",
50
- "@flighthq/registry": "0.5.1-next.650.5d3df0b",
51
- "@flighthq/render": "0.5.1-next.650.5d3df0b",
52
- "@flighthq/render-wgpu": "0.5.1-next.650.5d3df0b",
53
- "@flighthq/shape": "0.5.1-next.650.5d3df0b",
54
- "@flighthq/text": "0.5.1-next.650.5d3df0b",
55
- "@flighthq/textinput": "0.5.1-next.650.5d3df0b",
56
- "@flighthq/textlayout": "0.5.1-next.650.5d3df0b",
57
- "@flighthq/texture": "0.5.1-next.650.5d3df0b",
58
- "@flighthq/types": "0.5.1-next.650.5d3df0b",
59
- "@flighthq/velocity": "0.5.1-next.650.5d3df0b"
41
+ "@flighthq/color": "0.5.1-next.658.9cb44d7",
42
+ "@flighthq/entity": "0.5.1-next.658.9cb44d7",
43
+ "@flighthq/scene2d": "0.5.1-next.658.9cb44d7",
44
+ "@flighthq/scene2d-canvas": "0.5.1-next.658.9cb44d7",
45
+ "@flighthq/geometry": "0.5.1-next.658.9cb44d7",
46
+ "@flighthq/image": "0.5.1-next.658.9cb44d7",
47
+ "@flighthq/log": "0.5.1-next.658.9cb44d7",
48
+ "@flighthq/node": "0.5.1-next.658.9cb44d7",
49
+ "@flighthq/path": "0.5.1-next.658.9cb44d7",
50
+ "@flighthq/registry": "0.5.1-next.658.9cb44d7",
51
+ "@flighthq/render": "0.5.1-next.658.9cb44d7",
52
+ "@flighthq/render-wgpu": "0.5.1-next.658.9cb44d7",
53
+ "@flighthq/shape": "0.5.1-next.658.9cb44d7",
54
+ "@flighthq/text": "0.5.1-next.658.9cb44d7",
55
+ "@flighthq/textinput": "0.5.1-next.658.9cb44d7",
56
+ "@flighthq/textlayout": "0.5.1-next.658.9cb44d7",
57
+ "@flighthq/texture": "0.5.1-next.658.9cb44d7",
58
+ "@flighthq/types": "0.5.1-next.658.9cb44d7",
59
+ "@flighthq/velocity": "0.5.1-next.658.9cb44d7"
60
60
  },
61
61
  "peerDependencies": {
62
62
  "@webgpu/types": "^0.1.70"
@@ -1,6 +1,6 @@
1
1
  import { createMatrix } from '@flighthq/geometry/contract';
2
2
  import { getRegistryTableEntry } from '@flighthq/registry/contract';
3
- import type * as WgpuRenderWgpuModule from '@flighthq/render-wgpu/contract';
3
+ import * as renderWgpu from '@flighthq/render-wgpu/contract';
4
4
  import {
5
5
  createRenderCache,
6
6
  createRenderState,
@@ -21,138 +21,6 @@ import type {
21
21
  } from '@flighthq/types/contract';
22
22
  import { EntityRuntimeKey, RegistryEntryState } from '@flighthq/types/contract';
23
23
 
24
- import type * as WgpuNode2DModule from './wgpuNode2D';
25
- import type * as WgpuQuadBatchWriterModule from './wgpuQuadBatchWriter';
26
-
27
- // The GPU render-target lifecycle (@flighthq/render-wgpu) and the two local collaborators
28
- // ./wgpuQuadBatchWriter and ./wgpuNode2D are stubbed so cache orchestration can be unit-tested without a
29
- // real GPU pipeline: createWgpuRenderTarget returns a plain descriptor, and the composite, batch-flush
30
- // and subtree-render calls become spies for the call and ordering assertions below.
31
- //
32
- // ★ HOISTED MOCKS, NOT HAND-ROLLED ONES. This file is in REGISTRY_ISOLATED_TESTS, so it already runs with
33
- // its own module registry — the hermeticity the `scopeModuleMocks` + `vi.doMock` + dynamic-import dance
34
- // bought by hand comes from the platform here, with no hook, and these stubs cannot reach the real
35
- // render-wgpu / scene2d-wgpu consumers. The dance was not merely redundant: it rebuilt the subject's
36
- // entire transitive module graph inside a FIXED `beforeAll` deadline — three modules plus everything they
37
- // import — which is unbounded work against a fixed clock and the shape of flake tiering exists to remove.
38
- //
39
- // ★ THE FRAME STUBS REACH THROUGH `actual`, NOT THROUGH AN OUTER BINDING. A hoisted factory runs during
40
- // this file's own import phase, so closing over a module-scope `const` declared below it would be a
41
- // temporal-dead-zone trap that only fires once the import order changes. `actual` is in hand already.
42
- vi.mock('./wgpuQuadBatchWriter', async (importOriginal) => {
43
- const actual = await importOriginal<typeof WgpuQuadBatchWriterModule>();
44
- return { ...actual, flushWgpuQuadBatchWriter: vi.fn() };
45
- });
46
- vi.mock('@flighthq/render-wgpu/contract', async (importOriginal) => {
47
- const actual = await importOriginal<typeof WgpuRenderWgpuModule>();
48
- const render = await import('@flighthq/render/contract');
49
- const types = await import('@flighthq/types/contract');
50
- const beginWgpuFrame = vi.fn((state: WgpuRenderState) => {
51
- actual.getWgpuRenderStateRuntime(state).commandEncoder = {} as GPUCommandEncoder;
52
- });
53
- const submitWgpuRenderPass = vi.fn((state: WgpuRenderState) => {
54
- actual.getWgpuRenderStateRuntime(state).commandEncoder = null;
55
- });
56
- return {
57
- ...actual,
58
- beginWgpuFrame,
59
- beginWgpuRenderPass: vi.fn(),
60
- createWgpuOffscreenRenderState: vi.fn((deviceState, pipeline, options = {}) => {
61
- const state = render.createRenderState({
62
- allowSmoothing: options.imageSmoothingEnabled ?? true,
63
- pixelRatio: options.pixelRatio ?? 1,
64
- roundPixels: options.roundPixels ?? false,
65
- sceneGraphSyncPolicy: options.sceneGraphSyncPolicy,
66
- }) as WgpuRenderState;
67
- Object.assign(state, {
68
- applyBlendMode: null,
69
- device: deviceState.device,
70
- deviceState,
71
- format: options.format ?? 'bgra8unorm',
72
- pipeline,
73
- });
74
- const runtime = actual.createWgpuRenderStateRuntime(deviceState, pipeline);
75
- state[types.EntityRuntimeKey] = runtime;
76
- Object.assign(runtime, {
77
- commandEncoder: null,
78
- currentBlendMode: null,
79
- currentMaskDepth: 0,
80
- currentRenderTarget: null,
81
- depthStencilTexture: null,
82
- particleInstanceBuffer: null,
83
- quadBatchWriterBufferPool: [],
84
- renderPass: null,
85
- retiredBuffers: [],
86
- retiredTextures: [],
87
- surfaceAntialiasTexture: null,
88
- uniformBuffer: { destroy: vi.fn() } as unknown as GPUBuffer,
89
- uniformData: new Float32Array(0),
90
- uniformOffset: 0,
91
- });
92
- return state;
93
- }),
94
- setWgpuRenderTransform2D: vi.fn(),
95
- createWgpuRenderTarget: vi.fn(
96
- (_state: unknown, width: number, height: number): WgpuRenderTarget => ({
97
- bindings: new Map(),
98
- mipLevelCount: 1,
99
- colorSpace: 'srgb',
100
- depthStencilTexture: {} as GPUTexture,
101
- depthStencilView: {} as GPUTextureView,
102
- texture: {} as GPUTexture,
103
- view: {} as GPUTextureView,
104
- format: 'bgra8unorm',
105
- sampleCount: 1,
106
- clearColors: [],
107
- clearDepth: 1,
108
- width,
109
- height,
110
- }),
111
- ),
112
- destroyWgpuRenderTarget: vi.fn(),
113
- drawWgpuRenderTargetResult: vi.fn(),
114
- endWgpuRenderPass: vi.fn(),
115
- resizeWgpuRenderTarget: vi.fn((_state: unknown, target: WgpuRenderTarget, width: number, height: number) => {
116
- target.width = width;
117
- target.height = height;
118
- }),
119
- submitWgpuRenderPass,
120
- withWgpuFrameBorrow: vi.fn((owner: WgpuRenderState, borrower: WgpuRenderState, callback: () => unknown) => {
121
- const ownerRuntime = actual.getWgpuRenderStateRuntime(owner);
122
- const borrowerRuntime = actual.getWgpuRenderStateRuntime(borrower);
123
- const ownsFrame = ownerRuntime.commandEncoder === null;
124
- if (ownsFrame) beginWgpuFrame(owner);
125
- borrowerRuntime.commandEncoder = ownerRuntime.commandEncoder;
126
- try {
127
- return callback();
128
- } finally {
129
- borrowerRuntime.commandEncoder = null;
130
- if (ownsFrame) submitWgpuRenderPass(owner);
131
- }
132
- }),
133
- };
134
- });
135
- vi.mock('./wgpuNode2D', async (importOriginal) => {
136
- const actual = await importOriginal<typeof WgpuNode2DModule>();
137
- return { ...actual, renderWgpuScene2D: vi.fn() };
138
- });
139
-
140
- import {
141
- beginWgpuFrame,
142
- createEmptyWgpuRegistries,
143
- createWgpuDeviceState,
144
- createWgpuPipeline,
145
- createWgpuRenderStateRuntime,
146
- destroyWgpuRenderState,
147
- destroyWgpuRenderTarget,
148
- drawWgpuRenderTargetResult,
149
- getWgpuMaterialRenderer,
150
- getWgpuRenderStateRuntime,
151
- registerWgpuMaterialRenderer,
152
- resolveWgpuApplyBlendMode,
153
- submitWgpuRenderPass,
154
- } from '@flighthq/render-wgpu/contract';
155
-
156
24
  import {
157
25
  createWgpuCacheState,
158
26
  defaultWgpuRenderCacheRenderer,
@@ -162,14 +30,120 @@ import {
162
30
  refreshWgpuRenderCache,
163
31
  releaseWgpuRenderCache,
164
32
  } from './wgpuCache';
165
- import { renderWgpuScene2D } from './wgpuNode2D';
166
- import { flushWgpuQuadBatchWriter } from './wgpuQuadBatchWriter';
33
+ import * as wgpuNode2D from './wgpuNode2D';
34
+ import * as wgpuQuadBatchWriter from './wgpuQuadBatchWriter';
35
+
36
+ // The GPU render-target lifecycle (@flighthq/render-wgpu) and the two local collaborators
37
+ // ./wgpuQuadBatchWriter and ./wgpuNode2D are stubbed so cache orchestration can be unit-tested without a
38
+ // real GPU pipeline: createWgpuRenderTarget returns a plain descriptor, and the composite, batch-flush
39
+ // and subtree-render calls become spies for the call and ordering assertions below.
40
+ beforeEach(() => {
41
+ vi.spyOn(wgpuQuadBatchWriter, 'flushWgpuQuadBatchWriter').mockImplementation((() => {}) as never);
42
+
43
+ const beginWgpuFrameSpy = vi.spyOn(renderWgpu, 'beginWgpuFrame').mockImplementation(((state: WgpuRenderState) => {
44
+ renderWgpu.getWgpuRenderStateRuntime(state).commandEncoder = {} as GPUCommandEncoder;
45
+ }) as never);
46
+ const submitWgpuRenderPassSpy = vi.spyOn(renderWgpu, 'submitWgpuRenderPass').mockImplementation(((
47
+ state: WgpuRenderState,
48
+ ) => {
49
+ renderWgpu.getWgpuRenderStateRuntime(state).commandEncoder = null;
50
+ }) as never);
51
+ vi.spyOn(renderWgpu, 'beginWgpuRenderPass').mockImplementation((() => {}) as never);
52
+ vi.spyOn(renderWgpu, 'createWgpuOffscreenRenderState').mockImplementation(((
53
+ deviceState: any,
54
+ pipeline: any,
55
+ options: any = {},
56
+ ) => {
57
+ const state = createRenderState({
58
+ allowSmoothing: options.imageSmoothingEnabled ?? true,
59
+ pixelRatio: options.pixelRatio ?? 1,
60
+ roundPixels: options.roundPixels ?? false,
61
+ sceneGraphSyncPolicy: options.sceneGraphSyncPolicy,
62
+ }) as WgpuRenderState;
63
+ Object.assign(state, {
64
+ applyBlendMode: null,
65
+ device: deviceState.device,
66
+ deviceState,
67
+ format: options.format ?? 'bgra8unorm',
68
+ pipeline,
69
+ });
70
+ const runtime = renderWgpu.createWgpuRenderStateRuntime(deviceState, pipeline);
71
+ state[EntityRuntimeKey] = runtime;
72
+ Object.assign(runtime, {
73
+ commandEncoder: null,
74
+ currentBlendMode: null,
75
+ currentMaskDepth: 0,
76
+ currentRenderTarget: null,
77
+ depthStencilTexture: null,
78
+ particleInstanceBuffer: null,
79
+ quadBatchWriterBufferPool: [],
80
+ renderPass: null,
81
+ retiredBuffers: [],
82
+ retiredTextures: [],
83
+ surfaceAntialiasTexture: null,
84
+ uniformBuffer: { destroy: vi.fn() } as unknown as GPUBuffer,
85
+ uniformData: new Float32Array(0),
86
+ uniformOffset: 0,
87
+ });
88
+ return state;
89
+ }) as never);
90
+ vi.spyOn(renderWgpu, 'setWgpuRenderTransform2D').mockImplementation((() => {}) as never);
91
+ vi.spyOn(renderWgpu, 'createWgpuRenderTarget').mockImplementation(
92
+ ((_state: unknown, width: number, height: number): WgpuRenderTarget => ({
93
+ bindings: new Map(),
94
+ mipLevelCount: 1,
95
+ colorSpace: 'srgb',
96
+ depthStencilTexture: {} as GPUTexture,
97
+ depthStencilView: {} as GPUTextureView,
98
+ texture: {} as GPUTexture,
99
+ view: {} as GPUTextureView,
100
+ format: 'bgra8unorm',
101
+ sampleCount: 1,
102
+ clearColors: [],
103
+ clearDepth: 1,
104
+ width,
105
+ height,
106
+ })) as never,
107
+ );
108
+ vi.spyOn(renderWgpu, 'destroyWgpuRenderTarget').mockImplementation((() => {}) as never);
109
+ vi.spyOn(renderWgpu, 'drawWgpuRenderTargetResult').mockImplementation((() => {}) as never);
110
+ vi.spyOn(renderWgpu, 'endWgpuRenderPass').mockImplementation((() => {}) as never);
111
+ vi.spyOn(renderWgpu, 'resizeWgpuRenderTarget').mockImplementation(((
112
+ _state: unknown,
113
+ target: WgpuRenderTarget,
114
+ width: number,
115
+ height: number,
116
+ ) => {
117
+ target.width = width;
118
+ target.height = height;
119
+ }) as never);
120
+ vi.spyOn(renderWgpu, 'withWgpuFrameBorrow').mockImplementation(((
121
+ owner: WgpuPresentationRenderState,
122
+ borrower: WgpuRenderState,
123
+ callback: () => unknown,
124
+ ) => {
125
+ const ownerRuntime = renderWgpu.getWgpuRenderStateRuntime(owner);
126
+ const borrowerRuntime = renderWgpu.getWgpuRenderStateRuntime(borrower);
127
+ const ownsFrame = ownerRuntime.commandEncoder === null;
128
+ if (ownsFrame) beginWgpuFrameSpy(owner);
129
+ borrowerRuntime.commandEncoder = ownerRuntime.commandEncoder;
130
+ try {
131
+ return callback();
132
+ } finally {
133
+ borrowerRuntime.commandEncoder = null;
134
+ if (ownsFrame) submitWgpuRenderPassSpy(owner);
135
+ }
136
+ }) as never);
137
+ vi.spyOn(wgpuNode2D, 'renderWgpuScene2D').mockImplementation((() => {}) as never);
138
+ });
139
+
140
+ afterEach(() => vi.restoreAllMocks());
167
141
 
168
142
  function fakeScreen(options = {}): WgpuPresentationRenderState {
169
143
  const state = createRenderState(options) as unknown as WgpuPresentationRenderState;
170
144
  const device = {} as GPUDevice;
171
- const deviceState = createWgpuDeviceState(device);
172
- const pipeline = createWgpuPipeline(createEmptyWgpuRegistries());
145
+ const deviceState = renderWgpu.createWgpuDeviceState(device);
146
+ const pipeline = renderWgpu.createWgpuPipeline(renderWgpu.createEmptyWgpuRegistries());
173
147
  Object.assign(state, {
174
148
  context: {} as GPUCanvasContext,
175
149
  device,
@@ -178,8 +152,8 @@ function fakeScreen(options = {}): WgpuPresentationRenderState {
178
152
  pipeline,
179
153
  surface: { height: 600, width: 800 },
180
154
  });
181
- state[EntityRuntimeKey] = createWgpuRenderStateRuntime(deviceState, pipeline);
182
- const runtime = getWgpuRenderStateRuntime(state);
155
+ state[EntityRuntimeKey] = renderWgpu.createWgpuRenderStateRuntime(deviceState, pipeline);
156
+ const runtime = renderWgpu.getWgpuRenderStateRuntime(state);
183
157
  runtime.commandEncoder = null;
184
158
  runtime.currentBlendMode = null;
185
159
  return state;
@@ -189,7 +163,7 @@ function createCacheState(screen: WgpuPresentationRenderState): WgpuRenderState
189
163
  return createWgpuCacheState(
190
164
  screen,
191
165
  screen.deviceState,
192
- createWgpuPipeline(getWgpuRenderStateRuntime(screen).registries),
166
+ renderWgpu.createWgpuPipeline(renderWgpu.getWgpuRenderStateRuntime(screen).registries),
193
167
  {
194
168
  format: screen.format,
195
169
  imageSmoothingEnabled: screen.allowSmoothing,
@@ -208,25 +182,25 @@ describe('createWgpuCacheState', () => {
208
182
  it('does not destroy a uniform buffer owned by the screen state', () => {
209
183
  const screen = fakeScreen();
210
184
  const destroyUniformBuffer = vi.fn();
211
- const screenRuntime = getWgpuRenderStateRuntime(screen);
185
+ const screenRuntime = renderWgpu.getWgpuRenderStateRuntime(screen);
212
186
  screenRuntime.uniformBuffer = { destroy: destroyUniformBuffer } as unknown as GPUBuffer;
213
187
  screenRuntime.quadBatchWriterBufferPool = [];
214
188
 
215
189
  const cacheState = createCacheState(screen);
216
- destroyWgpuRenderState(cacheState);
190
+ renderWgpu.destroyWgpuRenderState(cacheState);
217
191
 
218
192
  expect(destroyUniformBuffer).not.toHaveBeenCalled();
219
193
  });
220
194
 
221
195
  it('does not retain the device tier when an owned cache state is left undisposed', () => {
222
196
  const screen = fakeScreen();
223
- const screenRuntime = getWgpuRenderStateRuntime(screen);
197
+ const screenRuntime = renderWgpu.getWgpuRenderStateRuntime(screen);
224
198
  const teardown = vi.fn();
225
199
  screenRuntime.context.teardowns.push(teardown);
226
200
  screenRuntime.quadBatchWriterBufferPool = [];
227
201
 
228
202
  createCacheState(screen);
229
- destroyWgpuRenderState(screen);
203
+ renderWgpu.destroyWgpuRenderState(screen);
230
204
 
231
205
  expect(teardown).toHaveBeenCalledOnce();
232
206
  });
@@ -241,14 +215,14 @@ describe('createWgpuCacheState', () => {
241
215
 
242
216
  expect(cacheState.applyBlendMode).toBeNull();
243
217
  expect(Object.getOwnPropertyDescriptor(cacheState, 'applyBlendMode')?.get).toBeUndefined();
244
- expect(resolveWgpuApplyBlendMode(cacheState)).toBeNull();
218
+ expect(renderWgpu.resolveWgpuApplyBlendMode(cacheState)).toBeNull();
245
219
  screen.applyBlendMode = screenHook;
246
220
  expect(cacheState.applyBlendMode).toBeNull();
247
- expect(resolveWgpuApplyBlendMode(cacheState)).toBe(screenHook);
221
+ expect(renderWgpu.resolveWgpuApplyBlendMode(cacheState)).toBe(screenHook);
248
222
 
249
223
  cacheState.applyBlendMode = cacheHook;
250
224
  screen.applyBlendMode = laterScreenHook;
251
- expect(resolveWgpuApplyBlendMode(cacheState)).toBe(cacheHook);
225
+ expect(renderWgpu.resolveWgpuApplyBlendMode(cacheState)).toBe(cacheHook);
252
226
  });
253
227
 
254
228
  it('copies renderers and shares the GPU device but keeps its own node map', () => {
@@ -262,7 +236,7 @@ describe('createWgpuCacheState', () => {
262
236
  };
263
237
  const colorAdjustmentFeatureGuard: WgpuColorAdjustmentMaterialFeatureGuard = vi.fn();
264
238
  const renderRootGuard: RenderRootGuard = vi.fn();
265
- const screenRuntime = getWgpuRenderStateRuntime(screen);
239
+ const screenRuntime = renderWgpu.getWgpuRenderStateRuntime(screen);
266
240
  screenRuntime.registries.colorAdjustments = {
267
241
  entry: { state: RegistryEntryState.Bound, value: resolver },
268
242
  onMiss: 'Disabled',
@@ -290,21 +264,21 @@ describe('createWgpuCacheState', () => {
290
264
  enableColorAdjustmentGuards(screen);
291
265
  enableWgpuRenderCache(screen);
292
266
  const cacheState = createCacheState(screen);
293
- expect(getWgpuRenderStateRuntime(cacheState).registries.renderers.entries.get(RenderCacheKind)).toEqual({
267
+ expect(renderWgpu.getWgpuRenderStateRuntime(cacheState).registries.renderers.entries.get(RenderCacheKind)).toEqual({
294
268
  state: 'bound',
295
269
  value: defaultWgpuRenderCacheRenderer,
296
270
  });
297
271
  expect((cacheState as any).device).toBe((screen as any).device);
298
- expect(getWgpuRenderStateRuntime(cacheState).renderProxyMap).not.toBe(
299
- getWgpuRenderStateRuntime(screen).renderProxyMap,
272
+ expect(renderWgpu.getWgpuRenderStateRuntime(cacheState).renderProxyMap).not.toBe(
273
+ renderWgpu.getWgpuRenderStateRuntime(screen).renderProxyMap,
300
274
  );
301
- expect(getWgpuRenderStateRuntime(cacheState).registries.colorAdjustments).toBe(
275
+ expect(renderWgpu.getWgpuRenderStateRuntime(cacheState).registries.colorAdjustments).toBe(
302
276
  screenRuntime.registries.colorAdjustments,
303
277
  );
304
- expect(getWgpuRenderStateRuntime(cacheState).registries.colorAdjustmentFeature).toBe(
278
+ expect(renderWgpu.getWgpuRenderStateRuntime(cacheState).registries.colorAdjustmentFeature).toBe(
305
279
  screenRuntime.registries.colorAdjustmentFeature,
306
280
  );
307
- const cacheRuntime = getWgpuRenderStateRuntime(cacheState);
281
+ const cacheRuntime = renderWgpu.getWgpuRenderStateRuntime(cacheState);
308
282
  expect(cacheRuntime.registries.colorAdjustmentFeatureGuard).toBe(
309
283
  screenRuntime.registries.colorAdjustmentFeatureGuard,
310
284
  );
@@ -343,11 +317,11 @@ describe('createWgpuCacheState', () => {
343
317
  const screen = fakeScreen();
344
318
  const first: WgpuMaterialRenderer = { instanceFloatCount: 0, getShaderModule: vi.fn() };
345
319
  const replacement: WgpuMaterialRenderer = { instanceFloatCount: 0, getShaderModule: vi.fn() };
346
- registerWgpuMaterialRenderer(screen, 'acme.Material', first);
320
+ renderWgpu.registerWgpuMaterialRenderer(screen, 'acme.Material', first);
347
321
 
348
322
  const cacheState = createCacheState(screen);
349
- const screenRuntime = getWgpuRenderStateRuntime(screen);
350
- const cacheRuntime = getWgpuRenderStateRuntime(cacheState);
323
+ const screenRuntime = renderWgpu.getWgpuRenderStateRuntime(screen);
324
+ const cacheRuntime = renderWgpu.getWgpuRenderStateRuntime(cacheState);
351
325
  expect(cacheRuntime.registries).not.toBe(screenRuntime.registries);
352
326
  expect(cacheRuntime.registries.colorAdjustments).toBe(screenRuntime.registries.colorAdjustments);
353
327
  expect(cacheRuntime.registries.compressedTextureDecoder).toBe(screenRuntime.registries.compressedTextureDecoder);
@@ -360,12 +334,12 @@ describe('createWgpuCacheState', () => {
360
334
  expect(cacheRuntime.registries.strokeTessellator).toBe(screenRuntime.registries.strokeTessellator);
361
335
  expect(cacheRuntime.registries.textureResolvers).toBe(screenRuntime.registries.textureResolvers);
362
336
  expect(cacheRuntime.registries.velocityWriters).toBe(screenRuntime.registries.velocityWriters);
363
- expect(getWgpuMaterialRenderer(cacheState, 'acme.Material')).toBe(first);
337
+ expect(renderWgpu.getWgpuMaterialRenderer(cacheState, 'acme.Material')).toBe(first);
364
338
 
365
- registerWgpuMaterialRenderer(screen, 'acme.Material', replacement);
339
+ renderWgpu.registerWgpuMaterialRenderer(screen, 'acme.Material', replacement);
366
340
 
367
- expect(getWgpuMaterialRenderer(screen, 'acme.Material')).toBe(replacement);
368
- expect(getWgpuMaterialRenderer(cacheState, 'acme.Material')).toBe(first);
341
+ expect(renderWgpu.getWgpuMaterialRenderer(screen, 'acme.Material')).toBe(replacement);
342
+ expect(renderWgpu.getWgpuMaterialRenderer(cacheState, 'acme.Material')).toBe(first);
369
343
  });
370
344
  });
371
345
 
@@ -373,7 +347,7 @@ describe('defaultWgpuRenderCacheRenderer', () => {
373
347
  it('does nothing when no cache is attached to the source', () => {
374
348
  const state = fakeScreen();
375
349
  defaultWgpuRenderCacheRenderer.submit(state, makeCacheNode(createDisplayObject()));
376
- expect(drawWgpuRenderTargetResult).not.toHaveBeenCalled();
350
+ expect(renderWgpu.drawWgpuRenderTargetResult).not.toHaveBeenCalled();
377
351
  });
378
352
 
379
353
  it('composites the cache target attached to the source node', () => {
@@ -383,7 +357,12 @@ describe('defaultWgpuRenderCacheRenderer', () => {
383
357
  useRenderCache(state, obj, cache);
384
358
  const target = ensureWgpuRenderCacheTarget(state, cache, 16, 16);
385
359
  defaultWgpuRenderCacheRenderer.submit(state, makeCacheNode(obj));
386
- expect(drawWgpuRenderTargetResult).toHaveBeenCalledWith(state, expect.anything(), target, expect.anything());
360
+ expect(renderWgpu.drawWgpuRenderTargetResult).toHaveBeenCalledWith(
361
+ state,
362
+ expect.anything(),
363
+ target,
364
+ expect.anything(),
365
+ );
387
366
  });
388
367
 
389
368
  it('flushes pending batched geometry before the immediate composite', () => {
@@ -396,9 +375,9 @@ describe('defaultWgpuRenderCacheRenderer', () => {
396
375
  // The composite draws an immediate quad outside the quad-batch writer; geometry submitted earlier in
397
376
  // the walk must be drained first, or the immediate quad interleaves with the un-flushed batch's
398
377
  // instance buffer and bind-group state and corrupts it.
399
- expect(flushWgpuQuadBatchWriter).toHaveBeenCalledWith(state);
400
- expect((flushWgpuQuadBatchWriter as any).mock.invocationCallOrder[0]).toBeLessThan(
401
- (drawWgpuRenderTargetResult as any).mock.invocationCallOrder[0],
378
+ expect(wgpuQuadBatchWriter.flushWgpuQuadBatchWriter).toHaveBeenCalledWith(state);
379
+ expect((wgpuQuadBatchWriter.flushWgpuQuadBatchWriter as any).mock.invocationCallOrder[0]).toBeLessThan(
380
+ (renderWgpu.drawWgpuRenderTargetResult as any).mock.invocationCallOrder[0],
402
381
  );
403
382
  });
404
383
  });
@@ -407,7 +386,7 @@ describe('enableWgpuRenderCache', () => {
407
386
  it('registers the renderer for the render cache kind', () => {
408
387
  const state = fakeScreen();
409
388
  enableWgpuRenderCache(state);
410
- expect(getWgpuRenderStateRuntime(state).registries.renderers.entries.get(RenderCacheKind)).toEqual({
389
+ expect(renderWgpu.getWgpuRenderStateRuntime(state).registries.renderers.entries.get(RenderCacheKind)).toEqual({
411
390
  state: 'bound',
412
391
  value: defaultWgpuRenderCacheRenderer,
413
392
  });
@@ -440,17 +419,17 @@ describe('ensureWgpuRenderCacheTarget', () => {
440
419
 
441
420
  it('enumerates and destroys every owned target during state teardown', () => {
442
421
  const state = fakeScreen();
443
- const runtime = getWgpuRenderStateRuntime(state);
422
+ const runtime = renderWgpu.getWgpuRenderStateRuntime(state);
444
423
  runtime.quadBatchWriterBufferPool = [];
445
424
  const firstCache = createRenderCache();
446
425
  const secondCache = createRenderCache();
447
426
  const first = ensureWgpuRenderCacheTarget(state, firstCache, 8, 8);
448
427
  const second = ensureWgpuRenderCacheTarget(state, secondCache, 16, 16);
449
428
 
450
- destroyWgpuRenderState(state);
429
+ renderWgpu.destroyWgpuRenderState(state);
451
430
 
452
- expect(destroyWgpuRenderTarget).toHaveBeenCalledWith(state, first);
453
- expect(destroyWgpuRenderTarget).toHaveBeenCalledWith(state, second);
431
+ expect(renderWgpu.destroyWgpuRenderTarget).toHaveBeenCalledWith(state, first);
432
+ expect(renderWgpu.destroyWgpuRenderTarget).toHaveBeenCalledWith(state, second);
454
433
  expect(getWgpuRenderCacheTarget(state, firstCache)).toBeNull();
455
434
  expect(getWgpuRenderCacheTarget(state, secondCache)).toBeNull();
456
435
  });
@@ -474,22 +453,22 @@ describe('refreshWgpuRenderCache', () => {
474
453
  const screen = fakeScreen();
475
454
  const cacheState = createCacheState(screen);
476
455
  refreshWgpuRenderCache(screen, cacheState, createRenderCache(), createDisplayObject(), { padding: 5 });
477
- expect(beginWgpuFrame).toHaveBeenCalledWith(screen);
478
- expect(submitWgpuRenderPass).toHaveBeenCalledWith(screen);
479
- expect(getWgpuRenderStateRuntime(screen).commandEncoder).toBeNull();
456
+ expect(renderWgpu.beginWgpuFrame).toHaveBeenCalledWith(screen);
457
+ expect(renderWgpu.submitWgpuRenderPass).toHaveBeenCalledWith(screen);
458
+ expect(renderWgpu.getWgpuRenderStateRuntime(screen).commandEncoder).toBeNull();
480
459
  });
481
460
 
482
461
  it('records into an active application frame without submitting it', () => {
483
462
  const screen = fakeScreen();
484
463
  const encoder = {} as GPUCommandEncoder;
485
- getWgpuRenderStateRuntime(screen).commandEncoder = encoder;
464
+ renderWgpu.getWgpuRenderStateRuntime(screen).commandEncoder = encoder;
486
465
  const cacheState = createCacheState(screen);
487
- vi.mocked(beginWgpuFrame).mockClear();
488
- vi.mocked(submitWgpuRenderPass).mockClear();
466
+ vi.mocked(renderWgpu.beginWgpuFrame).mockClear();
467
+ vi.mocked(renderWgpu.submitWgpuRenderPass).mockClear();
489
468
  refreshWgpuRenderCache(screen, cacheState, createRenderCache(), createDisplayObject(), { padding: 5 });
490
- expect(beginWgpuFrame).not.toHaveBeenCalled();
491
- expect(submitWgpuRenderPass).not.toHaveBeenCalled();
492
- expect(getWgpuRenderStateRuntime(screen).commandEncoder).toBe(encoder);
469
+ expect(renderWgpu.beginWgpuFrame).not.toHaveBeenCalled();
470
+ expect(renderWgpu.submitWgpuRenderPass).not.toHaveBeenCalled();
471
+ expect(renderWgpu.getWgpuRenderStateRuntime(screen).commandEncoder).toBe(encoder);
493
472
  });
494
473
 
495
474
  it('bakes on the first call and allocates the target on the screen state', () => {
@@ -499,7 +478,7 @@ describe('refreshWgpuRenderCache', () => {
499
478
  const obj = createDisplayObject();
500
479
  const rebaked = refreshWgpuRenderCache(screen, cacheState, cache, obj, { padding: 5 });
501
480
  expect(rebaked).toBe(true);
502
- expect(renderWgpuScene2D).toHaveBeenCalled();
481
+ expect(wgpuNode2D.renderWgpuScene2D).toHaveBeenCalled();
503
482
  const target = getWgpuRenderCacheTarget(screen, cache);
504
483
  expect(target).not.toBeNull();
505
484
  expect(target!.width).toBe(10);
@@ -521,7 +500,7 @@ describe('releaseWgpuRenderCache', () => {
521
500
  const cache = createRenderCache();
522
501
  const target = ensureWgpuRenderCacheTarget(state, cache, 8, 8);
523
502
  releaseWgpuRenderCache(state, cache);
524
- expect(destroyWgpuRenderTarget).toHaveBeenCalledWith(state, target);
503
+ expect(renderWgpu.destroyWgpuRenderTarget).toHaveBeenCalledWith(state, target);
525
504
  expect(getWgpuRenderCacheTarget(state, cache)).toBeNull();
526
505
  });
527
506
  });
@@ -1,4 +1,4 @@
1
- import type * as FlightNodeModule from '@flighthq/node/contract';
1
+ import * as flightNode from '@flighthq/node/contract';
2
2
  import { getWgpuRenderStateRuntime } from '@flighthq/render-wgpu/contract';
3
3
  import { createWgpuRenderStateForTest, installWgpuMock, renderWgpuBackground } from '@flighthq/render-wgpu/contract';
4
4
  import { enableRenderRegistryGuards, explainRenderRegistryMisses } from '@flighthq/render/contract';
@@ -12,23 +12,25 @@ import {
12
12
  import type { RenderProxy2D } from '@flighthq/types/contract';
13
13
  import { BatchFormat, RenderRegistry } from '@flighthq/types/contract';
14
14
 
15
- // ★ A HOISTED MOCK, NOT A HAND-ROLLED ONE. This file is in REGISTRY_ISOLATED_TESTS, so it already runs
16
- // with its own module registry — the hermeticity the `scopeModuleMocks` + `vi.doMock` + dynamic-import
17
- // dance bought by hand comes from the platform here, with no hook. The dance was not merely redundant:
18
- // it rebuilt the subject's entire transitive module graph inside a FIXED `beforeAll` deadline, which is
19
- // unbounded work against a fixed clock and the shape of flake that tiering exists to remove.
20
- vi.mock('@flighthq/node/contract', async (importOriginal) => ({
21
- ...(await importOriginal<typeof FlightNodeModule>()),
22
- getNodeLocalBoundsRectangle: () => ({ x: 0, y: 0, width: 64, height: 48 }),
23
- getNodeLocalContentRevision: (source: { data?: { version?: number } } | null | undefined) =>
24
- source?.data?.version ?? 0,
25
- }));
26
-
27
15
  import { defaultWgpuMeshShapeRenderer, drawWgpuMeshShape } from './wgpuMeshShapeRenderer';
28
16
  import { registerWgpuShapeRasterizer } from './wgpuShapeRasterizer';
29
17
 
30
18
  beforeAll(() => installWgpuMock());
31
19
 
20
+ beforeEach(() => {
21
+ vi.spyOn(flightNode, 'getNodeLocalBoundsRectangle').mockImplementation((() => ({
22
+ x: 0,
23
+ y: 0,
24
+ width: 64,
25
+ height: 48,
26
+ })) as never);
27
+ vi.spyOn(flightNode, 'getNodeLocalContentRevision').mockImplementation(
28
+ ((source: { data?: { version?: number } } | null | undefined) => source?.data?.version ?? 0) as never,
29
+ );
30
+ });
31
+
32
+ afterEach(() => vi.restoreAllMocks());
33
+
32
34
  function makeShapeData() {
33
35
  return {
34
36
  surface: null,
@@ -1,5 +1,5 @@
1
1
  import { createImageResource } from '@flighthq/image/contract';
2
- import type * as FlightNodeModule from '@flighthq/node/contract';
2
+ import * as flightNode from '@flighthq/node/contract';
3
3
  import { getWgpuRenderStateRuntime } from '@flighthq/render-wgpu/contract';
4
4
  import { createWgpuRenderStateForTest, installWgpuMock, renderWgpuBackground } from '@flighthq/render-wgpu/contract';
5
5
  import {
@@ -12,24 +12,24 @@ import { appendShapeBeginFill, appendShapeEndFill, appendShapeRectangle, createS
12
12
  import type { RenderProxy2D } from '@flighthq/types/contract';
13
13
  import { BatchFormat, RenderRegistry } from '@flighthq/types/contract';
14
14
 
15
- // ★ A HOISTED MOCK, NOT A HAND-ROLLED ONE. This file is in REGISTRY_ISOLATED_TESTS, so it already runs
16
- // with its own module registry — the hermeticity the `scopeModuleMocks` + `vi.doMock` + dynamic-import
17
- // dance bought by hand comes from the platform here, with no hook. The dance was not merely redundant:
18
- // it rebuilt the subject's entire transitive module graph inside a FIXED `beforeAll` deadline, which is
19
- // unbounded work against a fixed clock and the shape of flake that tiering exists to remove.
20
- vi.mock('@flighthq/node/contract', async (importOriginal) => ({
21
- ...(await importOriginal<typeof FlightNodeModule>()),
22
- getNodeLocalBoundsRectangle: () => ({ x: 0, y: 0, width: 64, height: 48 }),
23
- getNodeLocalContentRevision: (source: { data?: { version?: number } } | null | undefined) =>
24
- source?.data?.version ?? 0,
25
- }));
26
-
27
15
  import { defaultWgpuRasterShapeRenderer, drawWgpuRasterShape } from './wgpuRasterShapeRenderer';
28
16
  import { registerWgpuShapeRasterizer } from './wgpuShapeRasterizer';
29
17
  import { registerWgpuStandardMaterial } from './wgpuStandardMaterial';
30
18
 
31
19
  beforeAll(() => installWgpuMock());
32
20
 
21
+ beforeEach(() => {
22
+ vi.spyOn(flightNode, 'getNodeLocalBoundsRectangle').mockImplementation((() => ({
23
+ x: 0,
24
+ y: 0,
25
+ width: 64,
26
+ height: 48,
27
+ })) as never);
28
+ vi.spyOn(flightNode, 'getNodeLocalContentRevision').mockImplementation(
29
+ ((source: { data?: { version?: number } } | null | undefined) => source?.data?.version ?? 0) as never,
30
+ );
31
+ });
32
+
33
33
  beforeEach(() => {
34
34
  setRaster2DSurfaceProvider({
35
35
  createRaster2DSurface(width, height) {
@@ -59,6 +59,7 @@ beforeEach(() => {
59
59
  });
60
60
 
61
61
  afterEach(() => {
62
+ vi.restoreAllMocks();
62
63
  resetRaster2DSurfaceProviderForTest();
63
64
  });
64
65
 
@@ -1,5 +1,5 @@
1
1
  import { createImageResource } from '@flighthq/image/contract';
2
- import type * as FlightNodeModule from '@flighthq/node/contract';
2
+ import * as flightNode from '@flighthq/node/contract';
3
3
  import { renderWgpuBackground, submitWgpuRenderPass } from '@flighthq/render-wgpu/contract';
4
4
  import { getWgpuRenderStateRuntime } from '@flighthq/render-wgpu/contract';
5
5
  import { createWgpuRenderStateForTest, installWgpuMock } from '@flighthq/render-wgpu/contract';
@@ -18,22 +18,6 @@ import type { RenderProxy2D } from '@flighthq/types/contract';
18
18
  import { BatchFormat, PathCommand } from '@flighthq/types/contract';
19
19
 
20
20
  import { enableWgpuStrokePathTessellation } from './enableWgpuStrokePathTessellation';
21
- // @flighthq/node's bounds/revision queries expect a real BoundsNode; these tests drive drawWgpuShape with
22
- // lightweight fake proxies, so the two queries are stubbed.
23
- //
24
- // ★ A HOISTED MOCK, NOT A HAND-ROLLED ONE. This file is in REGISTRY_ISOLATED_TESTS, so it already runs
25
- // with its own module registry — the hermeticity the `scopeModuleMocks` + `vi.doMock` + dynamic-import
26
- // dance bought by hand comes from the platform here, with no hook, and the stub cannot reach the many
27
- // real consumers of these functions (node, interaction, shape, text). The dance was not merely
28
- // redundant: it rebuilt the subject's entire transitive module graph inside a FIXED `beforeAll`
29
- // deadline, which is unbounded work against a fixed clock and the shape of flake tiering exists to remove.
30
- vi.mock('@flighthq/node/contract', async (importOriginal) => ({
31
- ...(await importOriginal<typeof FlightNodeModule>()),
32
- getNodeLocalBoundsRectangle: () => ({ x: 0, y: 0, width: 64, height: 48 }),
33
- getNodeLocalContentRevision: (source: { data?: { version?: number } } | null | undefined) =>
34
- source?.data?.version ?? 0,
35
- }));
36
-
37
21
  import { defaultWgpuMorphShapeRenderer, defaultWgpuShapeRenderer, drawWgpuShape } from './wgpuShape';
38
22
  import { registerWgpuShapeRasterizer } from './wgpuShapeRasterizer';
39
23
  import { registerWgpuStandardMaterial } from './wgpuStandardMaterial';
@@ -42,6 +26,20 @@ const noopRasterizer = (): void => {};
42
26
 
43
27
  beforeAll(() => installWgpuMock());
44
28
 
29
+ // @flighthq/node's bounds/revision queries expect a real BoundsNode; these tests drive drawWgpuShape with
30
+ // lightweight fake proxies, so the two queries are stubbed.
31
+ beforeEach(() => {
32
+ vi.spyOn(flightNode, 'getNodeLocalBoundsRectangle').mockImplementation((() => ({
33
+ x: 0,
34
+ y: 0,
35
+ width: 64,
36
+ height: 48,
37
+ })) as never);
38
+ vi.spyOn(flightNode, 'getNodeLocalContentRevision').mockImplementation(
39
+ ((source: { data?: { version?: number } } | null | undefined) => source?.data?.version ?? 0) as never,
40
+ );
41
+ });
42
+
45
43
  beforeEach(() => {
46
44
  setRaster2DSurfaceProvider({
47
45
  createRaster2DSurface(width, height) {
@@ -71,6 +69,7 @@ beforeEach(() => {
71
69
  });
72
70
 
73
71
  afterEach(() => {
72
+ vi.restoreAllMocks();
74
73
  resetRaster2DSurfaceProviderForTest();
75
74
  });
76
75
 
@@ -4,42 +4,36 @@ import { getWgpuRenderStateRuntime } from '@flighthq/render-wgpu/contract';
4
4
  import { createWgpuRenderStateForTest, installWgpuMock } from '@flighthq/render-wgpu/contract';
5
5
  import { resetRaster2DSurfaceProviderForTest, setRaster2DSurfaceProvider } from '@flighthq/render/contract';
6
6
  import { createTextLabel } from '@flighthq/text/contract';
7
+ import * as textlayout from '@flighthq/textlayout/contract';
7
8
  import type { Raster2DSurface, RenderProxy2D } from '@flighthq/types/contract';
8
9
  import { BatchFormat } from '@flighthq/types/contract';
9
10
 
10
- // @flighthq/textlayout.computeTextLayout is stubbed to emit one deterministic glyph group.
11
- //
12
- // ★ A HOISTED MOCK, NOT A HAND-ROLLED ONE. This file is in REGISTRY_ISOLATED_TESTS, so it already runs
13
- // with its own module registry — the hermeticity the `scopeModuleMocks` + `vi.doMock` + dynamic-import
14
- // dance bought by hand comes from the platform here, with no hook, and the stub cannot reach the real
15
- // text-layout consumers. The dance was not merely redundant: it rebuilt the subject's entire transitive
16
- // module graph inside a FIXED `beforeAll` deadline, which is unbounded work against a fixed clock and
17
- // the shape of flake tiering exists to remove.
18
- vi.mock('@flighthq/textlayout/contract', async (importOriginal) => {
19
- const actual = (await importOriginal()) as Record<string, unknown>;
20
- return {
21
- ...actual,
22
- computeTextLayout: vi.fn((result: { groups: object[] }, params: { formatRanges: Array<{ format: object }> }) => {
23
- result.groups.push({
24
- offsetX: 0,
25
- offsetY: 0,
26
- width: 50,
27
- ascent: 12,
28
- descent: 4,
29
- format: params.formatRanges[0]?.format ?? {},
30
- startIndex: 0,
31
- endIndex: 5,
32
- });
33
- }),
34
- };
35
- });
36
-
37
11
  import { registerWgpuStandardMaterial } from './wgpuStandardMaterial';
38
12
  import { defaultWgpuTextLabelRenderer, drawWgpuTextLabel } from './wgpuTextLabel';
39
13
 
40
14
  beforeAll(() => installWgpuMock());
41
15
 
16
+ // @flighthq/textlayout.computeTextLayout is stubbed to emit one deterministic glyph group.
17
+ beforeEach(() => {
18
+ vi.spyOn(textlayout, 'computeTextLayout').mockImplementation(((
19
+ result: { groups: object[] },
20
+ params: { formatRanges: Array<{ format: object }> },
21
+ ) => {
22
+ result.groups.push({
23
+ offsetX: 0,
24
+ offsetY: 0,
25
+ width: 50,
26
+ ascent: 12,
27
+ descent: 4,
28
+ format: params.formatRanges[0]?.format ?? {},
29
+ startIndex: 0,
30
+ endIndex: 5,
31
+ });
32
+ }) as never);
33
+ });
34
+
42
35
  afterEach(() => {
36
+ vi.restoreAllMocks();
43
37
  resetRaster2DSurfaceProviderForTest();
44
38
  });
45
39