@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.
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/wgpuDraw.d.ts +3 -2
- package/dist/wgpuDraw.d.ts.map +1 -1
- package/dist/wgpuDraw.js +88 -1
- package/dist/wgpuDraw.js.map +1 -1
- package/dist/wgpuFullscreenPass.js +1 -1
- package/dist/wgpuFullscreenPass.js.map +1 -1
- package/dist/wgpuMipmap.d.ts +4 -0
- package/dist/wgpuMipmap.d.ts.map +1 -0
- package/dist/wgpuMipmap.js +92 -0
- package/dist/wgpuMipmap.js.map +1 -0
- package/dist/wgpuRenderState.d.ts +3 -2
- package/dist/wgpuRenderState.d.ts.map +1 -1
- package/dist/wgpuRenderState.js +33 -0
- package/dist/wgpuRenderState.js.map +1 -1
- package/dist/wgpuRenderTarget.d.ts +4 -3
- package/dist/wgpuRenderTarget.d.ts.map +1 -1
- package/dist/wgpuRenderTarget.js +61 -11
- package/dist/wgpuRenderTarget.js.map +1 -1
- package/dist/wgpuShader.d.ts.map +1 -1
- package/dist/wgpuShader.js +6 -15
- package/dist/wgpuShader.js.map +1 -1
- package/dist/wgpuTextureUpload.d.ts +5 -0
- package/dist/wgpuTextureUpload.d.ts.map +1 -0
- package/dist/wgpuTextureUpload.js +25 -0
- package/dist/wgpuTextureUpload.js.map +1 -0
- package/package.json +6 -6
- package/src/wgpuDraw.test.ts +75 -0
- package/src/wgpuMipmap.test.ts +73 -0
- package/src/wgpuRenderState.test.ts +46 -0
- package/src/wgpuRenderTarget.test.ts +32 -14
- package/src/wgpuShader.test.ts +3 -6
- package/src/wgpuTextureUpload.test.ts +60 -0
package/dist/wgpuRenderTarget.js
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { copyMatrix, createMatrix } from '@flighthq/geometry';
|
|
2
2
|
import { buildWgpuRenderTargetBindGroup, drawWgpuQuadWithTransform } from './wgpuDraw';
|
|
3
3
|
import { getWgpuRenderStateRuntime } from './wgpuRenderState';
|
|
4
|
-
function
|
|
4
|
+
function beginWgpuRenderPassEncoder(state, colorView, depthStencilView, width, height, loadOp, clearColor = { r: 0, g: 0, b: 0, a: 0 }, depthLoadOp = 'clear', depthClearValue = 1.0) {
|
|
5
5
|
const runtime = getWgpuRenderStateRuntime(state);
|
|
6
6
|
const pass = runtime.commandEncoder.beginRenderPass({
|
|
7
7
|
colorAttachments: [{ view: colorView, loadOp, storeOp: 'store', clearValue: clearColor }],
|
|
8
8
|
depthStencilAttachment: {
|
|
9
9
|
view: depthStencilView,
|
|
10
|
-
depthClearValue
|
|
11
|
-
depthLoadOp
|
|
10
|
+
depthClearValue,
|
|
11
|
+
depthLoadOp,
|
|
12
12
|
depthStoreOp: 'discard',
|
|
13
13
|
stencilClearValue: 0,
|
|
14
14
|
stencilLoadOp: 'clear',
|
|
@@ -18,7 +18,13 @@ function beginWgpuRenderPass(state, colorView, depthStencilView, width, height,
|
|
|
18
18
|
pass.setViewport(0, 0, width, height, 0, 1);
|
|
19
19
|
return pass;
|
|
20
20
|
}
|
|
21
|
-
|
|
21
|
+
// Begins a render pass into `target`: opens a wgpu render pass encoder that CLEARS every aspect by
|
|
22
|
+
// default (the loadOp 'clear' the pass previously always used). `preserve` switches an aspect's
|
|
23
|
+
// loadOp to 'load'; the clear VALUES are fixed on the target (WgpuRenderTarget.clearColors / clearDepth).
|
|
24
|
+
// Pair with endWgpuRenderPass. Carries no 2D transform — that is a display-object draw concern; a 2D pass
|
|
25
|
+
// that needs a specific root transform calls setWgpuRenderTransform2D after begin (saved/restored by the
|
|
26
|
+
// bracket). Mirrors beginGlRenderPass.
|
|
27
|
+
export function beginWgpuRenderPass(state, target, preserve) {
|
|
22
28
|
const runtime = getWgpuRenderStateRuntime(state);
|
|
23
29
|
// End the current render pass before beginning the new one
|
|
24
30
|
if (runtime.renderPass !== null) {
|
|
@@ -36,15 +42,14 @@ export function beginWgpuRenderTarget(state, target, renderTransform, clearColor
|
|
|
36
42
|
runtime.renderTargetViewport = { width: target.width, height: target.height };
|
|
37
43
|
// Scene pipelines drawn into this target must match its color format (e.g. rgba16float for HDR).
|
|
38
44
|
runtime.currentColorFormat = target.format;
|
|
39
|
-
const newTransform = createMatrix();
|
|
40
|
-
copyMatrix(newTransform, renderTransform);
|
|
41
|
-
state.renderTransform2D = newTransform;
|
|
42
45
|
// Reset mask/clip state for the new pass
|
|
43
46
|
runtime.currentMaskDepth = 0;
|
|
44
47
|
runtime.maskWriteMode = false;
|
|
45
48
|
runtime.currentScissorRect = null;
|
|
46
49
|
runtime.scissorStack = [];
|
|
47
|
-
|
|
50
|
+
const colorLoadOp = isWgpuColorPreserved(preserve?.preserveColor ?? false, 0) ? 'load' : 'clear';
|
|
51
|
+
const depthLoadOp = preserve?.preserveDepth === true ? 'load' : 'clear';
|
|
52
|
+
runtime.renderPass = beginWgpuRenderPassEncoder(state, target.view, target.depthStencilView, target.width, target.height, colorLoadOp, resolveWgpuClearColor(target), depthLoadOp, target.clearDepth);
|
|
48
53
|
}
|
|
49
54
|
// `format` defaults to the canvas format. Pass 'rgba16float' for an HDR effect target (bloom, tone
|
|
50
55
|
// mapping). The chosen format is recorded on the target so the effect-target pool matches on it.
|
|
@@ -65,7 +70,18 @@ export function createWgpuRenderTarget(state, width, height, format = state.form
|
|
|
65
70
|
usage: GPUTextureUsage.RENDER_ATTACHMENT,
|
|
66
71
|
});
|
|
67
72
|
const depthStencilView = depthStencilTexture.createView();
|
|
68
|
-
return {
|
|
73
|
+
return {
|
|
74
|
+
bindGroup,
|
|
75
|
+
texture,
|
|
76
|
+
view,
|
|
77
|
+
depthStencilTexture,
|
|
78
|
+
depthStencilView,
|
|
79
|
+
format,
|
|
80
|
+
clearColors: [],
|
|
81
|
+
clearDepth: 1,
|
|
82
|
+
width: w,
|
|
83
|
+
height: h,
|
|
84
|
+
};
|
|
69
85
|
}
|
|
70
86
|
export function destroyWgpuRenderTarget(_state, target) {
|
|
71
87
|
target.texture.destroy();
|
|
@@ -91,7 +107,11 @@ export function drawWgpuRenderTargetResult(state, renderProxy, target, transform
|
|
|
91
107
|
// Render target textures are stored with Y flipped relative to canvas (bottom-left origin)
|
|
92
108
|
drawWgpuQuadWithTransform(state, renderProxy, composedTransform, { texture: target.texture, view: target.view, bindGroup: target.bindGroup }, 0, 0, target.width, target.height, 0, 1, 1, 0);
|
|
93
109
|
}
|
|
94
|
-
|
|
110
|
+
// Ends the pass opened by beginWgpuRenderPass: closes the encoder, restores the saved canvas view,
|
|
111
|
+
// viewport, color format, and 2D transform, and reopens the canvas pass (loadOp 'load') so the frame
|
|
112
|
+
// continues. Mirrors endGlRenderPass / endCanvasRenderPass — no target argument. A call with no matching
|
|
113
|
+
// begin is a no-op.
|
|
114
|
+
export function endWgpuRenderPass(state) {
|
|
95
115
|
const runtime = getWgpuRenderStateRuntime(state);
|
|
96
116
|
if (runtime.renderPass !== null) {
|
|
97
117
|
runtime.renderPass.end();
|
|
@@ -111,7 +131,7 @@ export function endWgpuRenderTarget(state) {
|
|
|
111
131
|
runtime.currentScissorRect = null;
|
|
112
132
|
runtime.scissorStack = [];
|
|
113
133
|
if (saved.canvasTextureView !== null) {
|
|
114
|
-
runtime.renderPass =
|
|
134
|
+
runtime.renderPass = beginWgpuRenderPassEncoder(state, saved.canvasTextureView, saved.depthStencilView ?? runtime.depthStencilView, runtime.renderTargetViewport?.width ?? state.canvas.width, runtime.renderTargetViewport?.height ?? state.canvas.height, 'load');
|
|
115
135
|
}
|
|
116
136
|
}
|
|
117
137
|
export function resizeWgpuRenderTarget(state, target, width, height) {
|
|
@@ -139,4 +159,34 @@ export function resizeWgpuRenderTarget(state, target, width, height) {
|
|
|
139
159
|
target.depthStencilTexture = newDepth;
|
|
140
160
|
target.depthStencilView = newDepth.createView();
|
|
141
161
|
}
|
|
162
|
+
// True when color attachment `index` should be preserved (loadOp 'load') rather than cleared. A boolean
|
|
163
|
+
// applies to every attachment; an array is indexed by attachment location, missing entries defaulting to
|
|
164
|
+
// clear. Wgpu targets are single-attachment today, so index is always 0.
|
|
165
|
+
function isWgpuColorPreserved(preserve, index) {
|
|
166
|
+
if (typeof preserve === 'boolean')
|
|
167
|
+
return preserve;
|
|
168
|
+
return preserve[index] === true;
|
|
169
|
+
}
|
|
170
|
+
// Unpacks the target's packed-RGBA (0xRRGGBBAA) clear color for attachment 0 into a GPUColor; an empty
|
|
171
|
+
// clearColors means a transparent clear (the render-target default).
|
|
172
|
+
function resolveWgpuClearColor(target) {
|
|
173
|
+
const packed = target.clearColors[0];
|
|
174
|
+
if (packed === undefined)
|
|
175
|
+
return { r: 0, g: 0, b: 0, a: 0 };
|
|
176
|
+
return {
|
|
177
|
+
r: ((packed >>> 24) & 0xff) / 255,
|
|
178
|
+
g: ((packed >>> 16) & 0xff) / 255,
|
|
179
|
+
b: ((packed >>> 8) & 0xff) / 255,
|
|
180
|
+
a: (packed & 0xff) / 255,
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
// Sets the 2D root device transform the display-object update pass reads. Call after beginWgpuRenderPass
|
|
184
|
+
// when a 2D pass renders into a target with its own coordinate system (the render cache); the value is
|
|
185
|
+
// restored by the matching endWgpuRenderPass. Allocates a fresh matrix so the bracket's saved reference
|
|
186
|
+
// stays intact for restore. Mirrors setGlRenderTransform2D.
|
|
187
|
+
export function setWgpuRenderTransform2D(state, transform) {
|
|
188
|
+
const next = createMatrix();
|
|
189
|
+
copyMatrix(next, transform);
|
|
190
|
+
state.renderTransform2D = next;
|
|
191
|
+
}
|
|
142
192
|
//# sourceMappingURL=wgpuRenderTarget.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"wgpuRenderTarget.js","sourceRoot":"","sources":["../src/wgpuRenderTarget.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAG9D,OAAO,EAAE,8BAA8B,EAAE,yBAAyB,EAAE,MAAM,YAAY,CAAC;AACvF,OAAO,EAAE,yBAAyB,EAAE,MAAM,mBAAmB,CAAC;AAE9D,SAAS,
|
|
1
|
+
{"version":3,"file":"wgpuRenderTarget.js","sourceRoot":"","sources":["../src/wgpuRenderTarget.ts"],"names":[],"mappings":"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"}
|
package/dist/wgpuShader.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"wgpuShader.d.ts","sourceRoot":"","sources":["../src/wgpuShader.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AACpF,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAI5C,YAAY,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAcxD,eAAO,MAAM,iBAAiB,MAAM,CAAC;AA8GrC,KAAK,WAAW,GAAG,QAAQ,GAAG,QAAQ,GAAG,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"wgpuShader.d.ts","sourceRoot":"","sources":["../src/wgpuShader.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AACpF,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAI5C,YAAY,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAcxD,eAAO,MAAM,iBAAiB,MAAM,CAAC;AA8GrC,KAAK,WAAW,GAAG,QAAQ,GAAG,QAAQ,GAAG,WAAW,CAAC;AAuBrD,wBAAgB,0BAA0B,CAAC,MAAM,EAAE,SAAS,GAAG;IAC7D,sBAAsB,EAAE,kBAAkB,CAAC;IAC3C,sBAAsB,EAAE,kBAAkB,CAAC;CAC5C,CAmBA;AAED,wBAAgB,wBAAwB,CACtC,MAAM,EAAE,SAAS,EACjB,sBAAsB,EAAE,kBAAkB,EAC1C,sBAAsB,EAAE,kBAAkB,GACzC,iBAAiB,CAInB;AAYD,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,eAAe,GAAG,iBAAiB,CAQ/E;AAED,wBAAgB,eAAe,CAC7B,KAAK,EAAE,eAAe,EACtB,SAAS,EAAE,SAAS,GAAG,IAAI,EAC3B,WAAW,EAAE,WAAW,GACvB,iBAAiB,CA8CnB;AAID,wBAAgB,0BAA0B,CACxC,WAAW,EAAE,YAAY,EACzB,CAAC,EAAE;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,EACzE,QAAQ,EAAE;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAC1C,IAAI,CAgBN;AAID,wBAAgB,2BAA2B,CACzC,KAAK,EAAE,eAAe,EACtB,WAAW,EAAE,WAAW,EACxB,SAAS,EAAE;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,EACjF,EAAE,EAAE,MAAM,EACV,EAAE,EAAE,MAAM,EACV,EAAE,EAAE,MAAM,EACV,EAAE,EAAE,MAAM,EACV,EAAE,EAAE,MAAM,EACV,EAAE,EAAE,MAAM,EACV,EAAE,EAAE,MAAM,EACV,EAAE,EAAE,MAAM,GACT,MAAM,CAcR;AAKD,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,eAAe,EACtB,WAAW,EAAE;IACX,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC;CACrF,EACD,cAAc,EAAE,cAAc,GAAG,IAAI,EACrC,EAAE,EAAE,MAAM,EACV,EAAE,EAAE,MAAM,EACV,EAAE,EAAE,MAAM,EACV,EAAE,EAAE,MAAM,EACV,EAAE,EAAE,MAAM,EACV,EAAE,EAAE,MAAM,EACV,EAAE,EAAE,MAAM,EACV,EAAE,EAAE,MAAM,GACT,MAAM,CAoDR"}
|
package/dist/wgpuShader.js
CHANGED
|
@@ -117,30 +117,21 @@ fn fs_main(in : VertexOut) -> @location(0) vec4f {
|
|
|
117
117
|
}
|
|
118
118
|
`;
|
|
119
119
|
const NORMAL_BLEND = createWgpuBlendState('one', 'one-minus-src-alpha');
|
|
120
|
-
// The fixed-function realizations, mirroring render-gl's DEFAULT_GL_BLEND_MODES
|
|
121
|
-
// one component (WebGPU reads the alpha part of a color factor in the alpha slot,
|
|
122
|
-
// reproduces GL's non-separate blendFunc).
|
|
123
|
-
//
|
|
120
|
+
// The fixed-function realizations, mirroring render-gl's DEFAULT_GL_BLEND_MODES — the cheap fixed-function
|
|
121
|
+
// set. Both channels share one component (WebGPU reads the alpha part of a color factor in the alpha slot,
|
|
122
|
+
// so a single factor reproduces GL's non-separate blendFunc). The Porter-Duff coverage operators
|
|
123
|
+
// (Erase/Alpha/None/…) are a CompositeEffect and the destination-reading advanced modes
|
|
124
|
+
// (Overlay/HardLight/…/HSL) a BlendEffect — neither is in the node-property BlendMode enum, so there is
|
|
125
|
+
// nothing to map here.
|
|
124
126
|
const BLEND_MODES = {
|
|
125
127
|
[BlendMode.Add]: createWgpuBlendState('one', 'one'),
|
|
126
|
-
[BlendMode.Alpha]: null,
|
|
127
128
|
[BlendMode.Darken]: createWgpuBlendState('one', 'one', 'min'),
|
|
128
|
-
[BlendMode.Difference]: null,
|
|
129
|
-
[BlendMode.Erase]: createWgpuBlendState('zero', 'one-minus-src-alpha'),
|
|
130
|
-
[BlendMode.HardLight]: null,
|
|
131
|
-
[BlendMode.Invert]: null,
|
|
132
|
-
[BlendMode.Layer]: NORMAL_BLEND,
|
|
133
129
|
[BlendMode.Lighten]: createWgpuBlendState('one', 'one', 'max'),
|
|
134
130
|
// Premultiplied multiply: src.rgb*dst + dst*(1-src.a), so transparent/partial pixels leave the
|
|
135
131
|
// backdrop untouched instead of multiplying it toward black. Matches render-gl.
|
|
136
132
|
[BlendMode.Multiply]: createWgpuBlendState('dst', 'one-minus-src-alpha'),
|
|
137
|
-
// No blending: the source replaces the destination (matches Normal for opaque content).
|
|
138
|
-
[BlendMode.None]: createWgpuBlendState('one', 'zero'),
|
|
139
133
|
[BlendMode.Normal]: NORMAL_BLEND,
|
|
140
|
-
[BlendMode.Overlay]: null,
|
|
141
134
|
[BlendMode.Screen]: createWgpuBlendState('one', 'one-minus-src'),
|
|
142
|
-
[BlendMode.Shader]: null,
|
|
143
|
-
[BlendMode.Subtract]: createWgpuBlendState('one', 'one', 'reverse-subtract'),
|
|
144
135
|
};
|
|
145
136
|
// ---- Pipeline creation ----
|
|
146
137
|
export function createWgpuBindGroupLayouts(device) {
|
package/dist/wgpuShader.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"wgpuShader.js","sourceRoot":"","sources":["../src/wgpuShader.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAE5C,OAAO,EAAE,yBAAyB,EAAE,MAAM,mBAAmB,CAAC;AAI9D,wBAAwB;AAExB,uEAAuE;AACvE,kFAAkF;AAClF,6BAA6B;AAC7B,yCAAyC;AACzC,kCAAkC;AAClC,yCAAyC;AACzC,qCAAqC;AACrC,iEAAiE;AACjE,6DAA6D;AAC7D,2EAA2E;AAC3E,MAAM,CAAC,MAAM,iBAAiB,GAAG,GAAG,CAAC;AAErC,MAAM,iBAAiB,GAAG,UAAU,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAyDpC,CAAC;AAEF,6DAA6D;AAC7D,2FAA2F;AAC3F,MAAM,iBAAiB,GAAG,UAAU,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2CpC,CAAC;AAMF,MAAM,YAAY,GAAkB,oBAAoB,CAAC,KAAK,EAAE,qBAAqB,CAAC,CAAC;AAEvF,
|
|
1
|
+
{"version":3,"file":"wgpuShader.js","sourceRoot":"","sources":["../src/wgpuShader.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { ImageResource } from '@flighthq/types';
|
|
2
|
+
export declare function uploadWgpuTextureData(device: GPUDevice, texture: GPUTexture, origin: GPUOrigin3D, width: number, height: number, data: Readonly<Uint8ClampedArray<ArrayBuffer>>): void;
|
|
3
|
+
export declare function uploadWgpuTextureElement(device: GPUDevice, texture: GPUTexture, origin: GPUOrigin3D, width: number, height: number, source: GPUCopyExternalImageSource): void;
|
|
4
|
+
export declare function uploadWgpuTextureImageResource(device: GPUDevice, texture: GPUTexture, origin: GPUOrigin3D, image: Readonly<ImageResource>): void;
|
|
5
|
+
//# sourceMappingURL=wgpuTextureUpload.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wgpuTextureUpload.d.ts","sourceRoot":"","sources":["../src/wgpuTextureUpload.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AASrD,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,SAAS,EACjB,OAAO,EAAE,UAAU,EACnB,MAAM,EAAE,WAAW,EACnB,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,QAAQ,CAAC,iBAAiB,CAAC,WAAW,CAAC,CAAC,GAC7C,IAAI,CAON;AAID,wBAAgB,wBAAwB,CACtC,MAAM,EAAE,SAAS,EACjB,OAAO,EAAE,UAAU,EACnB,MAAM,EAAE,WAAW,EACnB,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,0BAA0B,GACjC,IAAI,CAEN;AAID,wBAAgB,8BAA8B,CAC5C,MAAM,EAAE,SAAS,EACjB,OAAO,EAAE,UAAU,EACnB,MAAM,EAAE,WAAW,EACnB,KAAK,EAAE,QAAQ,CAAC,aAAa,CAAC,GAC7B,IAAI,CAaN"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
// Texel-upload primitives for one texture region. Each writes into `texture` at `origin` (the [x, y, z]
|
|
2
|
+
// where z selects a cube-array layer / cube face). The wgpu mirror of render-gl's glTextureUpload; the
|
|
3
|
+
// caller owns texture creation and format.
|
|
4
|
+
// Uploads rgba8 CPU pixels through queue.writeTexture — the portable bedrock upload, reimplemented 1:1 by
|
|
5
|
+
// a native backend. `bytesPerRow` is width*4: a tightly-packed rgba8unorm (4 bytes/texel) region, which is
|
|
6
|
+
// exactly what a Surface's `data` holds.
|
|
7
|
+
export function uploadWgpuTextureData(device, texture, origin, width, height, data) {
|
|
8
|
+
device.queue.writeTexture({ texture, origin }, data, { bytesPerRow: width * 4, rowsPerImage: height }, [width, height, 1]);
|
|
9
|
+
}
|
|
10
|
+
// Uploads a decoded DOM element through queue.copyExternalImageToTexture — the web fast-path (GPU-side
|
|
11
|
+
// copy, no CPU staging). Absent on non-web hosts.
|
|
12
|
+
export function uploadWgpuTextureElement(device, texture, origin, width, height, source) {
|
|
13
|
+
device.queue.copyExternalImageToTexture({ source }, { texture, origin }, [width, height, 1]);
|
|
14
|
+
}
|
|
15
|
+
// Dispatches an ImageResource to the element fast-path when a decoded `source` is present, else the
|
|
16
|
+
// portable `data` path (a generated Surface). Assumes the resource has pixels in at least one form.
|
|
17
|
+
export function uploadWgpuTextureImageResource(device, texture, origin, image) {
|
|
18
|
+
if (image.source !== null) {
|
|
19
|
+
uploadWgpuTextureElement(device, texture, origin, image.width, image.height, image.source);
|
|
20
|
+
}
|
|
21
|
+
else {
|
|
22
|
+
uploadWgpuTextureData(device, texture, origin, image.width, image.height, image.data);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=wgpuTextureUpload.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wgpuTextureUpload.js","sourceRoot":"","sources":["../src/wgpuTextureUpload.ts"],"names":[],"mappings":"AAEA,wGAAwG;AACxG,uGAAuG;AACvG,2CAA2C;AAE3C,0GAA0G;AAC1G,2GAA2G;AAC3G,yCAAyC;AACzC,MAAM,UAAU,qBAAqB,CACnC,MAAiB,EACjB,OAAmB,EACnB,MAAmB,EACnB,KAAa,EACb,MAAc,EACd,IAA8C;IAE9C,MAAM,CAAC,KAAK,CAAC,YAAY,CACvB,EAAE,OAAO,EAAE,MAAM,EAAE,EACnB,IAAsC,EACtC,EAAE,WAAW,EAAE,KAAK,GAAG,CAAC,EAAE,YAAY,EAAE,MAAM,EAAE,EAChD,CAAC,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC,CACnB,CAAC;AACJ,CAAC;AAED,uGAAuG;AACvG,kDAAkD;AAClD,MAAM,UAAU,wBAAwB,CACtC,MAAiB,EACjB,OAAmB,EACnB,MAAmB,EACnB,KAAa,EACb,MAAc,EACd,MAAkC;IAElC,MAAM,CAAC,KAAK,CAAC,0BAA0B,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC;AAC/F,CAAC;AAED,oGAAoG;AACpG,oGAAoG;AACpG,MAAM,UAAU,8BAA8B,CAC5C,MAAiB,EACjB,OAAmB,EACnB,MAAmB,EACnB,KAA8B;IAE9B,IAAI,KAAK,CAAC,MAAM,KAAK,IAAI,EAAE,CAAC;QAC1B,wBAAwB,CACtB,MAAM,EACN,OAAO,EACP,MAAM,EACN,KAAK,CAAC,KAAK,EACX,KAAK,CAAC,MAAM,EACZ,KAAK,CAAC,MAAoC,CAC3C,CAAC;IACJ,CAAC;SAAM,CAAC;QACN,qBAAqB,CAAC,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,KAAK,EAAE,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC,IAAK,CAAC,CAAC;IACzF,CAAC;AACH,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@flighthq/render-wgpu",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.1-next.410.a23f189",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "https://github.com/flighthq/flight.git",
|
|
@@ -32,11 +32,11 @@
|
|
|
32
32
|
"clean:dist": "tsx ../../scripts/clean-package-dist.ts"
|
|
33
33
|
},
|
|
34
34
|
"dependencies": {
|
|
35
|
-
"@flighthq/displayobject": "0.2.
|
|
36
|
-
"@flighthq/geometry": "0.2.
|
|
37
|
-
"@flighthq/render": "0.2.
|
|
38
|
-
"@flighthq/surface": "0.2.
|
|
39
|
-
"@flighthq/types": "0.2.
|
|
35
|
+
"@flighthq/displayobject": "0.2.1-next.410.a23f189",
|
|
36
|
+
"@flighthq/geometry": "0.2.1-next.410.a23f189",
|
|
37
|
+
"@flighthq/render": "0.2.1-next.410.a23f189",
|
|
38
|
+
"@flighthq/surface": "0.2.1-next.410.a23f189",
|
|
39
|
+
"@flighthq/types": "0.2.1-next.410.a23f189"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
42
|
"@webgpu/types": "*",
|
package/src/wgpuDraw.test.ts
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import { createBitmap } from '@flighthq/displayobject';
|
|
2
2
|
import { getOrCreateRenderProxy2D, prepareDisplayObjectRender } from '@flighthq/render';
|
|
3
|
+
import type { ImageResource } from '@flighthq/types';
|
|
3
4
|
import { BlendMode } from '@flighthq/types';
|
|
4
5
|
|
|
5
6
|
import { renderWgpuBackground, submitWgpuRenderPass } from './wgpuBackground';
|
|
6
7
|
import {
|
|
7
8
|
applyWgpuBlendMode,
|
|
9
|
+
bindWgpuImageResourceTexture,
|
|
8
10
|
bindWgpuTexture,
|
|
9
11
|
buildWgpuRenderTargetBindGroup,
|
|
10
12
|
createWgpuTextureEntry,
|
|
@@ -37,6 +39,56 @@ describe('applyWgpuBlendMode', () => {
|
|
|
37
39
|
});
|
|
38
40
|
});
|
|
39
41
|
|
|
42
|
+
describe('bindWgpuImageResourceTexture', () => {
|
|
43
|
+
function dataResource(size: number, version: number): ImageResource {
|
|
44
|
+
return {
|
|
45
|
+
source: null,
|
|
46
|
+
data: new Uint8ClampedArray(size * size * 4),
|
|
47
|
+
width: size,
|
|
48
|
+
height: size,
|
|
49
|
+
version,
|
|
50
|
+
alphaType: 'straight',
|
|
51
|
+
} as unknown as ImageResource;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
it('uploads a data-only ImageResource (a generated Surface) via writeTexture', async () => {
|
|
55
|
+
const state = await createWgpuRenderStateForTest();
|
|
56
|
+
const writeTexture = vi.spyOn(state.device.queue, 'writeTexture');
|
|
57
|
+
const entry = bindWgpuImageResourceTexture(state, dataResource(4, 1));
|
|
58
|
+
expect(entry.texture).toBeDefined();
|
|
59
|
+
expect(writeTexture).toHaveBeenCalled();
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it('uploads an element-backed ImageResource via copyExternalImageToTexture', async () => {
|
|
63
|
+
const state = await createWgpuRenderStateForTest();
|
|
64
|
+
const copy = vi.spyOn(state.device.queue, 'copyExternalImageToTexture');
|
|
65
|
+
const canvas = document.createElement('canvas');
|
|
66
|
+
canvas.width = 4;
|
|
67
|
+
canvas.height = 4;
|
|
68
|
+
const image = {
|
|
69
|
+
source: canvas,
|
|
70
|
+
data: null,
|
|
71
|
+
width: 4,
|
|
72
|
+
height: 4,
|
|
73
|
+
version: 1,
|
|
74
|
+
alphaType: 'straight',
|
|
75
|
+
} as unknown as ImageResource;
|
|
76
|
+
bindWgpuImageResourceTexture(state, image);
|
|
77
|
+
expect(copy).toHaveBeenCalled();
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
it('caches by resource identity and re-uploads only when the version changes', async () => {
|
|
81
|
+
const state = await createWgpuRenderStateForTest();
|
|
82
|
+
const image = dataResource(2, 1);
|
|
83
|
+
const first = bindWgpuImageResourceTexture(state, image);
|
|
84
|
+
expect(bindWgpuImageResourceTexture(state, image)).toBe(first);
|
|
85
|
+
const createTexture = vi.spyOn(state.device, 'createTexture');
|
|
86
|
+
image.version = 2;
|
|
87
|
+
bindWgpuImageResourceTexture(state, image);
|
|
88
|
+
expect(createTexture).toHaveBeenCalled();
|
|
89
|
+
});
|
|
90
|
+
});
|
|
91
|
+
|
|
40
92
|
describe('bindWgpuTexture', () => {
|
|
41
93
|
it('creates and caches a texture entry', async () => {
|
|
42
94
|
const state = await createWgpuRenderStateForTest();
|
|
@@ -48,6 +100,29 @@ describe('bindWgpuTexture', () => {
|
|
|
48
100
|
expect(entry.texture).toBeDefined();
|
|
49
101
|
expect(bindWgpuTexture(state, canvas)).toBe(entry);
|
|
50
102
|
});
|
|
103
|
+
|
|
104
|
+
it('allocates a single mip level and generates no chain by default', async () => {
|
|
105
|
+
const state = await createWgpuRenderStateForTest();
|
|
106
|
+
const createTexture = vi.spyOn(state.device, 'createTexture');
|
|
107
|
+
const canvas = document.createElement('canvas');
|
|
108
|
+
canvas.width = 8;
|
|
109
|
+
canvas.height = 8;
|
|
110
|
+
bindWgpuTexture(state, canvas);
|
|
111
|
+
expect(createTexture).toHaveBeenCalledWith(expect.objectContaining({ mipLevelCount: 1 }));
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
it('allocates a full mip chain and generates it when generateMips is true', async () => {
|
|
115
|
+
const state = await createWgpuRenderStateForTest();
|
|
116
|
+
const createTexture = vi.spyOn(state.device, 'createTexture');
|
|
117
|
+
const submit = vi.spyOn(state.device.queue, 'submit');
|
|
118
|
+
const canvas = document.createElement('canvas');
|
|
119
|
+
canvas.width = 8;
|
|
120
|
+
canvas.height = 8;
|
|
121
|
+
bindWgpuTexture(state, canvas, true);
|
|
122
|
+
// 8x8 → 4 mip levels; the lower 3 are rendered via generateWgpuMipmaps (a queue submit).
|
|
123
|
+
expect(createTexture).toHaveBeenCalledWith(expect.objectContaining({ mipLevelCount: 4 }));
|
|
124
|
+
expect(submit).toHaveBeenCalled();
|
|
125
|
+
});
|
|
51
126
|
});
|
|
52
127
|
|
|
53
128
|
describe('buildWgpuRenderTargetBindGroup', () => {
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import type { WgpuRenderState } from '@flighthq/types';
|
|
2
|
+
|
|
3
|
+
import { generateWgpuMipmaps, getWgpuMipLevelCount } from './wgpuMipmap';
|
|
4
|
+
import { getWgpuRenderStateRuntime } from './wgpuRenderState';
|
|
5
|
+
import { createWgpuRenderStateForTest, installWgpuMock } from './wgpuTestHelper';
|
|
6
|
+
|
|
7
|
+
beforeAll(() => {
|
|
8
|
+
installWgpuMock();
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
function makeTextureSpy(): GPUTexture {
|
|
12
|
+
return { createView: vi.fn(() => ({}) as GPUTextureView), destroy: () => {} } as unknown as GPUTexture;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
// Replaces the mock device's command encoder with one whose render passes are spies, so a test can
|
|
16
|
+
// count how many downsample passes generateWgpuMipmaps opens. Returns the beginRenderPass spy.
|
|
17
|
+
function spyEncoderPasses(state: WgpuRenderState): ReturnType<typeof vi.fn> {
|
|
18
|
+
const beginRenderPass = vi.fn(
|
|
19
|
+
() =>
|
|
20
|
+
({
|
|
21
|
+
setPipeline: vi.fn(),
|
|
22
|
+
setBindGroup: vi.fn(),
|
|
23
|
+
draw: vi.fn(),
|
|
24
|
+
end: vi.fn(),
|
|
25
|
+
}) as unknown as GPURenderPassEncoder,
|
|
26
|
+
);
|
|
27
|
+
const encoder = { beginRenderPass, finish: () => ({}) as GPUCommandBuffer } as unknown as GPUCommandEncoder;
|
|
28
|
+
vi.spyOn(state.device, 'createCommandEncoder').mockReturnValue(encoder);
|
|
29
|
+
return beginRenderPass;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
describe('generateWgpuMipmaps', () => {
|
|
33
|
+
it('renders one downsample pass per generated mip level for a multi-level texture', async () => {
|
|
34
|
+
const state = await createWgpuRenderStateForTest();
|
|
35
|
+
const beginRenderPass = spyEncoderPasses(state);
|
|
36
|
+
const submit = vi.spyOn(state.device.queue, 'submit');
|
|
37
|
+
generateWgpuMipmaps(state, makeTextureSpy(), 4, 4, 'rgba8unorm');
|
|
38
|
+
// 4x4 → 3 levels → 2 downsample passes into levels 1 and 2.
|
|
39
|
+
expect(beginRenderPass).toHaveBeenCalledTimes(2);
|
|
40
|
+
expect(submit).toHaveBeenCalledTimes(1);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it('is a no-op for a single-level (1x1) texture', async () => {
|
|
44
|
+
const state = await createWgpuRenderStateForTest();
|
|
45
|
+
const beginRenderPass = spyEncoderPasses(state);
|
|
46
|
+
const submit = vi.spyOn(state.device.queue, 'submit');
|
|
47
|
+
generateWgpuMipmaps(state, makeTextureSpy(), 1, 1, 'rgba8unorm');
|
|
48
|
+
expect(beginRenderPass).not.toHaveBeenCalled();
|
|
49
|
+
expect(submit).not.toHaveBeenCalled();
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it('builds the downsample pipeline once and reuses it across textures', async () => {
|
|
53
|
+
const state = await createWgpuRenderStateForTest();
|
|
54
|
+
spyEncoderPasses(state);
|
|
55
|
+
generateWgpuMipmaps(state, makeTextureSpy(), 4, 4, 'rgba8unorm');
|
|
56
|
+
const pipeline = getWgpuRenderStateRuntime(state).mipmapPipeline;
|
|
57
|
+
expect(pipeline).toBeDefined();
|
|
58
|
+
generateWgpuMipmaps(state, makeTextureSpy(), 8, 8, 'rgba8unorm');
|
|
59
|
+
expect(getWgpuRenderStateRuntime(state).mipmapPipeline).toBe(pipeline);
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
describe('getWgpuMipLevelCount', () => {
|
|
64
|
+
it('returns 1 for a 1x1 base', () => {
|
|
65
|
+
expect(getWgpuMipLevelCount(1, 1)).toBe(1);
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
it('counts the full chain down to 1x1 using the larger dimension', () => {
|
|
69
|
+
expect(getWgpuMipLevelCount(8, 8)).toBe(4);
|
|
70
|
+
expect(getWgpuMipLevelCount(256, 1)).toBe(9);
|
|
71
|
+
expect(getWgpuMipLevelCount(5, 3)).toBe(3);
|
|
72
|
+
});
|
|
73
|
+
});
|
|
@@ -2,6 +2,7 @@ import {
|
|
|
2
2
|
createWgpuRenderStateRuntime,
|
|
3
3
|
destroyWgpuRenderState,
|
|
4
4
|
getWgpuRenderStateRuntime,
|
|
5
|
+
getWgpuSampler,
|
|
5
6
|
isWgpuSupported,
|
|
6
7
|
} from './wgpuRenderState';
|
|
7
8
|
import { createWgpuRenderStateForTest, installWgpuMock } from './wgpuTestHelper';
|
|
@@ -81,6 +82,51 @@ describe('getWgpuRenderStateRuntime', () => {
|
|
|
81
82
|
});
|
|
82
83
|
});
|
|
83
84
|
|
|
85
|
+
describe('getWgpuSampler', () => {
|
|
86
|
+
it('caches a sampler per filter+wrap+mip+anisotropy key and reuses it', async () => {
|
|
87
|
+
const state = await createWgpuRenderStateForTest();
|
|
88
|
+
const a = getWgpuSampler(state, 'linear', 'repeat', 'repeat');
|
|
89
|
+
const b = getWgpuSampler(state, 'linear', 'repeat', 'repeat');
|
|
90
|
+
expect(a).toBe(b);
|
|
91
|
+
expect(getWgpuRenderStateRuntime(state).samplerCache.get('linear|repeat|repeat|none|1')).toBe(a);
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
it('returns a distinct sampler for a different wrap or filter', async () => {
|
|
95
|
+
const state = await createWgpuRenderStateForTest();
|
|
96
|
+
const repeat = getWgpuSampler(state, 'linear', 'repeat', 'repeat');
|
|
97
|
+
const clamp = getWgpuSampler(state, 'linear', 'clamp-to-edge', 'clamp-to-edge');
|
|
98
|
+
const nearest = getWgpuSampler(state, 'nearest', 'repeat', 'repeat');
|
|
99
|
+
expect(repeat).not.toBe(clamp);
|
|
100
|
+
expect(repeat).not.toBe(nearest);
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
it('keys the mip filter separately so a trilinear sampler differs from a non-mip one', async () => {
|
|
104
|
+
const state = await createWgpuRenderStateForTest();
|
|
105
|
+
const noMip = getWgpuSampler(state, 'linear', 'repeat', 'repeat');
|
|
106
|
+
const trilinear = getWgpuSampler(state, 'linear', 'repeat', 'repeat', 'linear');
|
|
107
|
+
expect(noMip).not.toBe(trilinear);
|
|
108
|
+
expect(getWgpuRenderStateRuntime(state).samplerCache.has('linear|repeat|repeat|linear|1')).toBe(true);
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
it('forces linear filtering and a linear mip filter when anisotropy exceeds 1', async () => {
|
|
112
|
+
// WebGPU rejects maxAnisotropy > 1 unless min/mag/mip are all linear, so a nearest+aniso request
|
|
113
|
+
// collapses to the linear anisotropic key.
|
|
114
|
+
const state = await createWgpuRenderStateForTest();
|
|
115
|
+
const sampler = getWgpuSampler(state, 'nearest', 'clamp-to-edge', 'clamp-to-edge', undefined, 8);
|
|
116
|
+
const cache = getWgpuRenderStateRuntime(state).samplerCache;
|
|
117
|
+
expect(cache.get('linear|clamp-to-edge|clamp-to-edge|linear|8')).toBe(sampler);
|
|
118
|
+
expect(cache.has('nearest|clamp-to-edge|clamp-to-edge|none|8')).toBe(false);
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
it('floors and clamps the anisotropy level into the cache key', async () => {
|
|
122
|
+
const state = await createWgpuRenderStateForTest();
|
|
123
|
+
const a = getWgpuSampler(state, 'linear', 'repeat', 'repeat', 'linear', 4.9);
|
|
124
|
+
const b = getWgpuSampler(state, 'linear', 'repeat', 'repeat', 'linear', 4);
|
|
125
|
+
expect(a).toBe(b);
|
|
126
|
+
expect(getWgpuRenderStateRuntime(state).samplerCache.has('linear|repeat|repeat|linear|4')).toBe(true);
|
|
127
|
+
});
|
|
128
|
+
});
|
|
129
|
+
|
|
84
130
|
describe('isWgpuSupported', () => {
|
|
85
131
|
it('returns true when navigator.gpu is present', () => {
|
|
86
132
|
expect(isWgpuSupported()).toBe(true);
|