@flighthq/render-wgpu 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (79) hide show
  1. package/dist/index.d.ts +17 -0
  2. package/dist/index.d.ts.map +1 -0
  3. package/dist/index.js +16 -0
  4. package/dist/index.js.map +1 -0
  5. package/dist/wgpuAdapterCapabilities.d.ts +3 -0
  6. package/dist/wgpuAdapterCapabilities.d.ts.map +1 -0
  7. package/dist/wgpuAdapterCapabilities.js +28 -0
  8. package/dist/wgpuAdapterCapabilities.js.map +1 -0
  9. package/dist/wgpuBackground.d.ts +4 -0
  10. package/dist/wgpuBackground.d.ts.map +1 -0
  11. package/dist/wgpuBackground.js +110 -0
  12. package/dist/wgpuBackground.js.map +1 -0
  13. package/dist/wgpuDraw.d.ts +21 -0
  14. package/dist/wgpuDraw.d.ts.map +1 -0
  15. package/dist/wgpuDraw.js +153 -0
  16. package/dist/wgpuDraw.js.map +1 -0
  17. package/dist/wgpuElement.d.ts +2 -0
  18. package/dist/wgpuElement.d.ts.map +1 -0
  19. package/dist/wgpuElement.js +9 -0
  20. package/dist/wgpuElement.js.map +1 -0
  21. package/dist/wgpuFullscreenPass.d.ts +5 -0
  22. package/dist/wgpuFullscreenPass.d.ts.map +1 -0
  23. package/dist/wgpuFullscreenPass.js +106 -0
  24. package/dist/wgpuFullscreenPass.js.map +1 -0
  25. package/dist/wgpuMaterialRegistry.d.ts +5 -0
  26. package/dist/wgpuMaterialRegistry.d.ts.map +1 -0
  27. package/dist/wgpuMaterialRegistry.js +27 -0
  28. package/dist/wgpuMaterialRegistry.js.map +1 -0
  29. package/dist/wgpuRenderState.d.ts +7 -0
  30. package/dist/wgpuRenderState.d.ts.map +1 -0
  31. package/dist/wgpuRenderState.js +153 -0
  32. package/dist/wgpuRenderState.js.map +1 -0
  33. package/dist/wgpuRenderTarget.d.ts +19 -0
  34. package/dist/wgpuRenderTarget.d.ts.map +1 -0
  35. package/dist/wgpuRenderTarget.js +142 -0
  36. package/dist/wgpuRenderTarget.js.map +1 -0
  37. package/dist/wgpuRenderTargetPool.d.ts +10 -0
  38. package/dist/wgpuRenderTargetPool.d.ts.map +1 -0
  39. package/dist/wgpuRenderTargetPool.js +32 -0
  40. package/dist/wgpuRenderTargetPool.js.map +1 -0
  41. package/dist/wgpuScissor.d.ts +5 -0
  42. package/dist/wgpuScissor.d.ts.map +1 -0
  43. package/dist/wgpuScissor.js +37 -0
  44. package/dist/wgpuScissor.js.map +1 -0
  45. package/dist/wgpuShader.d.ts +43 -0
  46. package/dist/wgpuShader.d.ts.map +1 -0
  47. package/dist/wgpuShader.js +304 -0
  48. package/dist/wgpuShader.js.map +1 -0
  49. package/dist/wgpuShaderBinding.d.ts +5 -0
  50. package/dist/wgpuShaderBinding.d.ts.map +1 -0
  51. package/dist/wgpuShaderBinding.js +28 -0
  52. package/dist/wgpuShaderBinding.js.map +1 -0
  53. package/dist/wgpuShaderRegistry.d.ts +3 -0
  54. package/dist/wgpuShaderRegistry.d.ts.map +1 -0
  55. package/dist/wgpuShaderRegistry.js +8 -0
  56. package/dist/wgpuShaderRegistry.js.map +1 -0
  57. package/dist/wgpuSurface.d.ts +6 -0
  58. package/dist/wgpuSurface.d.ts.map +1 -0
  59. package/dist/wgpuSurface.js +107 -0
  60. package/dist/wgpuSurface.js.map +1 -0
  61. package/dist/wgpuTestHelper.d.ts +4 -0
  62. package/dist/wgpuTestHelper.d.ts.map +1 -0
  63. package/dist/wgpuTestHelper.js +137 -0
  64. package/dist/wgpuTestHelper.js.map +1 -0
  65. package/package.json +42 -0
  66. package/src/wgpuAdapterCapabilities.test.ts +49 -0
  67. package/src/wgpuBackground.test.ts +52 -0
  68. package/src/wgpuDraw.test.ts +174 -0
  69. package/src/wgpuElement.test.ts +21 -0
  70. package/src/wgpuFullscreenPass.test.ts +64 -0
  71. package/src/wgpuMaterialRegistry.test.ts +56 -0
  72. package/src/wgpuRenderState.test.ts +88 -0
  73. package/src/wgpuRenderTarget.test.ts +120 -0
  74. package/src/wgpuRenderTargetPool.test.ts +58 -0
  75. package/src/wgpuScissor.test.ts +97 -0
  76. package/src/wgpuShader.test.ts +140 -0
  77. package/src/wgpuShaderBinding.test.ts +62 -0
  78. package/src/wgpuShaderRegistry.test.ts +30 -0
  79. package/src/wgpuSurface.test.ts +49 -0
