@flighthq/render-wgpu 0.2.0 → 0.2.1-next.410.a23f189

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.
@@ -3,12 +3,13 @@ import { createMatrix } from '@flighthq/geometry';
3
3
  import { renderWgpuBackground, submitWgpuRenderPass } from './wgpuBackground';
4
4
  import { getWgpuRenderStateRuntime } from './wgpuRenderState';
5
5
  import {
6
- beginWgpuRenderTarget,
6
+ beginWgpuRenderPass,
7
7
  createWgpuRenderTarget,
8
8
  destroyWgpuRenderTarget,
9
9
  drawWgpuRenderTargetResult,
10
- endWgpuRenderTarget,
10
+ endWgpuRenderPass,
11
11
  resizeWgpuRenderTarget,
12
+ setWgpuRenderTransform2D,
12
13
  } from './wgpuRenderTarget';
13
14
  import { createWgpuRenderStateForTest, installWgpuMock } from './wgpuTestHelper';
14
15
 
@@ -16,31 +17,28 @@ beforeAll(() => {
16
17
  installWgpuMock();
17
18
  });
18
19
 
19
- describe('beginWgpuRenderTarget', () => {
20
+ describe('beginWgpuRenderPass', () => {
20
21
  it('sets the render target viewport', async () => {
21
22
  const state = await createWgpuRenderStateForTest();
22
23
  renderWgpuBackground(state);
23
24
  const target = createWgpuRenderTarget(state, 64, 64);
24
- beginWgpuRenderTarget(state, target, createMatrix());
25
+ beginWgpuRenderPass(state, target);
25
26
  expect(getWgpuRenderStateRuntime(state).renderTargetViewport?.width).toBe(64);
26
- endWgpuRenderTarget(state);
27
+ endWgpuRenderPass(state);
27
28
  submitWgpuRenderPass(state);
28
29
  });
29
- });
30
30
 
31
- describe('beginWgpuRenderTarget / endWgpuRenderTarget', () => {
32
- it('switches the render target and restores it', async () => {
31
+ it('switches the render target and restores it on end', async () => {
33
32
  const state = await createWgpuRenderStateForTest();
34
33
  renderWgpuBackground(state);
35
34
 
36
35
  const target = createWgpuRenderTarget(state, 128, 128);
37
- const transform = createMatrix();
38
- beginWgpuRenderTarget(state, target, transform);
36
+ beginWgpuRenderPass(state, target);
39
37
 
40
38
  const runtime = getWgpuRenderStateRuntime(state);
41
39
  expect(runtime.renderTargetViewport?.width).toBe(128);
42
40
 
43
- endWgpuRenderTarget(state);
41
+ endWgpuRenderPass(state);
44
42
  expect(runtime.renderTargetViewport).toBeNull();
45
43
 
46
44
  submitWgpuRenderPass(state);
@@ -94,13 +92,13 @@ describe('drawWgpuRenderTargetResult', () => {
94
92
  });
95
93
  });
96
94
 
97
- describe('endWgpuRenderTarget', () => {
95
+ describe('endWgpuRenderPass', () => {
98
96
  it('restores null renderTargetViewport', async () => {
99
97
  const state = await createWgpuRenderStateForTest();
100
98
  renderWgpuBackground(state);
101
99
  const target = createWgpuRenderTarget(state, 32, 32);
102
- beginWgpuRenderTarget(state, target, createMatrix());
103
- endWgpuRenderTarget(state);
100
+ beginWgpuRenderPass(state, target);
101
+ endWgpuRenderPass(state);
104
102
  expect(getWgpuRenderStateRuntime(state).renderTargetViewport).toBeNull();
105
103
  submitWgpuRenderPass(state);
106
104
  });
@@ -118,3 +116,23 @@ describe('resizeWgpuRenderTarget', () => {
118
116
  expect(target.bindGroup).not.toBe(previousBindGroup);
119
117
  });
120
118
  });
119
+
120
+ describe('setWgpuRenderTransform2D', () => {
121
+ it('installs a copy of the transform, restored by the enclosing pass', async () => {
122
+ const state = await createWgpuRenderStateForTest();
123
+ renderWgpuBackground(state);
124
+ const original = state.renderTransform2D;
125
+ const target = createWgpuRenderTarget(state, 32, 32);
126
+ const bake = createMatrix();
127
+ bake.tx = 42;
128
+
129
+ beginWgpuRenderPass(state, target);
130
+ setWgpuRenderTransform2D(state, bake);
131
+ expect(state.renderTransform2D?.tx).toBe(42);
132
+ expect(state.renderTransform2D).not.toBe(bake);
133
+ endWgpuRenderPass(state);
134
+
135
+ expect(state.renderTransform2D).toBe(original);
136
+ submitWgpuRenderPass(state);
137
+ });
138
+ });
@@ -1,4 +1,4 @@
1
- import { BlendMode } from '@flighthq/types';
1
+ import { AdvancedBlendMode, BlendMode } from '@flighthq/types';
2
2
 
3
3
  import { renderWgpuBackground } from './wgpuBackground';
4
4
  import { getWgpuRenderStateRuntime } from './wgpuRenderState';
@@ -81,11 +81,8 @@ describe('getWgpuPipeline', () => {
81
81
  operation: 'add',
82
82
  });
83
83
  expect(blendOf(BlendMode.Screen)).toEqual({ srcFactor: 'one', dstFactor: 'one-minus-src', operation: 'add' });
84
- expect(blendOf(BlendMode.Erase)).toEqual({ srcFactor: 'zero', dstFactor: 'one-minus-src-alpha', operation: 'add' });
85
- expect(blendOf(BlendMode.None)).toEqual({ srcFactor: 'one', dstFactor: 'zero', operation: 'add' });
86
84
  expect(blendOf(BlendMode.Darken).operation).toBe('min');
87
85
  expect(blendOf(BlendMode.Lighten).operation).toBe('max');
88
- expect(blendOf(BlendMode.Subtract).operation).toBe('reverse-subtract');
89
86
  });
90
87
 
91
88
  it('falls back to normal blend for shader-composited modes', async () => {
@@ -95,12 +92,12 @@ describe('getWgpuPipeline', () => {
95
92
  ...(getWgpuPipeline(state, mode, 'normal') as unknown as { __descriptor: GPURenderPipelineDescriptor })
96
93
  .__descriptor.fragment!.targets,
97
94
  ][0]!.blend!.color;
98
- expect(blendOf(BlendMode.Overlay)).toEqual({
95
+ expect(blendOf(AdvancedBlendMode.Overlay)).toEqual({
99
96
  srcFactor: 'one',
100
97
  dstFactor: 'one-minus-src-alpha',
101
98
  operation: 'add',
102
99
  });
103
- expect(blendOf(BlendMode.HardLight)).toEqual({
100
+ expect(blendOf(AdvancedBlendMode.HardLight)).toEqual({
104
101
  srcFactor: 'one',
105
102
  dstFactor: 'one-minus-src-alpha',
106
103
  operation: 'add',
@@ -0,0 +1,60 @@
1
+ import type { ImageResource } from '@flighthq/types';
2
+
3
+ import { uploadWgpuTextureData, uploadWgpuTextureElement, uploadWgpuTextureImageResource } from './wgpuTextureUpload';
4
+
5
+ // A device whose queue records the two upload calls so a test can assert which path ran and with what.
6
+ function makeDevice(): GPUDevice {
7
+ return {
8
+ queue: { writeTexture: vi.fn(), copyExternalImageToTexture: vi.fn() },
9
+ } as unknown as GPUDevice;
10
+ }
11
+
12
+ describe('uploadWgpuTextureData', () => {
13
+ it('drives writeTexture with a tightly-packed rgba8 layout (bytesPerRow = width*4)', () => {
14
+ const device = makeDevice();
15
+ const texture = {} as GPUTexture;
16
+ const data = new Uint8ClampedArray(2 * 2 * 4);
17
+ uploadWgpuTextureData(device, texture, [0, 0, 3], 2, 2, data);
18
+ expect(device.queue.writeTexture).toHaveBeenCalledWith(
19
+ { texture, origin: [0, 0, 3] },
20
+ data,
21
+ { bytesPerRow: 8, rowsPerImage: 2 },
22
+ [2, 2, 1],
23
+ );
24
+ });
25
+ });
26
+
27
+ describe('uploadWgpuTextureElement', () => {
28
+ it('drives copyExternalImageToTexture with the external source', () => {
29
+ const device = makeDevice();
30
+ const texture = {} as GPUTexture;
31
+ const source = {} as GPUCopyExternalImageSource;
32
+ uploadWgpuTextureElement(device, texture, [0, 0, 0], 4, 4, source);
33
+ expect(device.queue.copyExternalImageToTexture).toHaveBeenCalledWith(
34
+ { source },
35
+ { texture, origin: [0, 0, 0] },
36
+ [4, 4, 1],
37
+ );
38
+ });
39
+ });
40
+
41
+ describe('uploadWgpuTextureImageResource', () => {
42
+ it('takes the element path when the resource carries a source', () => {
43
+ const device = makeDevice();
44
+ const texture = {} as GPUTexture;
45
+ const image = { source: {} as CanvasImageSource, data: null, width: 4, height: 4 } as ImageResource;
46
+ uploadWgpuTextureImageResource(device, texture, [0, 0, 0], image);
47
+ expect(device.queue.copyExternalImageToTexture).toHaveBeenCalledTimes(1);
48
+ expect(device.queue.writeTexture).not.toHaveBeenCalled();
49
+ });
50
+
51
+ it('takes the raw-pixel path when the resource is data-only', () => {
52
+ const device = makeDevice();
53
+ const texture = {} as GPUTexture;
54
+ const data = new Uint8ClampedArray(4 * 4 * 4);
55
+ const image = { source: null, data, width: 4, height: 4 } as ImageResource;
56
+ uploadWgpuTextureImageResource(device, texture, [0, 0, 0], image);
57
+ expect(device.queue.writeTexture).toHaveBeenCalledTimes(1);
58
+ expect(device.queue.copyExternalImageToTexture).not.toHaveBeenCalled();
59
+ });
60
+ });