@flighthq/effects-wgpu 0.5.1-next.1069.554a2ac → 0.5.1-next.1201.9b49dee

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.
Files changed (194) hide show
  1. package/README.md +2 -2
  2. package/dist/wgpuBevelEffect.d.ts +2 -2
  3. package/dist/wgpuBevelEffect.d.ts.map +1 -1
  4. package/dist/wgpuBevelEffect.js +7 -7
  5. package/dist/wgpuBevelEffect.js.map +1 -1
  6. package/dist/wgpuBitmapDisplacementEffect.d.ts +2 -2
  7. package/dist/wgpuBitmapDisplacementEffect.d.ts.map +1 -1
  8. package/dist/wgpuBitmapDisplacementEffect.js.map +1 -1
  9. package/dist/wgpuBlendEffect.d.ts +4 -4
  10. package/dist/wgpuBlendEffect.d.ts.map +1 -1
  11. package/dist/wgpuBlendEffect.js.map +1 -1
  12. package/dist/wgpuBloomEffect.d.ts +2 -2
  13. package/dist/wgpuBloomEffect.d.ts.map +1 -1
  14. package/dist/wgpuBloomEffect.js +7 -7
  15. package/dist/wgpuBloomEffect.js.map +1 -1
  16. package/dist/wgpuBlurEffect.d.ts +3 -3
  17. package/dist/wgpuBlurEffect.d.ts.map +1 -1
  18. package/dist/wgpuBlurEffect.js +5 -5
  19. package/dist/wgpuBlurEffect.js.map +1 -1
  20. package/dist/wgpuCameraMotionBlurEffect.d.ts +2 -2
  21. package/dist/wgpuCameraMotionBlurEffect.d.ts.map +1 -1
  22. package/dist/wgpuCameraMotionBlurEffect.js.map +1 -1
  23. package/dist/wgpuChromaticAberrationEffect.d.ts +2 -2
  24. package/dist/wgpuChromaticAberrationEffect.d.ts.map +1 -1
  25. package/dist/wgpuChromaticAberrationEffect.js.map +1 -1
  26. package/dist/wgpuColorLutPass.d.ts +2 -2
  27. package/dist/wgpuColorLutPass.d.ts.map +1 -1
  28. package/dist/wgpuColorLutPass.js.map +1 -1
  29. package/dist/wgpuColorMatrixPass.d.ts +2 -2
  30. package/dist/wgpuColorMatrixPass.d.ts.map +1 -1
  31. package/dist/wgpuColorMatrixPass.js.map +1 -1
  32. package/dist/wgpuCompositeEffect.d.ts +2 -2
  33. package/dist/wgpuCompositeEffect.d.ts.map +1 -1
  34. package/dist/wgpuCompositeEffect.js.map +1 -1
  35. package/dist/wgpuContactShadowsEffect.d.ts +2 -2
  36. package/dist/wgpuContactShadowsEffect.d.ts.map +1 -1
  37. package/dist/wgpuContactShadowsEffect.js.map +1 -1
  38. package/dist/wgpuConvolutionEffect.d.ts +2 -2
  39. package/dist/wgpuConvolutionEffect.d.ts.map +1 -1
  40. package/dist/wgpuConvolutionEffect.js.map +1 -1
  41. package/dist/wgpuCrtEffect.d.ts +2 -2
  42. package/dist/wgpuCrtEffect.d.ts.map +1 -1
  43. package/dist/wgpuCrtEffect.js.map +1 -1
  44. package/dist/wgpuDirectionalBlurEffect.d.ts +2 -2
  45. package/dist/wgpuDirectionalBlurEffect.d.ts.map +1 -1
  46. package/dist/wgpuDirectionalBlurEffect.js.map +1 -1
  47. package/dist/wgpuDisplacementEffect.d.ts +2 -2
  48. package/dist/wgpuDisplacementEffect.d.ts.map +1 -1
  49. package/dist/wgpuDisplacementEffect.js.map +1 -1
  50. package/dist/wgpuDitherEffect.d.ts +2 -2
  51. package/dist/wgpuDitherEffect.d.ts.map +1 -1
  52. package/dist/wgpuDitherEffect.js.map +1 -1
  53. package/dist/wgpuDropShadowEffect.d.ts +2 -2
  54. package/dist/wgpuDropShadowEffect.d.ts.map +1 -1
  55. package/dist/wgpuDropShadowEffect.js +7 -7
  56. package/dist/wgpuDropShadowEffect.js.map +1 -1
  57. package/dist/wgpuEffectBlitShader.d.ts +4 -4
  58. package/dist/wgpuEffectBlitShader.d.ts.map +1 -1
  59. package/dist/wgpuEffectBlitShader.js.map +1 -1
  60. package/dist/wgpuEffectBoxBlur.d.ts +2 -2
  61. package/dist/wgpuEffectBoxBlur.d.ts.map +1 -1
  62. package/dist/wgpuEffectBoxBlur.js.map +1 -1
  63. package/dist/wgpuEffectPass.d.ts +5 -5
  64. package/dist/wgpuEffectPass.d.ts.map +1 -1
  65. package/dist/wgpuEffectPass.js +14 -11
  66. package/dist/wgpuEffectPass.js.map +1 -1
  67. package/dist/wgpuEffectTexelScale.d.ts +3 -2
  68. package/dist/wgpuEffectTexelScale.d.ts.map +1 -1
  69. package/dist/wgpuEffectTexelScale.js +8 -2
  70. package/dist/wgpuEffectTexelScale.js.map +1 -1
  71. package/dist/wgpuEffectTintShader.d.ts +4 -4
  72. package/dist/wgpuEffectTintShader.d.ts.map +1 -1
  73. package/dist/wgpuEffectTintShader.js.map +1 -1
  74. package/dist/wgpuFilmGrainEffect.d.ts +2 -2
  75. package/dist/wgpuFilmGrainEffect.d.ts.map +1 -1
  76. package/dist/wgpuFilmGrainEffect.js.map +1 -1
  77. package/dist/wgpuFxaaEffect.d.ts +2 -2
  78. package/dist/wgpuFxaaEffect.d.ts.map +1 -1
  79. package/dist/wgpuFxaaEffect.js.map +1 -1
  80. package/dist/wgpuGlitchEffect.d.ts +2 -2
  81. package/dist/wgpuGlitchEffect.d.ts.map +1 -1
  82. package/dist/wgpuGlitchEffect.js.map +1 -1
  83. package/dist/wgpuGodRaysEffect.d.ts +2 -2
  84. package/dist/wgpuGodRaysEffect.d.ts.map +1 -1
  85. package/dist/wgpuGodRaysEffect.js.map +1 -1
  86. package/dist/wgpuGradientBevelEffect.d.ts +2 -2
  87. package/dist/wgpuGradientBevelEffect.d.ts.map +1 -1
  88. package/dist/wgpuGradientBevelEffect.js +7 -7
  89. package/dist/wgpuGradientBevelEffect.js.map +1 -1
  90. package/dist/wgpuGradientGlowEffect.d.ts +2 -2
  91. package/dist/wgpuGradientGlowEffect.d.ts.map +1 -1
  92. package/dist/wgpuGradientGlowEffect.js +7 -7
  93. package/dist/wgpuGradientGlowEffect.js.map +1 -1
  94. package/dist/wgpuHalftoneEffect.d.ts +2 -2
  95. package/dist/wgpuHalftoneEffect.d.ts.map +1 -1
  96. package/dist/wgpuHalftoneEffect.js.map +1 -1
  97. package/dist/wgpuInnerGlowEffect.d.ts +2 -2
  98. package/dist/wgpuInnerGlowEffect.d.ts.map +1 -1
  99. package/dist/wgpuInnerGlowEffect.js +7 -7
  100. package/dist/wgpuInnerGlowEffect.js.map +1 -1
  101. package/dist/wgpuInnerShadowEffect.d.ts +2 -2
  102. package/dist/wgpuInnerShadowEffect.d.ts.map +1 -1
  103. package/dist/wgpuInnerShadowEffect.js +7 -7
  104. package/dist/wgpuInnerShadowEffect.js.map +1 -1
  105. package/dist/wgpuKuwaharaEffect.d.ts +2 -2
  106. package/dist/wgpuKuwaharaEffect.d.ts.map +1 -1
  107. package/dist/wgpuKuwaharaEffect.js.map +1 -1
  108. package/dist/wgpuLensDirtEffect.d.ts +2 -2
  109. package/dist/wgpuLensDirtEffect.d.ts.map +1 -1
  110. package/dist/wgpuLensDirtEffect.js +7 -7
  111. package/dist/wgpuLensDirtEffect.js.map +1 -1
  112. package/dist/wgpuLensDistortionEffect.d.ts +2 -2
  113. package/dist/wgpuLensDistortionEffect.d.ts.map +1 -1
  114. package/dist/wgpuLensDistortionEffect.js.map +1 -1
  115. package/dist/wgpuLensFlareEffect.d.ts +2 -2
  116. package/dist/wgpuLensFlareEffect.d.ts.map +1 -1
  117. package/dist/wgpuLensFlareEffect.js.map +1 -1
  118. package/dist/wgpuMedianEffect.d.ts +2 -2
  119. package/dist/wgpuMedianEffect.d.ts.map +1 -1
  120. package/dist/wgpuMedianEffect.js.map +1 -1
  121. package/dist/wgpuMotionBlurEffect.d.ts +2 -2
  122. package/dist/wgpuMotionBlurEffect.d.ts.map +1 -1
  123. package/dist/wgpuMotionBlurEffect.js.map +1 -1
  124. package/dist/wgpuOuterGlowEffect.d.ts +2 -2
  125. package/dist/wgpuOuterGlowEffect.d.ts.map +1 -1
  126. package/dist/wgpuOuterGlowEffect.js +7 -7
  127. package/dist/wgpuOuterGlowEffect.js.map +1 -1
  128. package/dist/wgpuOutlineEffect.d.ts +2 -2
  129. package/dist/wgpuOutlineEffect.d.ts.map +1 -1
  130. package/dist/wgpuOutlineEffect.js.map +1 -1
  131. package/dist/wgpuPixelateEffect.d.ts +2 -2
  132. package/dist/wgpuPixelateEffect.d.ts.map +1 -1
  133. package/dist/wgpuPixelateEffect.js.map +1 -1
  134. package/dist/wgpuPosterizeEffect.d.ts +2 -2
  135. package/dist/wgpuPosterizeEffect.d.ts.map +1 -1
  136. package/dist/wgpuPosterizeEffect.js.map +1 -1
  137. package/dist/wgpuRadialBlurEffect.d.ts +2 -2
  138. package/dist/wgpuRadialBlurEffect.d.ts.map +1 -1
  139. package/dist/wgpuRadialBlurEffect.js.map +1 -1
  140. package/dist/wgpuRenderEffectPipeline.d.ts +3 -3
  141. package/dist/wgpuRenderEffectPipeline.d.ts.map +1 -1
  142. package/dist/wgpuRenderEffectPipeline.js +58 -43
  143. package/dist/wgpuRenderEffectPipeline.js.map +1 -1
  144. package/dist/wgpuScanlinesEffect.d.ts +2 -2
  145. package/dist/wgpuScanlinesEffect.d.ts.map +1 -1
  146. package/dist/wgpuScanlinesEffect.js.map +1 -1
  147. package/dist/wgpuScreenSpaceFogEffect.d.ts +2 -2
  148. package/dist/wgpuScreenSpaceFogEffect.d.ts.map +1 -1
  149. package/dist/wgpuScreenSpaceFogEffect.js.map +1 -1
  150. package/dist/wgpuSharpenEffect.d.ts +2 -2
  151. package/dist/wgpuSharpenEffect.d.ts.map +1 -1
  152. package/dist/wgpuSharpenEffect.js.map +1 -1
  153. package/dist/wgpuSketchEffect.d.ts +2 -2
  154. package/dist/wgpuSketchEffect.d.ts.map +1 -1
  155. package/dist/wgpuSketchEffect.js.map +1 -1
  156. package/dist/wgpuSmaaEffect.d.ts +2 -2
  157. package/dist/wgpuSmaaEffect.d.ts.map +1 -1
  158. package/dist/wgpuSmaaEffect.js.map +1 -1
  159. package/dist/wgpuSsaoEffect.d.ts +2 -2
  160. package/dist/wgpuSsaoEffect.d.ts.map +1 -1
  161. package/dist/wgpuSsaoEffect.js.map +1 -1
  162. package/dist/wgpuTiltShiftEffect.d.ts +2 -2
  163. package/dist/wgpuTiltShiftEffect.d.ts.map +1 -1
  164. package/dist/wgpuTiltShiftEffect.js.map +1 -1
  165. package/dist/wgpuToneMapEffect.d.ts +2 -2
  166. package/dist/wgpuToneMapEffect.d.ts.map +1 -1
  167. package/dist/wgpuToneMapEffect.js.map +1 -1
  168. package/dist/wgpuVignetteEffect.d.ts +2 -2
  169. package/dist/wgpuVignetteEffect.d.ts.map +1 -1
  170. package/dist/wgpuVignetteEffect.js.map +1 -1
  171. package/dist/wgpuWhiteBalanceEffect.d.ts +2 -2
  172. package/dist/wgpuWhiteBalanceEffect.d.ts.map +1 -1
  173. package/dist/wgpuWhiteBalanceEffect.js.map +1 -1
  174. package/package.json +10 -10
  175. package/src/enableWgpuRenderEffectGuards.test.ts +8 -6
  176. package/src/wgpuBevelEffect.test.ts +13 -6
  177. package/src/wgpuBitmapDisplacementEffect.test.ts +8 -3
  178. package/src/wgpuBlendEffect.test.ts +3 -3
  179. package/src/wgpuColorLutPass.test.ts +7 -2
  180. package/src/wgpuColorMatrixPass.test.ts +2 -2
  181. package/src/wgpuDropShadowEffect.test.ts +2 -2
  182. package/src/wgpuEffectBlitShader.test.ts +3 -3
  183. package/src/wgpuEffectPass.test.ts +20 -18
  184. package/src/wgpuEffectTexelScale.test.ts +26 -2
  185. package/src/wgpuGodRaysEffect.test.ts +3 -3
  186. package/src/wgpuGradientBevelEffect.test.ts +14 -6
  187. package/src/wgpuHalftoneEffect.test.ts +3 -3
  188. package/src/wgpuInnerGlowEffect.test.ts +2 -2
  189. package/src/wgpuInnerShadowEffect.test.ts +2 -2
  190. package/src/wgpuLensDirtEffect.test.ts +7 -7
  191. package/src/wgpuLogicalEffectResolution.test.ts +12 -7
  192. package/src/wgpuOuterGlowEffect.test.ts +2 -2
  193. package/src/wgpuRadialBlurEffect.test.ts +3 -3
  194. package/src/wgpuRenderEffectPipeline.test.ts +71 -52