@@ -0,0 +1,304 @@
1
+ import { BlendMode } from '@flighthq/types';
2
+ import { getWgpuRenderStateRuntime } from './wgpuRenderState';
3
+ // ---- WGSL source ----
4
+ // Uniform buffer layout (per-draw slot in the ring, 256-byte aligned):
5
+ // offset 0–47 : mat3x3f matrix (3 columns × 16 bytes each due to vec3 padding)
6
+ // offset 48 : f32 alpha
7
+ // offset 52 : u32 hasColorTransform
8
+ // offset 56–63 : 2× f32 padding
9
+ // offset 64–79 : vec4f colorMultiplier
10
+ // offset 80–95 : vec4f colorOffset
11
+ // offset 96–111: f32 x0, y0, x1, y1 (quad pixel-space corners)
12
+ // offset 112–127: f32 u0, v0, u1, v1 (texture coordinates)
13
+ // Total used: 128 bytes; slot size: minUniformBufferOffsetAlignment (≥256)
14
+ export const UNIFORM_BYTE_SIZE = 128;
15
+ const BITMAP_SHADER_SRC = /* wgsl */ `
16
+ struct Uniforms {
17
+ matrix : mat3x3f,
18
+ alpha : f32,
19
+ hasColorTransform : u32,
20
+ _pad0 : f32,
21
+ _pad1 : f32,
22
+ colorMultiplier : vec4f,
23
+ colorOffset : vec4f,
24
+ x0 : f32, y0 : f32, x1 : f32, y1 : f32,
25
+ u0 : f32, v0 : f32, u1 : f32, v1 : f32,
26
+ }
27
+
28
+ @group(0) @binding(0) var<uniform> uni : Uniforms;
29
+ @group(1) @binding(0) var tex : texture_2d<f32>;
30
+ @group(1) @binding(1) var smp : sampler;
31
+
32
+ struct VertexOut {
33
+ @builtin(position) position : vec4f,
34
+ @location(0) uv : vec2f,
35
+ }
36
+
37
+ // Quad corner order matching index pattern [0,1,2, 0,2,3]:
38
+ // vi 0 → corner (x0,y0,u0,v0)
39
+ // vi 1 → corner (x1,y0,u1,v0)
40
+ // vi 2 → corner (x1,y1,u1,v1)
41
+ // vi 3 → corner (x0,y0,u0,v0) [repeated]
42
+ // vi 4 → corner (x1,y1,u1,v1) [repeated]
43
+ // vi 5 → corner (x0,y1,u0,v1)
44
+
45
+ @vertex
46
+ fn vs_main(@builtin(vertex_index) vi : u32) -> VertexOut {
47
+ let xi = (vi == 1u || vi == 2u || vi == 4u);
48
+ let yi = (vi == 2u || vi == 4u || vi == 5u);
49
+ let x = select(uni.x0, uni.x1, xi);
50
+ let y = select(uni.y0, uni.y1, yi);
51
+ let u = select(uni.u0, uni.u1, xi);
52
+ let v = select(uni.v0, uni.v1, yi);
53
+ let p = uni.matrix * vec3f(x, y, 1.0);
54
+ var out : VertexOut;
55
+ out.position = vec4f(p.x, p.y, 0.0, 1.0);
56
+ out.uv = vec2f(u, v);
57
+ return out;
58
+ }
59
+
60
+ @fragment
61
+ fn fs_main(in : VertexOut) -> @location(0) vec4f {
62
+ var color = textureSample(tex, smp, in.uv);
63
+ if (color.a <= 0.0) { discard; }
64
+ if (uni.hasColorTransform != 0u && color.a > 0.0) {
65
+ // Unpremultiply, apply transform, repremultiply
66
+ color = vec4f(color.rgb / color.a, color.a);
67
+ color = clamp(color * uni.colorMultiplier + uni.colorOffset, vec4f(0.0), vec4f(1.0));
68
+ color = vec4f(color.rgb * color.a, color.a);
69
+ }
70
+ return color * clamp(uni.alpha, 0.0, 1.0);
71
+ }
72
+ `;
73
+ // Stencil-write pipeline: only writes to stencil, not color.
74
+ // Uses same vertex shader; fragment just discards to keep stencil logic in pipeline state.
75
+ const MASK_FRAGMENT_SRC = /* wgsl */ `
76
+ struct Uniforms {
77
+ matrix : mat3x3f,
78
+ alpha : f32,
79
+ hasColorTransform : u32,
80
+ _pad0 : f32,
81
+ _pad1 : f32,
82
+ colorMultiplier : vec4f,
83
+ colorOffset : vec4f,
84
+ x0 : f32, y0 : f32, x1 : f32, y1 : f32,
85
+ u0 : f32, v0 : f32, u1 : f32, v1 : f32,
86
+ }
87
+
88
+ @group(0) @binding(0) var<uniform> uni : Uniforms;
89
+ @group(1) @binding(0) var tex : texture_2d<f32>;
90
+ @group(1) @binding(1) var smp : sampler;
91
+
92
+ struct VertexOut {
93
+ @builtin(position) position : vec4f,
94
+ @location(0) uv : vec2f,
95
+ }
96
+
97
+ @vertex
98
+ fn vs_main(@builtin(vertex_index) vi : u32) -> VertexOut {
99
+ let xi = (vi == 1u || vi == 2u || vi == 4u);
100
+ let yi = (vi == 2u || vi == 4u || vi == 5u);
101
+ let x = select(uni.x0, uni.x1, xi);
102
+ let y = select(uni.y0, uni.y1, yi);
103
+ let u = select(uni.u0, uni.u1, xi);
104
+ let v = select(uni.v0, uni.v1, yi);
105
+ let p = uni.matrix * vec3f(x, y, 1.0);
106
+ var out : VertexOut;
107
+ out.position = vec4f(p.x, p.y, 0.0, 1.0);
108
+ out.uv = vec2f(u, v);
109
+ return out;
110
+ }
111
+
112
+ @fragment
113
+ fn fs_main(in : VertexOut) -> @location(0) vec4f {
114
+ let s = textureSample(tex, smp, in.uv);
115
+ if (s.a <= 0.0) { discard; }
116
+ return vec4f(0.0);
117
+ }
118
+ `;
119
+ const NORMAL_BLEND = {
120
+ color: { srcFactor: 'one', dstFactor: 'one-minus-src-alpha', operation: 'add' },
121
+ alpha: { srcFactor: 'one', dstFactor: 'one-minus-src-alpha', operation: 'add' },
122
+ };
123
+ const BLEND_MODES = {
124
+ [BlendMode.Add]: {
125
+ color: { srcFactor: 'one', dstFactor: 'one', operation: 'add' },
126
+ alpha: { srcFactor: 'one', dstFactor: 'one', operation: 'add' },
127
+ },
128
+ [BlendMode.Alpha]: null,
129
+ [BlendMode.Darken]: null,
130
+ [BlendMode.Difference]: null,
131
+ [BlendMode.Erase]: null,
132
+ [BlendMode.Hardlight]: null,
133
+ [BlendMode.Invert]: null,
134
+ [BlendMode.Layer]: NORMAL_BLEND,
135
+ [BlendMode.Lighten]: null,
136
+ [BlendMode.Multiply]: null,
137
+ [BlendMode.Normal]: NORMAL_BLEND,
138
+ [BlendMode.Overlay]: null,
139
+ [BlendMode.Screen]: null,
140
+ [BlendMode.Shader]: null,
141
+ [BlendMode.Subtract]: null,
142
+ };
143
+ // ---- Pipeline creation ----
144
+ export function createWgpuBindGroupLayouts(device) {
145
+ const uniformBindGroupLayout = device.createBindGroupLayout({
146
+ entries: [
147
+ {
148
+ binding: 0,
149
+ visibility: GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT,
150
+ buffer: { type: 'uniform', hasDynamicOffset: true, minBindingSize: UNIFORM_BYTE_SIZE },
151
+ },
152
+ ],
153
+ });
154
+ const textureBindGroupLayout = device.createBindGroupLayout({
155
+ entries: [
156
+ { binding: 0, visibility: GPUShaderStage.FRAGMENT, texture: { sampleType: 'float' } },
157
+ { binding: 1, visibility: GPUShaderStage.FRAGMENT, sampler: { type: 'filtering' } },
158
+ ],
159
+ });
160
+ return { uniformBindGroupLayout, textureBindGroupLayout };
161
+ }
162
+ export function createWgpuPipelineLayout(device, uniformBindGroupLayout, textureBindGroupLayout) {
163
+ return device.createPipelineLayout({
164
+ bindGroupLayouts: [uniformBindGroupLayout, textureBindGroupLayout],
165
+ });
166
+ }
167
+ function buildStencilFaceState(stencilMode) {
168
+ if (stencilMode === 'maskwrite') {
169
+ return { compare: 'always', passOp: 'replace', failOp: 'keep', depthFailOp: 'keep' };
170
+ }
171
+ if (stencilMode === 'masked') {
172
+ return { compare: 'equal', passOp: 'keep', failOp: 'keep', depthFailOp: 'keep' };
173
+ }
174
+ return { compare: 'always', passOp: 'keep', failOp: 'keep', depthFailOp: 'keep' };
175
+ }
176
+ export function getActiveWgpuPipeline(state) {
177
+ const runtime = getWgpuRenderStateRuntime(state);
178
+ const stencilMode = runtime.maskWriteMode
179
+ ? 'maskwrite'
180
+ : runtime.currentMaskDepth > 0
181
+ ? 'masked'
182
+ : 'normal';
183
+ return getWgpuPipeline(state, runtime.currentBlendMode, stencilMode);
184
+ }
185
+ export function getWgpuPipeline(state, blendMode, stencilMode) {
186
+ const runtime = getWgpuRenderStateRuntime(state);
187
+ // The pipeline bakes its color-attachment format, so key on the current target format too (rgba16float
188
+ // inside an HDR effect target vs the canvas format).
189
+ const format = runtime.currentColorFormat ?? state.format;
190
+ const key = `${blendMode ?? 'null'}-${stencilMode}-${format}`;
191
+ const cached = runtime.pipelineCache.get(key);
192
+ if (cached !== undefined)
193
+ return cached;
194
+ const blend = (blendMode !== null ? BLEND_MODES[blendMode] : null) ?? NORMAL_BLEND;
195
+ const isMaskWrite = stencilMode === 'maskwrite';
196
+ const stencilFace = buildStencilFaceState(stencilMode);
197
+ const { device } = state;
198
+ const shaderSrc = isMaskWrite ? MASK_FRAGMENT_SRC : BITMAP_SHADER_SRC;
199
+ const module = device.createShaderModule({ code: shaderSrc });
200
+ const layout = createWgpuPipelineLayout(device, runtime.uniformBindGroupLayout, runtime.textureBindGroupLayout);
201
+ const pipeline = device.createRenderPipeline({
202
+ layout,
203
+ vertex: { module, entryPoint: 'vs_main' },
204
+ fragment: {
205
+ module,
206
+ entryPoint: 'fs_main',
207
+ targets: [
208
+ {
209
+ format,
210
+ blend: isMaskWrite ? undefined : blend,
211
+ writeMask: isMaskWrite ? 0 : GPUColorWrite.ALL,
212
+ },
213
+ ],
214
+ },
215
+ depthStencil: {
216
+ format: 'depth24plus-stencil8',
217
+ depthWriteEnabled: false,
218
+ depthCompare: 'always',
219
+ stencilFront: stencilFace,
220
+ stencilBack: stencilFace,
221
+ stencilReadMask: 0xff,
222
+ stencilWriteMask: isMaskWrite ? 0xff : 0x00,
223
+ },
224
+ primitive: { topology: 'triangle-list' },
225
+ });
226
+ runtime.pipelineCache.set(key, pipeline);
227
+ return pipeline;
228
+ }
229
+ // ---- Matrix helpers ----
230
+ export function setWgpuMatrixFromTransform(matrixArray, t, viewport) {
231
+ const iw = 2 / viewport.width;
232
+ const ih = 2 / viewport.height;
233
+ // Column-major mat3x3 with vec3-to-16-byte padding:
234
+ // col0
235
+ matrixArray[0] = t.a * iw;
236
+ matrixArray[1] = -t.b * ih;
237
+ matrixArray[2] = 0;
238
+ // col1
239
+ matrixArray[3] = t.c * iw;
240
+ matrixArray[4] = -t.d * ih;
241
+ matrixArray[5] = 0;
242
+ // col2
243
+ matrixArray[6] = t.tx * iw - 1;
244
+ matrixArray[7] = -t.ty * ih + 1;
245
+ matrixArray[8] = 1;
246
+ }
247
+ // ---- Uniform slot writing ----
248
+ export function writeWgpuMatrixOnlyUniforms(state, renderProxy, transform, x0, y0, x1, y1, u0, v0, u1, v1) {
249
+ return writeWgpuQuadUniforms(state, { alpha: renderProxy.alpha, transform2D: transform }, null, x0, y0, x1, y1, u0, v0, u1, v1);
250
+ }
251
+ // Writes the standard uniforms (matrix + alpha + color transform + quad coords) into
252
+ // the ring buffer at the current uniformOffset, then advances the offset by uniformStride.
253
+ // Returns the byte offset of the slot just written (for use as the dynamic offset in setBindGroup).
254
+ export function writeWgpuQuadUniforms(state, renderProxy, colorTransform, x0, y0, x1, y1, u0, v0, u1, v1) {
255
+ const runtime = getWgpuRenderStateRuntime(state);
256
+ const byteOffset = runtime.uniformOffset;
257
+ const floatBase = byteOffset >> 2; // divide by 4
258
+ const { uniformData, uniformDataU32, matrixArray } = runtime;
259
+ const viewport = runtime.renderTargetViewport ?? state.canvas;
260
+ setWgpuMatrixFromTransform(matrixArray, renderProxy.transform2D, viewport);
261
+ // mat3x3 columns with per-column padding (4 floats each = 16 bytes):
262
+ uniformData[floatBase + 0] = matrixArray[0];
263
+ uniformData[floatBase + 1] = matrixArray[1];
264
+ uniformData[floatBase + 2] = matrixArray[2];
265
+ uniformData[floatBase + 3] = 0;
266
+ uniformData[floatBase + 4] = matrixArray[3];
267
+ uniformData[floatBase + 5] = matrixArray[4];
268
+ uniformData[floatBase + 6] = matrixArray[5];
269
+ uniformData[floatBase + 7] = 0;
270
+ uniformData[floatBase + 8] = matrixArray[6];
271
+ uniformData[floatBase + 9] = matrixArray[7];
272
+ uniformData[floatBase + 10] = matrixArray[8];
273
+ uniformData[floatBase + 11] = 0;
274
+ // alpha at float 12 (byte 48)
275
+ uniformData[floatBase + 12] = renderProxy.alpha;
276
+ // hasColorTransform at float 13 (byte 52) — written as u32. The color transform comes from the
277
+ // node's material (resolved by the caller); null → identity.
278
+ uniformDataU32[floatBase + 13] = colorTransform !== null ? 1 : 0;
279
+ // padding floats 14–15
280
+ uniformData[floatBase + 14] = 0;
281
+ uniformData[floatBase + 15] = 0;
282
+ // colorMultiplier at float 16–19 (byte 64–79)
283
+ uniformData[floatBase + 16] = colorTransform?.redMultiplier ?? 1;
284
+ uniformData[floatBase + 17] = colorTransform?.greenMultiplier ?? 1;
285
+ uniformData[floatBase + 18] = colorTransform?.blueMultiplier ?? 1;
286
+ uniformData[floatBase + 19] = colorTransform?.alphaMultiplier ?? 1;
287
+ // colorOffset at float 20–23 (byte 80–95)
288
+ uniformData[floatBase + 20] = (colorTransform?.redOffset ?? 0) / 255;
289
+ uniformData[floatBase + 21] = (colorTransform?.greenOffset ?? 0) / 255;
290
+ uniformData[floatBase + 22] = (colorTransform?.blueOffset ?? 0) / 255;
291
+ uniformData[floatBase + 23] = (colorTransform?.alphaOffset ?? 0) / 255;
292
+ // quad corners at float 24–31 (byte 96–127)
293
+ uniformData[floatBase + 24] = x0;
294
+ uniformData[floatBase + 25] = y0;
295
+ uniformData[floatBase + 26] = x1;
296
+ uniformData[floatBase + 27] = y1;
297
+ uniformData[floatBase + 28] = u0;
298
+ uniformData[floatBase + 29] = v0;
299
+ uniformData[floatBase + 30] = u1;
300
+ uniformData[floatBase + 31] = v1;
301
+ runtime.uniformOffset += runtime.uniformStride;
302
+ return byteOffset;
303
+ }
304
+ //# sourceMappingURL=wgpuShader.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wgpuShader.js","sourceRoot":"","sources":["../src/wgpuShader.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ import type { DisplayObject, RenderProxy2D, WgpuBitmapShader, WgpuRenderState } from '@flighthq/types';
2
+ export declare function getWgpuShader(renderProxy: RenderProxy2D): WgpuBitmapShader | undefined;
3
+ export declare function resolveWgpuShader(state: WgpuRenderState, renderProxy: RenderProxy2D): WgpuBitmapShader | null;
4
+ export declare function setWgpuShader(state: WgpuRenderState, node: DisplayObject, shader: WgpuBitmapShader | null): void;
5
+ //# sourceMappingURL=wgpuShaderBinding.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wgpuShaderBinding.d.ts","sourceRoot":"","sources":["../src/wgpuShaderBinding.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,aAAa,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAMvG,wBAAgB,aAAa,CAAC,WAAW,EAAE,aAAa,GAAG,gBAAgB,GAAG,SAAS,CAEtF;AAID,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,eAAe,EAAE,WAAW,EAAE,aAAa,GAAG,gBAAgB,GAAG,IAAI,CAQ7G;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,eAAe,EAAE,IAAI,EAAE,aAAa,EAAE,MAAM,EAAE,gBAAgB,GAAG,IAAI,GAAG,IAAI,CAQhH"}
@@ -0,0 +1,28 @@
1
+ import { getOrCreateRenderProxy2D } from '@flighthq/render';
2
+ import { getWgpuRenderStateRuntime } from './wgpuRenderState';
3
+ const _shaderBindings = new WeakMap();
4
+ export function getWgpuShader(renderProxy) {
5
+ return _shaderBindings.get(renderProxy);
6
+ }
7
+ // Returns the per-node shader binding, or null when none is bound. The lookup is reached only
8
+ // through the installed resolver, so it and the binding map tree-shake until setWgpuShader is used.
9
+ export function resolveWgpuShader(state, renderProxy) {
10
+ const runtime = getWgpuRenderStateRuntime(state);
11
+ const resolver = runtime.webgpuShaderBindingResolver;
12
+ if (resolver !== undefined) {
13
+ const shader = resolver(renderProxy);
14
+ if (shader !== undefined)
15
+ return shader;
16
+ }
17
+ return null;
18
+ }
19
+ export function setWgpuShader(state, node, shader) {
20
+ const renderProxy = getOrCreateRenderProxy2D(state, node);
21
+ if (shader === null) {
22
+ _shaderBindings.delete(renderProxy);
23
+ return;
24
+ }
25
+ _shaderBindings.set(renderProxy, shader);
26
+ getWgpuRenderStateRuntime(state).webgpuShaderBindingResolver = getWgpuShader;
27
+ }
28
+ //# sourceMappingURL=wgpuShaderBinding.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wgpuShaderBinding.js","sourceRoot":"","sources":["../src/wgpuShaderBinding.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,wBAAwB,EAAE,MAAM,kBAAkB,CAAC;AAG5D,OAAO,EAAE,yBAAyB,EAAE,MAAM,mBAAmB,CAAC;AAE9D,MAAM,eAAe,GAAG,IAAI,OAAO,EAAmC,CAAC;AAEvE,MAAM,UAAU,aAAa,CAAC,WAA0B;IACtD,OAAO,eAAe,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;AAC1C,CAAC;AAED,8FAA8F;AAC9F,oGAAoG;AACpG,MAAM,UAAU,iBAAiB,CAAC,KAAsB,EAAE,WAA0B;IAClF,MAAM,OAAO,GAAG,yBAAyB,CAAC,KAAK,CAAC,CAAC;IACjD,MAAM,QAAQ,GAAG,OAAO,CAAC,2BAA2B,CAAC;IACrD,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;QAC3B,MAAM,MAAM,GAAG,QAAQ,CAAC,WAAW,CAAC,CAAC;QACrC,IAAI,MAAM,KAAK,SAAS;YAAE,OAAO,MAAM,CAAC;IAC1C,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,KAAsB,EAAE,IAAmB,EAAE,MAA+B;IACxG,MAAM,WAAW,GAAG,wBAAwB,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;IAC1D,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;QACpB,eAAe,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;QACpC,OAAO;IACT,CAAC;IACD,eAAe,CAAC,GAAG,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC;IACzC,yBAAyB,CAAC,KAAK,CAAC,CAAC,2BAA2B,GAAG,aAAa,CAAC;AAC/E,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { WgpuBitmapShader, WgpuRenderState } from '@flighthq/types';
2
+ export declare function registerWgpuBitmapShader(state: WgpuRenderState, shader: WgpuBitmapShader): void;
3
+ //# sourceMappingURL=wgpuShaderRegistry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wgpuShaderRegistry.d.ts","sourceRoot":"","sources":["../src/wgpuShaderRegistry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAOzE,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,eAAe,EAAE,MAAM,EAAE,gBAAgB,GAAG,IAAI,CAE/F"}
@@ -0,0 +1,8 @@
1
+ import { getWgpuRenderStateRuntime } from './wgpuRenderState';
2
+ // Registers a custom bitmap shader as the state-wide default, replacing the built-in quad shader.
3
+ // Use this to globally swap the render pipeline (for example a custom color-transform or tint
4
+ // shader) on a render state without per-node setWgpuShader bindings.
5
+ export function registerWgpuBitmapShader(state, shader) {
6
+ getWgpuRenderStateRuntime(state).defaultBitmapShader = shader;
7
+ }
8
+ //# sourceMappingURL=wgpuShaderRegistry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wgpuShaderRegistry.js","sourceRoot":"","sources":["../src/wgpuShaderRegistry.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,yBAAyB,EAAE,MAAM,mBAAmB,CAAC;AAE9D,kGAAkG;AAClG,8FAA8F;AAC9F,qEAAqE;AACrE,MAAM,UAAU,wBAAwB,CAAC,KAAsB,EAAE,MAAwB;IACvF,yBAAyB,CAAC,KAAK,CAAC,CAAC,mBAAmB,GAAG,MAAM,CAAC;AAChE,CAAC"}
@@ -0,0 +1,6 @@
1
+ import type { Surface, WgpuRenderState } from '@flighthq/types';
2
+ export declare function acquireWgpuFrameCaptureTexture(state: Readonly<WgpuRenderState>): GPUTexture | null;
3
+ export declare function createSurfaceFromWgpuRenderState(state: Readonly<WgpuRenderState>): Promise<Surface>;
4
+ export declare function enableWgpuFrameCapture(state: Readonly<WgpuRenderState>): void;
5
+ export declare function encodeWgpuFrameCapture(state: Readonly<WgpuRenderState>, encoder: GPUCommandEncoder): void;
6
+ //# sourceMappingURL=wgpuSurface.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wgpuSurface.d.ts","sourceRoot":"","sources":["../src/wgpuSurface.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAchE,wBAAgB,8BAA8B,CAAC,KAAK,EAAE,QAAQ,CAAC,eAAe,CAAC,GAAG,UAAU,GAAG,IAAI,CAmBlG;AAOD,wBAAsB,gCAAgC,CAAC,KAAK,EAAE,QAAQ,CAAC,eAAe,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC,CA0CzG;AAMD,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,QAAQ,CAAC,eAAe,CAAC,GAAG,IAAI,CAE7E;AAKD,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,QAAQ,CAAC,eAAe,CAAC,EAAE,OAAO,EAAE,iBAAiB,GAAG,IAAI,CA2BzG"}
@@ -0,0 +1,107 @@
1
+ import { createSurface } from '@flighthq/surface';
2
+ import { getWgpuRenderStateRuntime } from './wgpuRenderState';
3
+ // Opt-in capture of the rendered frame to a CPU Surface. Two environment facts drive the design:
4
+ // (1) headless/software adapters never present the swapchain, and its texture reads back as zeros, so
5
+ // the frame is redirected into an offscreen COPY_SRC texture (acquireWgpuFrameCaptureTexture, used by
6
+ // renderWgpuBackground); (2) GPU work queued in a later task than the frame is dropped on these
7
+ // adapters, so submitWgpuRenderPass copies the capture texture into the retained capture buffer in the
8
+ // same frame (encodeWgpuFrameCapture), and createSurfaceFromWgpuRenderState only maps that buffer.
9
+ // Returns the offscreen texture the frame should render into when capture is enabled, creating/resizing
10
+ // it to the canvas on demand, or null when capture is off (the caller then renders to the swapchain).
11
+ // Internal: called by renderWgpuBackground to redirect the frame so its pixels stay readable.
12
+ export function acquireWgpuFrameCaptureTexture(state) {
13
+ const runtime = getWgpuRenderStateRuntime(state);
14
+ if (!runtime.frameCaptureEnabled)
15
+ return null;
16
+ const width = Math.max(1, state.canvas.width);
17
+ const height = Math.max(1, state.canvas.height);
18
+ const existing = runtime.frameCaptureTexture;
19
+ if (existing !== null && existing !== undefined && existing.width === width && existing.height === height) {
20
+ return existing;
21
+ }
22
+ existing?.destroy();
23
+ const texture = state.device.createTexture({
24
+ size: [width, height, 1],
25
+ format: state.format,
26
+ usage: GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_SRC,
27
+ });
28
+ runtime.frameCaptureTexture = texture;
29
+ return texture;
30
+ }
31
+ // Reads the most recently captured frame into a CPU Surface. Requires enableWgpuFrameCapture(state)
32
+ // before rendering and at least one submitWgpuRenderPass since (which fills the capture buffer);
33
+ // throws otherwise (calling it without enabling capture is API misuse). Only maps the retained buffer —
34
+ // no GPU work is queued here, since later-task GPU work is unreliable on the adapters this exists for.
35
+ // Allocates the returned Surface; the capture buffer is retained and reused across frames.
36
+ export async function createSurfaceFromWgpuRenderState(state) {
37
+ const runtime = getWgpuRenderStateRuntime(state);
38
+ const buffer = runtime.frameCaptureBuffer;
39
+ if (buffer === null || buffer === undefined) {
40
+ throw new Error('createSurfaceFromWgpuRenderState requires enableWgpuFrameCapture(state) before rendering, then a submitWgpuRenderPass.');
41
+ }
42
+ const width = runtime.frameCaptureWidth;
43
+ const height = runtime.frameCaptureHeight;
44
+ const bytesPerRow = runtime.frameCaptureBytesPerRow;
45
+ await buffer.mapAsync(GPUMapMode.READ);
46
+ const mapped = new Uint8Array(buffer.getMappedRange());
47
+ const surface = createSurface(width, height);
48
+ const out = surface.data;
49
+ // The preferred canvas format is BGRA on most platforms and RGBA on software adapters; normalize to
50
+ // the Surface's RGBA byte order so coverage/fingerprint and saved pixels read correctly either way.
51
+ // Pixels are left premultiplied (the texture's stored form): functional content renders over an opaque
52
+ // background, so alpha is 255 and premultiplied == straight; do NOT un-premultiply here — dividing RGB
53
+ // by an 8-bit alpha amplifies quantization and clamps, blowing out exactly the semi-transparent pixels
54
+ // a colour comparison cares about. If straight-alpha output is ever needed, convert at the consumer in
55
+ // higher precision, or compare in premultiplied space on both sides.
56
+ const swizzleBGRA = state.format === 'bgra8unorm' || state.format === 'bgra8unorm-srgb';
57
+ for (let y = 0; y < height; y++) {
58
+ const srcRow = y * bytesPerRow;
59
+ const dstRow = y * width * 4;
60
+ for (let x = 0; x < width; x++) {
61
+ const s = srcRow + x * 4;
62
+ const d = dstRow + x * 4;
63
+ out[d] = swizzleBGRA ? mapped[s + 2] : mapped[s];
64
+ out[d + 1] = mapped[s + 1];
65
+ out[d + 2] = swizzleBGRA ? mapped[s] : mapped[s + 2];
66
+ out[d + 3] = mapped[s + 3];
67
+ }
68
+ }
69
+ // Unmap (not destroy) so the next frame's submit can copy into the retained buffer again.
70
+ buffer.unmap();
71
+ return surface;
72
+ }
73
+ // Enables opt-in frame capture on a render state so createSurfaceFromWgpuRenderState can read it back.
74
+ // The frame is then drawn into an offscreen texture instead of the swapchain (the only reliably
75
+ // readable path on headless/software adapters); the canvas is not presented while capture is on. Leave
76
+ // it off for normal on-screen rendering. The capture texture and buffer are allocated lazily.
77
+ export function enableWgpuFrameCapture(state) {
78
+ getWgpuRenderStateRuntime(state).frameCaptureEnabled = true;
79
+ }
80
+ // Encodes the capture-texture → capture-buffer copy into the frame's command encoder, sizing/reallocating
81
+ // the retained buffer to the canvas on demand. No-op unless capture is enabled. Internal: called by
82
+ // submitWgpuRenderPass so the copy is queued in the render frame, not a later (dropped) task.
83
+ export function encodeWgpuFrameCapture(state, encoder) {
84
+ const runtime = getWgpuRenderStateRuntime(state);
85
+ const texture = runtime.frameCaptureTexture;
86
+ if (!runtime.frameCaptureEnabled || texture === null || texture === undefined)
87
+ return;
88
+ const width = texture.width;
89
+ const height = texture.height;
90
+ // Wgpu requires copyTextureToBuffer rows to be 256-byte aligned; the buffer is padded per row.
91
+ const bytesPerRow = Math.ceil((width * 4) / 256) * 256;
92
+ if (runtime.frameCaptureBuffer === null ||
93
+ runtime.frameCaptureBuffer === undefined ||
94
+ runtime.frameCaptureWidth !== width ||
95
+ runtime.frameCaptureHeight !== height) {
96
+ runtime.frameCaptureBuffer?.destroy();
97
+ runtime.frameCaptureBuffer = state.device.createBuffer({
98
+ size: bytesPerRow * height,
99
+ usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.MAP_READ,
100
+ });
101
+ runtime.frameCaptureBytesPerRow = bytesPerRow;
102
+ runtime.frameCaptureWidth = width;
103
+ runtime.frameCaptureHeight = height;
104
+ }
105
+ encoder.copyTextureToBuffer({ texture }, { buffer: runtime.frameCaptureBuffer, bytesPerRow }, [width, height, 1]);
106
+ }
107
+ //# sourceMappingURL=wgpuSurface.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wgpuSurface.js","sourceRoot":"","sources":["../src/wgpuSurface.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import type { WgpuRenderState } from '@flighthq/types';
2
+ export declare function createWgpuRenderStateForTest(): Promise<WgpuRenderState>;
3
+ export declare function installWgpuMock(): void;
4
+ //# sourceMappingURL=wgpuTestHelper.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wgpuTestHelper.d.ts","sourceRoot":"","sources":["../src/wgpuTestHelper.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAwHvD,wBAAsB,4BAA4B,IAAI,OAAO,CAAC,eAAe,CAAC,CAK7E;AAED,wBAAgB,eAAe,IAAI,IAAI,CAiCtC"}