@@ -15,7 +15,7 @@ let nextTargetId = 0;
15
15
  beforeEach(() => {
16
16
  nextTargetId = 0;
17
17
 
18
- vi.spyOn(renderWgpuContractModule, 'acquireWgpuRenderTarget').mockImplementation(((
18
+ vi.spyOn(renderWgpuContractModule, 'acquireWgpuTextureRenderTarget').mockImplementation(((
19
19
  _state: never,
20
20
  _pool: never,
21
21
  descriptor: never,
@@ -24,7 +24,7 @@ beforeEach(() => {
24
24
  id: `scratch-${nextTargetId++}`,
25
25
  texture: {},
26
26
  })) as never);
27
- vi.spyOn(renderWgpuContractModule, 'releaseWgpuRenderTarget').mockImplementation((() => {}) as never);
27
+ vi.spyOn(renderWgpuContractModule, 'releaseWgpuTextureRenderTarget').mockImplementation((() => {}) as never);
28
28
  vi.spyOn(wgpuBlurEffectModule, 'applyGaussianBlurToWgpu').mockImplementation((() => {}) as never);
29
29
  vi.spyOn(wgpuEffectPassModule, 'createWgpuDualSourceEffectPipeline').mockReturnValue({ pipeline: {} } as never);
30
30
  vi.spyOn(wgpuEffectPassModule, 'drawWgpuDualSourceEffectPass').mockImplementation((() => {}) as never);
@@ -59,9 +59,9 @@ describe('applyLensDirtEffectToWgpu', () => {
59
59
  }),
60
60
  );
61
61
 
62
- expect(renderWgpuContractModule.acquireWgpuRenderTarget).toHaveBeenCalledTimes(3);
62
+ expect(renderWgpuContractModule.acquireWgpuTextureRenderTarget).toHaveBeenCalledTimes(3);
63
63
  const [bright, blurred, temp] = vi
64
- .mocked(renderWgpuContractModule.acquireWgpuRenderTarget)
64
+ .mocked(renderWgpuContractModule.acquireWgpuTextureRenderTarget)
65
65
  .mock.results.map((result) => result.value!);
66
66
  expect(wgpuEffectProgramCacheModule.getWgpuEffectPipeline).toHaveBeenCalledWith(
67
67
  state,
@@ -93,9 +93,9 @@ describe('applyLensDirtEffectToWgpu', () => {
93
93
  expect.anything(),
94
94
  expect.any(Function),
95
95
  );
96
- expect(renderWgpuContractModule.releaseWgpuRenderTarget).toHaveBeenNthCalledWith(1, pool, bright);
97
- expect(renderWgpuContractModule.releaseWgpuRenderTarget).toHaveBeenNthCalledWith(2, pool, blurred);
98
- expect(renderWgpuContractModule.releaseWgpuRenderTarget).toHaveBeenNthCalledWith(3, pool, temp);
96
+ expect(renderWgpuContractModule.releaseWgpuTextureRenderTarget).toHaveBeenNthCalledWith(1, pool, bright);
97
+ expect(renderWgpuContractModule.releaseWgpuTextureRenderTarget).toHaveBeenNthCalledWith(2, pool, blurred);
98
+ expect(renderWgpuContractModule.releaseWgpuTextureRenderTarget).toHaveBeenNthCalledWith(3, pool, temp);
99
99
 
100
100
  const brightUniforms = new Float32Array(4);
101
101
  vi.mocked(wgpuEffectPassModule.drawWgpuEffectPass).mock.calls[0]![4](
@@ -13,7 +13,8 @@ import {
13
13
  createSsaoEffect,
14
14
  createTiltShiftEffect,
15
15
  } from '@flighthq/effects/contract';
16
- import type { WgpuRenderState, WgpuRenderTarget } from '@flighthq/types/contract';
16
+ import type { WgpuRenderState, WgpuTextureRenderTarget } from '@flighthq/types/contract';
17
+ import { EntityRuntimeKey } from '@flighthq/types/contract';
17
18
 
18
19
  import * as wgpuEffectPassModule from './wgpuEffectPass';
19
20
  import * as wgpuEffectProgramCacheModule from './wgpuEffectProgramCache';
@@ -72,12 +73,16 @@ import { applyTiltShiftEffectToWgpu } from './wgpuTiltShiftEffect';
72
73
 
73
74
  type ApplyEffect = (
74
75
  state: WgpuRenderState,
75
- source: Readonly<WgpuRenderTarget>,
76
- dest: Readonly<WgpuRenderTarget>,
76
+ source: Readonly<WgpuTextureRenderTarget>,
77
+ dest: Readonly<WgpuTextureRenderTarget>,
77
78
  ) => void;
78
79
 
79
- const state = { surface: { height: 600, width: 800 } } as unknown as WgpuRenderState;
80
- const nativeTarget = { height: 600, sampleCount: 1, view: {}, width: 800 } as unknown as WgpuRenderTarget;
80
+ // The logical extent an effect measures its descriptor distances against is the open pass's viewport, so
81
+ // the stand-in state carries a runtime with that viewport rather than a surface.
82
+ const state = {
83
+ [EntityRuntimeKey]: { passStack: [{ viewport: { height: 600, width: 800 } }] },
84
+ } as unknown as WgpuRenderState;
85
+ const nativeTarget = { height: 600, sampleCount: 1, view: {}, width: 800 } as unknown as WgpuTextureRenderTarget;
81
86
  // Pool scratch targets preserve supersampled dimensions but have sampleCount 1; this is the discriminator
82
87
  // that prevents a tempting sampleCount-derived implementation from silently returning the wrong scale.
83
88
  const supersampledScratchTarget = {
@@ -85,7 +90,7 @@ const supersampledScratchTarget = {
85
90
  sampleCount: 1,
86
91
  view: {},
87
92
  width: 1600,
88
- } as unknown as WgpuRenderTarget;
93
+ } as unknown as WgpuTextureRenderTarget;
89
94
 
90
95
  const logicalEffects: ReadonlyArray<{
91
96
  readonly apply: ApplyEffect;
@@ -175,7 +180,7 @@ const physicalEffects: ReadonlyArray<{ readonly apply: ApplyEffect; readonly nam
175
180
  },
176
181
  ];
177
182
 
178
- function uploadedBy(apply: ApplyEffect, target: WgpuRenderTarget): readonly number[] {
183
+ function uploadedBy(apply: ApplyEffect, target: WgpuTextureRenderTarget): readonly number[] {
179
184
  recorded.uniforms.length = 0;
180
185
  apply(state, target, target);
181
186
  return recorded.uniforms[0]!;
@@ -16,7 +16,7 @@ let nextTargetId = 0;
16
16
  beforeEach(() => {
17
17
  nextTargetId = 0;
18
18
 
19
- vi.spyOn(renderWgpuContractModule, 'acquireWgpuRenderTarget').mockImplementation(((
19
+ vi.spyOn(renderWgpuContractModule, 'acquireWgpuTextureRenderTarget').mockImplementation(((
20
20
  _state: never,
21
21
  _pool: never,
22
22
  descriptor: never,
@@ -25,7 +25,7 @@ beforeEach(() => {
25
25
  id: `scratch-${nextTargetId++}`,
26
26
  texture: {},
27
27
  })) as never);
28
- vi.spyOn(renderWgpuContractModule, 'releaseWgpuRenderTarget').mockImplementation((() => {}) as never);
28
+ vi.spyOn(renderWgpuContractModule, 'releaseWgpuTextureRenderTarget').mockImplementation((() => {}) as never);
29
29
  vi.spyOn(wgpuEffectBlitShaderModule, 'applyWgpuEffectBlitPass').mockImplementation((() => {}) as never);
30
30
  vi.spyOn(wgpuEffectBlitShaderModule, 'applyWgpuEffectErasePass').mockImplementation((() => {}) as never);
31
31
  vi.spyOn(wgpuEffectBoxBlurModule, 'applyWgpuEffectBoxBlur').mockImplementation((() => {}) as never);
@@ -1,6 +1,6 @@
1
1
  import { createRadialBlurEffect } from '@flighthq/effects/contract';
2
2
  import { createWgpuRenderStateForTest, installWgpuMock } from '@flighthq/render-wgpu/contract';
3
- import type { RadialBlurEffect, WgpuRenderState, WgpuRenderTarget } from '@flighthq/types/contract';
3
+ import type { RadialBlurEffect, WgpuRenderState, WgpuTextureRenderTarget } from '@flighthq/types/contract';
4
4
 
5
5
  import * as wgpuEffectPassModule from './wgpuEffectPass';
6
6
  import * as wgpuEffectProgramCacheModule from './wgpuEffectProgramCache';
@@ -53,7 +53,7 @@ beforeAll(() => installWgpuMock());
53
53
  function apply(effect: Readonly<Partial<RadialBlurEffect>> = {}): readonly number[] {
54
54
  recorded.pipelines.length = 0;
55
55
  recorded.uniforms.length = 0;
56
- const target = { height: 64, view: {}, width: 64 } as unknown as WgpuRenderTarget;
56
+ const target = { height: 64, view: {}, width: 64 } as unknown as WgpuTextureRenderTarget;
57
57
  applyRadialBlurEffectToWgpu({} as unknown as WgpuRenderState, target, target, createRadialBlurEffect(effect));
58
58
  return recorded.uniforms[0]!;
59
59
  }
@@ -119,7 +119,7 @@ describe('applyRadialBlurEffectToWgpu', () => {
119
119
  describe('defaultWgpuRadialBlurEffectRunner', () => {
120
120
  it('routes the runner context through to the pass', () => {
121
121
  recorded.uniforms.length = 0;
122
- const target = { height: 8, view: {}, width: 8 } as unknown as WgpuRenderTarget;
122
+ const target = { height: 8, view: {}, width: 8 } as unknown as WgpuTextureRenderTarget;
123
123
 
124
124
  defaultWgpuRadialBlurEffectRunner(
125
125
  { dest: target, pool: {}, source: target, state: {} } as never,
@@ -1,6 +1,11 @@
1
1
  import { createColorLutCache } from '@flighthq/adjustments/contract';
2
2
  import { allocateEntity, finishEntity } from '@flighthq/entity/contract';
3
- import { beginWgpuFrame, createWgpuRenderStateForTest, installWgpuMock } from '@flighthq/render-wgpu/contract';
3
+ import {
4
+ beginWgpuScreenRenderPassForTest,
5
+ createWgpuRenderStateForTest,
6
+ endWgpuRenderPass,
7
+ installWgpuMock,
8
+ } from '@flighthq/render-wgpu/contract';
4
9
  import type { RenderEffect } from '@flighthq/types/contract';
5
10
  import { EntityRuntimeKey } from '@flighthq/types/contract';
6
11
 
@@ -22,71 +27,83 @@ describe('beginWgpuRenderEffectPipeline', () => {
22
27
  const state = await createWgpuRenderStateForTest();
23
28
  const pipeline = createWgpuRenderEffectPipeline(state);
24
29
 
25
- beginWgpuFrame(state);
26
- beginWgpuRenderEffectPipeline(state, pipeline);
30
+ const screenPass = beginWgpuScreenRenderPassForTest(state);
31
+ endWgpuRenderEffectPipeline(beginWgpuRenderEffectPipeline(screenPass, pipeline), pipeline, []);
27
32
  const first = pipeline.sceneTarget;
28
- endWgpuRenderEffectPipeline(state, pipeline, []);
29
-
30
- beginWgpuFrame(state);
31
- beginWgpuRenderEffectPipeline(state, pipeline);
33
+ endWgpuRenderEffectPipeline(beginWgpuRenderEffectPipeline(screenPass, pipeline), pipeline, []);
32
34
 
33
35
  expect(first).not.toBeNull();
34
36
  // The retained-target contract: begin resizes rather than reallocating, so a per-frame pipeline
35
37
  // does not churn GPU memory. A new object here would be a leak the pool cannot see.
36
38
  expect(pipeline.sceneTarget).toBe(first);
37
- endWgpuRenderEffectPipeline(state, pipeline, []);
39
+ endWgpuRenderPass(screenPass);
38
40
  });
39
41
 
40
42
  it('stamps the requested color space onto the scene target before the pass opens', async () => {
41
43
  const state = await createWgpuRenderStateForTest();
42
44
  const pipeline = createWgpuRenderEffectPipeline(state);
43
45
 
44
- beginWgpuFrame(state);
45
- beginWgpuRenderEffectPipeline(state, pipeline, 'linear');
46
+ const screenPass = beginWgpuScreenRenderPassForTest(state);
47
+ const scenePass = beginWgpuRenderEffectPipeline(screenPass, pipeline, undefined, 'linear');
46
48
 
47
49
  expect(pipeline.sceneTarget?.colorSpace).toBe('linear');
48
- endWgpuRenderEffectPipeline(state, pipeline, []);
50
+ endWgpuRenderEffectPipeline(scenePass, pipeline, []);
51
+ endWgpuRenderPass(screenPass);
49
52
  });
50
53
 
51
- it('packs the background quadruple into one 0xRRGGBBAA clear color', async () => {
54
+ // ★ THE CLEAR IS AN ARGUMENT, NOT A STATE PROPERTY. The scene target used to be cleared to
55
+ // state.backgroundColorRgba, which meant "what the frame is cleared to" was a value the render state
56
+ // carried around and every caller shared. It is per-pass data and now arrives as one.
57
+ it('clears the scene target to the colour it is given', async () => {
52
58
  const state = await createWgpuRenderStateForTest();
53
59
  const pipeline = createWgpuRenderEffectPipeline(state);
54
- // Quarter/half/three-quarter channels, chosen so a wrong byte order cannot coincide with the
55
- // right one — the ground truth is arithmetic here, not a value read back out of the source.
56
- state.backgroundColorRgba.splice(0, state.backgroundColorRgba.length, 0x40 / 255, 0x80 / 255, 0xc0 / 255, 1);
60
+ const screenPass = beginWgpuScreenRenderPassForTest(state);
61
+ const { getWgpuRenderStateRuntime } = await import('@flighthq/render-wgpu/contract');
62
+ const beginRenderPass = vi.spyOn(getWgpuRenderStateRuntime(state).commandEncoder!, 'beginRenderPass');
57
63
 
58
- beginWgpuFrame(state);
59
- beginWgpuRenderEffectPipeline(state, pipeline);
64
+ const scenePass = beginWgpuRenderEffectPipeline(screenPass, pipeline, {
65
+ color: [0x40 / 255, 0x80 / 255, 0xc0 / 255, 1],
66
+ depth: 1.0,
67
+ });
60
68
 
61
- expect(pipeline.sceneTarget?.clearColors).toEqual([0x4080c0ff]);
62
- endWgpuRenderEffectPipeline(state, pipeline, []);
69
+ const attachment = Array.from(beginRenderPass.mock.calls.at(-1)![0].colorAttachments)[0]!;
70
+ const clearValue = attachment.clearValue as GPUColorDict;
71
+ expect(clearValue.r).toBeCloseTo(0x40 / 255);
72
+ expect(clearValue.g).toBeCloseTo(0x80 / 255);
73
+ expect(clearValue.b).toBeCloseTo(0xc0 / 255);
74
+ expect(clearValue.a).toBe(1);
75
+ endWgpuRenderEffectPipeline(scenePass, pipeline, []);
76
+ endWgpuRenderPass(screenPass);
63
77
  });
64
78
 
65
- it('leaves the clear list empty when the background is not a full quadruple', async () => {
79
+ it('clears to transparent black when the caller names no colour', async () => {
66
80
  const state = await createWgpuRenderStateForTest();
67
81
  const pipeline = createWgpuRenderEffectPipeline(state);
68
- state.backgroundColorRgba.splice(0, state.backgroundColorRgba.length, 0.5, 0.5, 0.5);
82
+ const screenPass = beginWgpuScreenRenderPassForTest(state);
83
+ const { getWgpuRenderStateRuntime } = await import('@flighthq/render-wgpu/contract');
84
+ const beginRenderPass = vi.spyOn(getWgpuRenderStateRuntime(state).commandEncoder!, 'beginRenderPass');
69
85
 
70
- beginWgpuFrame(state);
71
- beginWgpuRenderEffectPipeline(state, pipeline);
86
+ const scenePass = beginWgpuRenderEffectPipeline(screenPass, pipeline);
72
87
 
73
- // Empty means "no background to composite" — a different frame than a transparent clear, and the
74
- // reason the target falls back to the render state's own background instead.
75
- expect(pipeline.sceneTarget?.clearColors).toEqual([]);
76
- endWgpuRenderEffectPipeline(state, pipeline, []);
88
+ const attachment = Array.from(beginRenderPass.mock.calls.at(-1)![0].colorAttachments)[0]!;
89
+ const clearValue = attachment.clearValue as GPUColorDict;
90
+ expect([clearValue.r, clearValue.g, clearValue.b, clearValue.a]).toEqual([0, 0, 0, 0]);
91
+ endWgpuRenderEffectPipeline(scenePass, pipeline, []);
92
+ endWgpuRenderPass(screenPass);
77
93
  });
78
94
 
79
95
  it('realizes a four-sample scene target at twice the canvas extent', async () => {
80
96
  const state = await createWgpuRenderStateForTest();
81
97
  const pipeline = createWgpuRenderEffectPipeline(state, { sampleCount: 4 });
82
98
 
83
- beginWgpuFrame(state);
84
- beginWgpuRenderEffectPipeline(state, pipeline);
99
+ const screenPass = beginWgpuScreenRenderPassForTest(state);
100
+ const scenePass = beginWgpuRenderEffectPipeline(screenPass, pipeline);
85
101
 
86
- expect(pipeline.sceneTarget?.width).toBe(state.surface.width * 2);
87
- expect(pipeline.sceneTarget?.height).toBe(state.surface.height * 2);
102
+ expect(pipeline.sceneTarget?.width).toBe(screenPass.viewport.width * 2);
103
+ expect(pipeline.sceneTarget?.height).toBe(screenPass.viewport.height * 2);
88
104
  expect(pipeline.sceneTarget?.sampleCount).toBe(4);
89
- endWgpuRenderEffectPipeline(state, pipeline, []);
105
+ endWgpuRenderEffectPipeline(scenePass, pipeline, []);
106
+ endWgpuRenderPass(screenPass);
90
107
  });
91
108
  });
92
109
 
@@ -155,9 +172,9 @@ describe('destroyWgpuRenderEffectPipeline', () => {
155
172
  it('releases the scene target and clears the LUT caches', async () => {
156
173
  const state = await createWgpuRenderStateForTest();
157
174
  const pipeline = createWgpuRenderEffectPipeline(state);
158
- beginWgpuFrame(state);
159
- beginWgpuRenderEffectPipeline(state, pipeline);
160
- endWgpuRenderEffectPipeline(state, pipeline, []);
175
+ const screenPass = beginWgpuScreenRenderPassForTest(state);
176
+ endWgpuRenderEffectPipeline(beginWgpuRenderEffectPipeline(screenPass, pipeline), pipeline, []);
177
+ endWgpuRenderPass(screenPass);
161
178
  expect(pipeline.sceneTarget).not.toBeNull();
162
179
 
163
180
  destroyWgpuRenderEffectPipeline(state, pipeline);
@@ -179,9 +196,9 @@ describe('destroyWgpuRenderEffectPipeline', () => {
179
196
  it('is idempotent — a second destroy neither throws nor resurrects state', async () => {
180
197
  const state = await createWgpuRenderStateForTest();
181
198
  const pipeline = createWgpuRenderEffectPipeline(state);
182
- beginWgpuFrame(state);
183
- beginWgpuRenderEffectPipeline(state, pipeline);
184
- endWgpuRenderEffectPipeline(state, pipeline, []);
199
+ const screenPass = beginWgpuScreenRenderPassForTest(state);
200
+ endWgpuRenderEffectPipeline(beginWgpuRenderEffectPipeline(screenPass, pipeline), pipeline, []);
201
+ endWgpuRenderPass(screenPass);
185
202
 
186
203
  destroyWgpuRenderEffectPipeline(state, pipeline);
187
204
  expect(() => destroyWgpuRenderEffectPipeline(state, pipeline)).not.toThrow();
@@ -196,8 +213,10 @@ describe('endWgpuRenderEffectPipeline', () => {
196
213
  const pool = pipeline.pool;
197
214
 
198
215
  // The early return is the only thing standing between an unbegun pipeline and endWgpuRenderPass
199
- // popping a pass that was never pushed, so it is asserted rather than assumed.
200
- expect(() => endWgpuRenderEffectPipeline(state, pipeline, [])).not.toThrow();
216
+ // closing a pass the pipeline never opened, so it is asserted rather than assumed.
217
+ const screenPass = beginWgpuScreenRenderPassForTest(state);
218
+ expect(() => endWgpuRenderEffectPipeline(screenPass, pipeline, [])).not.toThrow();
219
+ endWgpuRenderPass(screenPass);
201
220
  expect(pipeline.sceneTarget).toBeNull();
202
221
  expect(pipeline.pool).toBe(pool);
203
222
  });
@@ -206,9 +225,9 @@ describe('endWgpuRenderEffectPipeline', () => {
206
225
  const state = await createWgpuRenderStateForTest();
207
226
  const pipeline = createWgpuRenderEffectPipeline(state);
208
227
 
209
- beginWgpuFrame(state);
210
- beginWgpuRenderEffectPipeline(state, pipeline);
211
- endWgpuRenderEffectPipeline(state, pipeline, []);
228
+ const screenPass = beginWgpuScreenRenderPassForTest(state);
229
+ endWgpuRenderEffectPipeline(beginWgpuRenderEffectPipeline(screenPass, pipeline), pipeline, []);
230
+ endWgpuRenderPass(screenPass);
212
231
 
213
232
  // Every acquire must be matched by a release before end returns; a pool holding entries after an
214
233
  // empty chain would mean the ping-pong leaked a target on the no-op path.
@@ -226,9 +245,9 @@ describe('endWgpuRenderEffectPipeline', () => {
226
245
  })() as RenderEffect,
227
246
  ];
228
247
 
229
- beginWgpuFrame(state);
230
- beginWgpuRenderEffectPipeline(state, pipeline);
231
- endWgpuRenderEffectPipeline(state, pipeline, chain);
248
+ const screenPass = beginWgpuScreenRenderPassForTest(state);
249
+ endWgpuRenderEffectPipeline(beginWgpuRenderEffectPipeline(screenPass, pipeline), pipeline, chain);
250
+ endWgpuRenderPass(screenPass);
232
251
 
233
252
  // An unregistered kind is skipped, so the chain does no work — but the bracketing still has to
234
253
  // balance. This is the acquire/release invariant measured at its cheapest observable point.
@@ -256,18 +275,18 @@ describe('setWgpuRenderEffectPipelineSkipGuard', () => {
256
275
  ];
257
276
 
258
277
  setWgpuRenderEffectPipelineSkipGuard(state, (_state, kind) => dropped.push(kind));
259
- beginWgpuFrame(state);
260
- beginWgpuRenderEffectPipeline(state, pipeline);
261
- endWgpuRenderEffectPipeline(state, pipeline, chain);
278
+ const guarded = beginWgpuScreenRenderPassForTest(state);
279
+ endWgpuRenderEffectPipeline(beginWgpuRenderEffectPipeline(guarded, pipeline), pipeline, chain);
280
+ endWgpuRenderPass(guarded);
262
281
 
263
282
  expect(dropped).toEqual(['test.wgpu-pipeline-skip-seam']);
264
283
 
265
284
  // Clearing must restore the original silence exactly: the seam is the ONLY path by which a dropped
266
285
  // effect is observable, so a stale guard would be the difference between a diagnostic and a leak.
267
286
  setWgpuRenderEffectPipelineSkipGuard(state, null);
268
- beginWgpuFrame(state);
269
- beginWgpuRenderEffectPipeline(state, pipeline);
270
- endWgpuRenderEffectPipeline(state, pipeline, chain);
287
+ const silent = beginWgpuScreenRenderPassForTest(state);
288
+ endWgpuRenderEffectPipeline(beginWgpuRenderEffectPipeline(silent, pipeline), pipeline, chain);
289
+ endWgpuRenderPass(silent);
271
290
 
272
291
  expect(dropped).toEqual(['test.wgpu-pipeline-skip-seam']);
273
292
  });