longpipe 0.0.14 → 0.0.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +32 -270
- package/dist/chunk-NYCCJS3G.js +4924 -0
- package/dist/index-BctoEDhZ.d.cts +288 -0
- package/dist/index-BctoEDhZ.d.ts +288 -0
- package/dist/index.d.cts +3 -229
- package/dist/index.d.ts +3 -229
- package/dist/index.js +4 -4926
- package/dist/model.cjs +7008 -0
- package/dist/model.d.cts +155 -0
- package/dist/model.d.ts +155 -0
- package/dist/model.js +2085 -0
- package/package.json +7 -2
package/dist/model.js
ADDED
|
@@ -0,0 +1,2085 @@
|
|
|
1
|
+
import {a,b,f as f$1,g,c as c$1,e,d}from'./chunk-NYCCJS3G.js';export{h as WebGPUBackend}from'./chunk-NYCCJS3G.js';var Ct=`#version 300 es
|
|
2
|
+
const vec2 VERTS[6] = vec2[6](
|
|
3
|
+
vec2(-1.0,-1.0), vec2(1.0,-1.0), vec2(-1.0,1.0),
|
|
4
|
+
vec2(-1.0,1.0), vec2(1.0,-1.0), vec2(1.0,1.0)
|
|
5
|
+
);
|
|
6
|
+
void main() { gl_Position = vec4(VERTS[gl_VertexID], 0.0, 1.0); }`,c=class{constructor(e){this.backend=e;}backend;shader="";program;samplers=[];uniformInts={};uniformFloats={};makeTexture(e,t,r){let o=this.backend.gl,i=this.backend.textureFormat,s=this.backend.toTextureView(e),n=o.createTexture();return o.bindTexture(o.TEXTURE_2D,n),o.texImage2D(o.TEXTURE_2D,0,i.internalFormat,t,r,0,i.format,i.type,s),o.texParameteri(o.TEXTURE_2D,o.TEXTURE_MIN_FILTER,o.NEAREST),o.texParameteri(o.TEXTURE_2D,o.TEXTURE_MAG_FILTER,o.NEAREST),o.texParameteri(o.TEXTURE_2D,o.TEXTURE_WRAP_S,o.CLAMP_TO_EDGE),o.texParameteri(o.TEXTURE_2D,o.TEXTURE_WRAP_T,o.CLAMP_TO_EDGE),n}defaultSetup(){let e=this.backend.gl,t=e.createShader(e.VERTEX_SHADER);e.shaderSource(t,Ct),e.compileShader(t);let r=e.createShader(e.FRAGMENT_SHADER);if(e.shaderSource(r,this.shader),e.compileShader(r),!e.getShaderParameter(r,e.COMPILE_STATUS))throw new Error(`GLSL compile error: ${e.getShaderInfoLog(r)}`);if(this.program=e.createProgram(),e.attachShader(this.program,t),e.attachShader(this.program,r),e.linkProgram(this.program),!e.getProgramParameter(this.program,e.LINK_STATUS))throw new Error(`GLSL link error: ${e.getProgramInfoLog(this.program)}`)}run(){let e=this.backend.gl;e.useProgram(this.program),this.samplers.forEach(({name:t,texture:r},o)=>{e.activeTexture(e.TEXTURE0+o),e.bindTexture(e.TEXTURE_2D,r),e.uniform1i(e.getUniformLocation(this.program,t),o);});for(let[t,r]of Object.entries(this.uniformInts))e.uniform1i(e.getUniformLocation(this.program,t),r);for(let[t,r]of Object.entries(this.uniformFloats))e.uniform1f(e.getUniformLocation(this.program,t),r);e.bindFramebuffer(e.FRAMEBUFFER,this.backend.fbo),e.framebufferTexture2D(e.FRAMEBUFFER,e.COLOR_ATTACHMENT0,e.TEXTURE_2D,this.output.texture,0),e.viewport(0,0,this.dispatch[0],this.dispatch[1]),e.bindVertexArray(null),e.drawArrays(e.TRIANGLES,0,6);}};var Re=`#version 300 es
|
|
7
|
+
// Conv2d \u2014 handles all variants: 1\xD71 (pointwise), 3\xD73, 5\xD75, strided, BN-fused.
|
|
8
|
+
//
|
|
9
|
+
// Tensor layout: NHWC vec4 \u2014 texture dimensions (W * C/4, H).
|
|
10
|
+
// texel (x * C_groups + c_group, y) = channels [c_group*4 .. c_group*4+3] at pixel (x,y).
|
|
11
|
+
//
|
|
12
|
+
// Weight layout: (I_groups * 4, K\xB2 * O_groups) RGBA32F texture.
|
|
13
|
+
// Row = z * u_out_c_groups + o_group (kernel_pos outer, out_group inner)
|
|
14
|
+
// Col = i_group * 4 + mat_col (4 texels per mat4)
|
|
15
|
+
// mat4[col][row] = weight(in_channel=col, out_channel=row)
|
|
16
|
+
// Operation: (mat4 * in_val)[r] = \u03A3_c weight(in=c, out=r) * in_val[c] \u2014 same as WGSL.
|
|
17
|
+
//
|
|
18
|
+
// Bias layout: (O_groups, 1).
|
|
19
|
+
//
|
|
20
|
+
// Padding model: pad_top / pad_left applied to input offset; right/bottom asymmetry
|
|
21
|
+
// is handled implicitly by the bounds check, same as the WGSL implementation.
|
|
22
|
+
|
|
23
|
+
precision highp float;
|
|
24
|
+
precision highp int;
|
|
25
|
+
|
|
26
|
+
uniform sampler2D u_input; // (in_W * in_C_groups, in_H)
|
|
27
|
+
uniform sampler2D u_weights; // (in_C_groups * 4, K\xB2 * out_C_groups)
|
|
28
|
+
uniform sampler2D u_bias; // (out_C_groups, 1)
|
|
29
|
+
|
|
30
|
+
uniform int u_in_w;
|
|
31
|
+
uniform int u_in_h;
|
|
32
|
+
uniform int u_in_c_groups;
|
|
33
|
+
uniform int u_out_c_groups;
|
|
34
|
+
uniform int u_kernel_h;
|
|
35
|
+
uniform int u_kernel_w;
|
|
36
|
+
uniform int u_stride;
|
|
37
|
+
uniform int u_pad_top;
|
|
38
|
+
uniform int u_pad_left;
|
|
39
|
+
uniform int u_activation; // 0 = none, 1 = relu6, 2 = relu, 3 = leaky(0.1)
|
|
40
|
+
|
|
41
|
+
out vec4 fragColor;
|
|
42
|
+
|
|
43
|
+
void main() {
|
|
44
|
+
int fx = int(gl_FragCoord.x);
|
|
45
|
+
int fy = int(gl_FragCoord.y);
|
|
46
|
+
int x_out = fx / u_out_c_groups;
|
|
47
|
+
int y_out = fy;
|
|
48
|
+
int o_group = fx - x_out * u_out_c_groups;
|
|
49
|
+
|
|
50
|
+
vec4 result = texelFetch(u_bias, ivec2(o_group, 0), 0);
|
|
51
|
+
|
|
52
|
+
for (int ky = 0; ky < u_kernel_h; ky++) {
|
|
53
|
+
for (int kx = 0; kx < u_kernel_w; kx++) {
|
|
54
|
+
int in_y = y_out * u_stride + ky - u_pad_top;
|
|
55
|
+
int in_x = x_out * u_stride + kx - u_pad_left;
|
|
56
|
+
|
|
57
|
+
if (in_y < 0 || in_y >= u_in_h || in_x < 0 || in_x >= u_in_w) continue;
|
|
58
|
+
|
|
59
|
+
int z = ky * u_kernel_w + kx;
|
|
60
|
+
int w_row = z * u_out_c_groups + o_group;
|
|
61
|
+
|
|
62
|
+
for (int i = 0; i < u_in_c_groups; i++) {
|
|
63
|
+
vec4 in_val = texelFetch(u_input, ivec2(in_x * u_in_c_groups + i, in_y), 0);
|
|
64
|
+
|
|
65
|
+
int base = i * 4;
|
|
66
|
+
mat4 w = mat4(
|
|
67
|
+
texelFetch(u_weights, ivec2(base, w_row), 0),
|
|
68
|
+
texelFetch(u_weights, ivec2(base + 1, w_row), 0),
|
|
69
|
+
texelFetch(u_weights, ivec2(base + 2, w_row), 0),
|
|
70
|
+
texelFetch(u_weights, ivec2(base + 3, w_row), 0)
|
|
71
|
+
);
|
|
72
|
+
result += w * in_val;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
if (u_activation == 1) result = clamp(result, 0.0, 6.0);
|
|
78
|
+
else if (u_activation == 2) result = max(result, vec4(0.0));
|
|
79
|
+
else if (u_activation == 3) result = max(result, 0.1 * result);
|
|
80
|
+
|
|
81
|
+
fragColor = result;
|
|
82
|
+
}
|
|
83
|
+
`;var E=class extends c{inputs;weights;output;dispatch;shader=Re;constructor(e$1,t,r,o){super(e$1);let i=c$1(t.h,o.kernel,o.stride,o.padding),s=c$1(t.w,o.kernel,o.stride,o.padding),n=t.c/4,u=o.outChannels/4,l=e(o.padding,t.h,i,o.kernel,o.stride),p=e(o.padding,t.w,s,o.kernel,o.stride),h=f$1(r.weights),m=f$1(r.bias),x=this.makeTexture(h,n*4,o.kernel*o.kernel*u),_=this.makeTexture(m,u,1),g=s*u,b=this.makeTexture(null,g,i);this.output={h:i,w:s,c:o.outChannels,texture:b,texW:g,texH:i},this.inputs=[t],this.weights=[],this.samplers=[{name:"u_input",texture:t.texture},{name:"u_weights",texture:x},{name:"u_bias",texture:_}],this.uniformInts={u_in_w:t.w,u_in_h:t.h,u_in_c_groups:n,u_out_c_groups:u,u_kernel_h:o.kernel,u_kernel_w:o.kernel,u_stride:o.stride,u_pad_top:l,u_pad_left:p,u_activation:o.activation==="relu6"?1:o.activation==="relu"?2:o.activation==="leaky"?3:0},this.defaultSetup(),this.dispatch=[g,i];}};var De=`#version 300 es
|
|
84
|
+
// ConvTranspose2d \u2014 gather form. Identical texture layouts + mat4 weight
|
|
85
|
+
// semantics as conv2d.glsl; only the spatial mapping differs:
|
|
86
|
+
// in_y = (y_out + pad - ky) / stride (must divide evenly + be in bounds)
|
|
87
|
+
// No explicit kernel flip \u2014 the (y_out + pad - ky) indexing carries it.
|
|
88
|
+
|
|
89
|
+
precision highp float;
|
|
90
|
+
precision highp int;
|
|
91
|
+
|
|
92
|
+
uniform sampler2D u_input; // (in_W * in_C_groups, in_H)
|
|
93
|
+
uniform sampler2D u_weights; // (in_C_groups * 4, K\xB2 * out_C_groups)
|
|
94
|
+
uniform sampler2D u_bias; // (out_C_groups, 1)
|
|
95
|
+
|
|
96
|
+
uniform int u_in_w;
|
|
97
|
+
uniform int u_in_h;
|
|
98
|
+
uniform int u_in_c_groups;
|
|
99
|
+
uniform int u_out_c_groups;
|
|
100
|
+
uniform int u_kernel_h;
|
|
101
|
+
uniform int u_kernel_w;
|
|
102
|
+
uniform int u_stride;
|
|
103
|
+
uniform int u_pad_top;
|
|
104
|
+
uniform int u_pad_left;
|
|
105
|
+
uniform int u_activation; // 0 = none, 1 = relu6, 2 = relu, 3 = leaky(0.1)
|
|
106
|
+
|
|
107
|
+
out vec4 fragColor;
|
|
108
|
+
|
|
109
|
+
void main() {
|
|
110
|
+
int fx = int(gl_FragCoord.x);
|
|
111
|
+
int fy = int(gl_FragCoord.y);
|
|
112
|
+
int x_out = fx / u_out_c_groups;
|
|
113
|
+
int y_out = fy;
|
|
114
|
+
int o_group = fx - x_out * u_out_c_groups;
|
|
115
|
+
|
|
116
|
+
vec4 result = texelFetch(u_bias, ivec2(o_group, 0), 0);
|
|
117
|
+
|
|
118
|
+
for (int ky = 0; ky < u_kernel_h; ky++) {
|
|
119
|
+
for (int kx = 0; kx < u_kernel_w; kx++) {
|
|
120
|
+
int iy_num = y_out + u_pad_top - ky;
|
|
121
|
+
int ix_num = x_out + u_pad_left - kx;
|
|
122
|
+
if (iy_num < 0 || ix_num < 0) continue;
|
|
123
|
+
if ((iy_num % u_stride) != 0 || (ix_num % u_stride) != 0) continue;
|
|
124
|
+
int in_y = iy_num / u_stride;
|
|
125
|
+
int in_x = ix_num / u_stride;
|
|
126
|
+
if (in_y >= u_in_h || in_x >= u_in_w) continue;
|
|
127
|
+
|
|
128
|
+
int z = ky * u_kernel_w + kx;
|
|
129
|
+
int w_row = z * u_out_c_groups + o_group;
|
|
130
|
+
|
|
131
|
+
for (int i = 0; i < u_in_c_groups; i++) {
|
|
132
|
+
vec4 in_val = texelFetch(u_input, ivec2(in_x * u_in_c_groups + i, in_y), 0);
|
|
133
|
+
|
|
134
|
+
int base = i * 4;
|
|
135
|
+
mat4 w = mat4(
|
|
136
|
+
texelFetch(u_weights, ivec2(base, w_row), 0),
|
|
137
|
+
texelFetch(u_weights, ivec2(base + 1, w_row), 0),
|
|
138
|
+
texelFetch(u_weights, ivec2(base + 2, w_row), 0),
|
|
139
|
+
texelFetch(u_weights, ivec2(base + 3, w_row), 0)
|
|
140
|
+
);
|
|
141
|
+
result += w * in_val;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
if (u_activation == 1) result = clamp(result, 0.0, 6.0);
|
|
147
|
+
else if (u_activation == 2) result = max(result, vec4(0.0));
|
|
148
|
+
else if (u_activation == 3) result = max(result, 0.1 * result);
|
|
149
|
+
|
|
150
|
+
fragColor = result;
|
|
151
|
+
}
|
|
152
|
+
`;var G=class extends c{inputs;weights;output;dispatch;shader=De;constructor(e,t,r,o){super(e);let i=d(t.h,o.kernel,o.stride,o.padding),s=d(t.w,o.kernel,o.stride,o.padding),n=t.c/4,u=o.outChannels/4,l=f$1(r.weights),p=f$1(r.bias),h=this.makeTexture(l,n*4,o.kernel*o.kernel*u),m=this.makeTexture(p,u,1),x=s*u,_=this.makeTexture(null,x,i);this.output={h:i,w:s,c:o.outChannels,texture:_,texW:x,texH:i},this.inputs=[t],this.weights=[],this.samplers=[{name:"u_input",texture:t.texture},{name:"u_weights",texture:h},{name:"u_bias",texture:m}],this.uniformInts={u_in_w:t.w,u_in_h:t.h,u_in_c_groups:n,u_out_c_groups:u,u_kernel_h:o.kernel,u_kernel_w:o.kernel,u_stride:o.stride,u_pad_top:o.padding,u_pad_left:o.padding,u_activation:o.activation==="relu6"?1:o.activation==="relu"?2:o.activation==="leaky"?3:0},this.defaultSetup(),this.dispatch=[x,i];}};var Be=`#version 300 es
|
|
153
|
+
// Depthwise Conv2d \u2014 groups = in_channels (each channel convolved independently).
|
|
154
|
+
//
|
|
155
|
+
// Weight layout: (C_groups, K\xB2) RGBA32F texture \u2014 contrast with conv2d which uses mat4.
|
|
156
|
+
// texel (c_group, z) = vec4 kernel weights for 4 channels at kernel position z.
|
|
157
|
+
// Operation: element-wise multiply (not matmul). 4\xD7 smaller than a mat4 approach.
|
|
158
|
+
//
|
|
159
|
+
// Padding model: same asymmetric SAME-pad handling as conv2d.glsl.
|
|
160
|
+
|
|
161
|
+
precision highp float;
|
|
162
|
+
precision highp int;
|
|
163
|
+
|
|
164
|
+
uniform sampler2D u_input; // (in_W * C_groups, in_H)
|
|
165
|
+
uniform sampler2D u_weights; // (C_groups, K\xB2)
|
|
166
|
+
uniform sampler2D u_bias; // (C_groups, 1)
|
|
167
|
+
|
|
168
|
+
uniform int u_in_w;
|
|
169
|
+
uniform int u_in_h;
|
|
170
|
+
uniform int u_c_groups;
|
|
171
|
+
uniform int u_kernel_h;
|
|
172
|
+
uniform int u_kernel_w;
|
|
173
|
+
uniform int u_stride;
|
|
174
|
+
uniform int u_pad_top;
|
|
175
|
+
uniform int u_pad_left;
|
|
176
|
+
uniform int u_apply_relu6; // 0 = none, 1 = relu6
|
|
177
|
+
|
|
178
|
+
out vec4 fragColor;
|
|
179
|
+
|
|
180
|
+
void main() {
|
|
181
|
+
int fx = int(gl_FragCoord.x);
|
|
182
|
+
int fy = int(gl_FragCoord.y);
|
|
183
|
+
int x_out = fx / u_c_groups;
|
|
184
|
+
int y_out = fy;
|
|
185
|
+
int c_group = fx - x_out * u_c_groups;
|
|
186
|
+
|
|
187
|
+
vec4 result = texelFetch(u_bias, ivec2(c_group, 0), 0);
|
|
188
|
+
|
|
189
|
+
for (int ky = 0; ky < u_kernel_h; ky++) {
|
|
190
|
+
for (int kx = 0; kx < u_kernel_w; kx++) {
|
|
191
|
+
int in_y = y_out * u_stride + ky - u_pad_top;
|
|
192
|
+
int in_x = x_out * u_stride + kx - u_pad_left;
|
|
193
|
+
|
|
194
|
+
if (in_y < 0 || in_y >= u_in_h || in_x < 0 || in_x >= u_in_w) continue;
|
|
195
|
+
|
|
196
|
+
int z = ky * u_kernel_w + kx;
|
|
197
|
+
|
|
198
|
+
vec4 in_val = texelFetch(u_input, ivec2(in_x * u_c_groups + c_group, in_y), 0);
|
|
199
|
+
vec4 w = texelFetch(u_weights, ivec2(c_group, z), 0);
|
|
200
|
+
|
|
201
|
+
result += w * in_val; // element-wise multiply, not matmul
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
if (u_apply_relu6 == 1) result = clamp(result, 0.0, 6.0);
|
|
206
|
+
|
|
207
|
+
fragColor = result;
|
|
208
|
+
}
|
|
209
|
+
`;var F=class extends c{inputs;weights;output;dispatch;shader=Be;constructor(e$1,t,r,o){super(e$1);let i=c$1(t.h,o.kernel,o.stride,o.padding),s=c$1(t.w,o.kernel,o.stride,o.padding),n=t.c/4,u=e(o.padding,t.h,i,o.kernel,o.stride),l=e(o.padding,t.w,s,o.kernel,o.stride),p=f$1(r.weights),h=f$1(r.bias),m=this.makeTexture(p,n,o.kernel*o.kernel),x=this.makeTexture(h,n,1),_=s*n,g=this.makeTexture(null,_,i);this.output={h:i,w:s,c:t.c,texture:g,texW:_,texH:i},this.inputs=[t],this.weights=[],this.samplers=[{name:"u_input",texture:t.texture},{name:"u_weights",texture:m},{name:"u_bias",texture:x}],this.uniformInts={u_in_w:t.w,u_in_h:t.h,u_c_groups:n,u_kernel_h:o.kernel,u_kernel_w:o.kernel,u_stride:o.stride,u_pad_top:u,u_pad_left:l,u_apply_relu6:o.activation==="relu6"?1:0},this.defaultSetup(),this.dispatch=[_,i];}};var Ue=`#version 300 es
|
|
210
|
+
// Element-wise add \u2014 both inputs and output share the same texture dimensions.
|
|
211
|
+
// Works for any 2D layout; used here with a flat (nVec4, 1) texture.
|
|
212
|
+
|
|
213
|
+
precision highp float;
|
|
214
|
+
|
|
215
|
+
uniform sampler2D u_input_a;
|
|
216
|
+
uniform sampler2D u_input_b;
|
|
217
|
+
|
|
218
|
+
out vec4 fragColor;
|
|
219
|
+
|
|
220
|
+
void main() {
|
|
221
|
+
ivec2 fc = ivec2(gl_FragCoord.xy);
|
|
222
|
+
fragColor = texelFetch(u_input_a, fc, 0) + texelFetch(u_input_b, fc, 0);
|
|
223
|
+
}
|
|
224
|
+
`;var A=class extends c{inputs;weights=[];output;dispatch;shader=Ue;constructor(e,t,r){super(e);let o=t,i=this.makeTexture(null,o.texW,o.texH);this.output={h:t.h,w:t.w,c:t.c,texture:i,texW:o.texW,texH:o.texH},this.inputs=[t,r],this.samplers=[{name:"u_input_a",texture:t.texture},{name:"u_input_b",texture:r.texture}],this.defaultSetup(),this.dispatch=[o.texW,o.texH];}};var Pe=`#version 300 es
|
|
225
|
+
// Element-wise sigmoid \u2014 works on any texture layout (flat or spatial).
|
|
226
|
+
|
|
227
|
+
precision highp float;
|
|
228
|
+
|
|
229
|
+
uniform sampler2D u_input;
|
|
230
|
+
|
|
231
|
+
out vec4 fragColor;
|
|
232
|
+
|
|
233
|
+
void main() {
|
|
234
|
+
vec4 x = texelFetch(u_input, ivec2(gl_FragCoord.xy), 0);
|
|
235
|
+
fragColor = 1.0 / (1.0 + exp(-x));
|
|
236
|
+
}
|
|
237
|
+
`;var S=class extends c{inputs;weights=[];output;dispatch;shader=Pe;constructor(e,t){super(e);let r=t,o=this.makeTexture(null,r.texW,r.texH);this.output={h:t.h,w:t.w,c:t.c,texture:o,texW:r.texW,texH:r.texH},this.inputs=[t],this.samplers=[{name:"u_input",texture:r.texture}],this.defaultSetup(),this.dispatch=[r.texW,r.texH];}};var Me=`#version 300 es
|
|
238
|
+
// Element-wise tanh \u2014 used by ConvGRU candidate activation.
|
|
239
|
+
// Layout-agnostic (flat or spatial); GLSL tanh is element-wise on vec4.
|
|
240
|
+
|
|
241
|
+
precision highp float;
|
|
242
|
+
|
|
243
|
+
uniform sampler2D u_input;
|
|
244
|
+
|
|
245
|
+
out vec4 fragColor;
|
|
246
|
+
|
|
247
|
+
void main() {
|
|
248
|
+
fragColor = tanh(texelFetch(u_input, ivec2(gl_FragCoord.xy), 0));
|
|
249
|
+
}
|
|
250
|
+
`;var R=class extends c{inputs;weights=[];output;dispatch;shader=Me;constructor(e,t){super(e);let r=t,o=this.makeTexture(null,r.texW,r.texH);this.output={h:t.h,w:t.w,c:t.c,texture:o,texW:r.texW,texH:r.texH},this.inputs=[t],this.samplers=[{name:"u_input",texture:r.texture}],this.defaultSetup(),this.dispatch=[r.texW,r.texH];}};var Oe=`#version 300 es
|
|
251
|
+
// Element-wise multiply \u2014 used in ConvGRU for r \u2299 h_prev.
|
|
252
|
+
// Same shape constraint as add.glsl.
|
|
253
|
+
|
|
254
|
+
precision highp float;
|
|
255
|
+
|
|
256
|
+
uniform sampler2D u_input_a;
|
|
257
|
+
uniform sampler2D u_input_b;
|
|
258
|
+
|
|
259
|
+
out vec4 fragColor;
|
|
260
|
+
|
|
261
|
+
void main() {
|
|
262
|
+
ivec2 fc = ivec2(gl_FragCoord.xy);
|
|
263
|
+
fragColor = texelFetch(u_input_a, fc, 0) * texelFetch(u_input_b, fc, 0);
|
|
264
|
+
}
|
|
265
|
+
`;var D=class extends c{inputs;weights=[];output;dispatch;shader=Oe;constructor(e,t,r){super(e);let o=t,i=this.makeTexture(null,o.texW,o.texH);this.output={h:t.h,w:t.w,c:t.c,texture:i,texW:o.texW,texH:o.texH},this.inputs=[t,r],this.samplers=[{name:"u_input_a",texture:t.texture},{name:"u_input_b",texture:r.texture}],this.defaultSetup(),this.dispatch=[o.texW,o.texH];}};var He=`#version 300 es
|
|
266
|
+
// Bilinear gather-warp. out[p] = sample(source, p + flow_scale\xB7flow[p].xy),
|
|
267
|
+
// edge-clamped. Source/output are (W\xB7G, H) with G = c/4 channel groups
|
|
268
|
+
// (fragment x decomposes to pixel + group, like conv); flow is 4-ch, same
|
|
269
|
+
// spatial resolution, vector in .xy.
|
|
270
|
+
|
|
271
|
+
precision highp float;
|
|
272
|
+
precision highp int;
|
|
273
|
+
|
|
274
|
+
uniform sampler2D u_source; // (W * G, H)
|
|
275
|
+
uniform sampler2D u_flow; // (W, H), flow in .xy
|
|
276
|
+
uniform int u_w;
|
|
277
|
+
uniform int u_h;
|
|
278
|
+
uniform int u_groups;
|
|
279
|
+
uniform float u_flow_scale;
|
|
280
|
+
|
|
281
|
+
out vec4 fragColor;
|
|
282
|
+
|
|
283
|
+
vec4 samp(int x, int y, int g) {
|
|
284
|
+
int cx = clamp(x, 0, u_w - 1);
|
|
285
|
+
int cy = clamp(y, 0, u_h - 1);
|
|
286
|
+
return texelFetch(u_source, ivec2(cx * u_groups + g, cy), 0);
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
void main() {
|
|
290
|
+
int fx = int(gl_FragCoord.x);
|
|
291
|
+
int y = int(gl_FragCoord.y);
|
|
292
|
+
int x = fx / u_groups;
|
|
293
|
+
int g = fx - x * u_groups;
|
|
294
|
+
|
|
295
|
+
vec2 f = texelFetch(u_flow, ivec2(x, y), 0).xy;
|
|
296
|
+
float sx = clamp(float(x) + u_flow_scale * f.x, 0.0, float(u_w - 1));
|
|
297
|
+
float sy = clamp(float(y) + u_flow_scale * f.y, 0.0, float(u_h - 1));
|
|
298
|
+
|
|
299
|
+
int x0 = int(floor(sx));
|
|
300
|
+
int y0 = int(floor(sy));
|
|
301
|
+
float tx = sx - float(x0);
|
|
302
|
+
float ty = sy - float(y0);
|
|
303
|
+
|
|
304
|
+
vec4 top = mix(samp(x0, y0, g), samp(x0 + 1, y0, g), tx);
|
|
305
|
+
vec4 bot = mix(samp(x0, y0 + 1, g), samp(x0 + 1, y0 + 1, g), tx);
|
|
306
|
+
fragColor = mix(top, bot, ty);
|
|
307
|
+
}
|
|
308
|
+
`;var B=class extends c{inputs;weights=[];output;dispatch;shader=He;constructor(e,t,r,o){super(e);let i=t.w,s=t.h,n=t.c/4,u=this.makeTexture(null,i*n,s);this.output={h:s,w:i,c:t.c,texture:u,texW:i*n,texH:s},this.inputs=[t,r],this.samplers=[{name:"u_source",texture:t.texture},{name:"u_flow",texture:r.texture}],this.uniformInts={u_w:i,u_h:s,u_groups:n},this.uniformFloats={u_flow_scale:o.flowScale},this.defaultSetup(),this.dispatch=[i*n,s];}};var Ie=`#version 300 es
|
|
309
|
+
// Face-box decode from 5-keypoint heatmaps. Output is a 1\xD71 texture:
|
|
310
|
+
// (cx, cy, halfSide, score) in FRAME FRACTIONS (halfSide as a fraction of
|
|
311
|
+
// frame WIDTH; the heatmap grid shares the frame's aspect, so squaring in
|
|
312
|
+
// grid px squares in frame px). Peaks refined with a windowed soft-argmax
|
|
313
|
+
// centroid \u2014 NEVER hard argmax (whole-cell snapping jitters the crop).
|
|
314
|
+
//
|
|
315
|
+
// Single fragment does all 5 channels serially \u2014 the grid is tiny (\u2264 ~48\xD728).
|
|
316
|
+
// Heatmap texture: (w * 2, h) \u2014 8 channels = 2 vec4 groups per pixel.
|
|
317
|
+
|
|
318
|
+
precision highp float;
|
|
319
|
+
precision highp int;
|
|
320
|
+
|
|
321
|
+
uniform sampler2D u_hm;
|
|
322
|
+
uniform int u_h;
|
|
323
|
+
uniform int u_w;
|
|
324
|
+
uniform int u_win;
|
|
325
|
+
uniform float u_thresh;
|
|
326
|
+
uniform float u_box_scale;
|
|
327
|
+
|
|
328
|
+
out vec4 fragColor;
|
|
329
|
+
|
|
330
|
+
float hmAt(int x, int y, int k) {
|
|
331
|
+
vec4 v = texelFetch(u_hm, ivec2(x * 2 + k / 4, y), 0);
|
|
332
|
+
return v[k % 4];
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
void main() {
|
|
336
|
+
float x0 = 1e9, x1 = -1e9, y0 = 1e9, y1 = -1e9, score = 1e9;
|
|
337
|
+
|
|
338
|
+
for (int k = 0; k < 5; k++) {
|
|
339
|
+
// Peak.
|
|
340
|
+
float peak = -1.0;
|
|
341
|
+
int pr = 0, pc = 0;
|
|
342
|
+
for (int y = 0; y < u_h; y++) {
|
|
343
|
+
for (int x = 0; x < u_w; x++) {
|
|
344
|
+
float v = hmAt(x, y, k);
|
|
345
|
+
if (v > peak) { peak = v; pr = y; pc = x; }
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
// Windowed soft-argmax centroid.
|
|
349
|
+
int r0 = max(0, pr - u_win), r1 = min(u_h, pr + u_win + 1);
|
|
350
|
+
int c0 = max(0, pc - u_win), c1 = min(u_w, pc + u_win + 1);
|
|
351
|
+
float wsum = 0.0, sy = 0.0, sx = 0.0;
|
|
352
|
+
for (int y = r0; y < r1; y++) {
|
|
353
|
+
for (int x = c0; x < c1; x++) {
|
|
354
|
+
float v = hmAt(x, y, k);
|
|
355
|
+
wsum += v; sy += v * float(y); sx += v * float(x);
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
wsum = max(wsum, 1e-6);
|
|
359
|
+
float kx = sx / wsum, ky = sy / wsum;
|
|
360
|
+
x0 = min(x0, kx); x1 = max(x1, kx);
|
|
361
|
+
y0 = min(y0, ky); y1 = max(y1, ky);
|
|
362
|
+
score = min(score, peak);
|
|
363
|
+
}
|
|
364
|
+
if (score < u_thresh) score = 0.0;
|
|
365
|
+
|
|
366
|
+
float halfPx = 0.5 * u_box_scale * max(x1 - x0, y1 - y0);
|
|
367
|
+
float cx = ((x0 + x1) * 0.5 + 0.5) / float(u_w);
|
|
368
|
+
float cy = ((y0 + y1) * 0.5 + 0.5) / float(u_h);
|
|
369
|
+
fragColor = vec4(cx, cy, halfPx / float(u_w), score);
|
|
370
|
+
}
|
|
371
|
+
`;var U=class extends c{inputs;weights=[];output;dispatch=[1,1];shader=Ie;constructor(e,t,r){if(super(e),t.c!==8)throw new Error(`FaceBoxFromHeatmaps: expected 8-ch heatmaps (5 real), got ${t.c}`);let o=this.makeTexture(null,1,1);this.output={h:1,w:1,c:4,texture:o,texW:1,texH:1},this.inputs=[t],this.samplers=[{name:"u_hm",texture:t.texture}],this.uniformInts={u_h:t.h,u_w:t.w,u_win:r.win},this.uniformFloats={u_thresh:r.thresh,u_box_scale:r.boxScale},this.defaultSetup();}};var Ne=`#version 300 es
|
|
372
|
+
// MULTI-FACE box decode from 5-keypoint heatmaps \u2192 1\xD7K texture, slot i =
|
|
373
|
+
// (cx, cy, halfSide, score) in FRAME FRACTIONS (halfSide a fraction of frame
|
|
374
|
+
// WIDTH). The multi-face sibling of face_box.glsl. See face_boxes.wgsl for the
|
|
375
|
+
// full algorithm commentary \u2014 this mirrors it exactly.
|
|
376
|
+
//
|
|
377
|
+
// WebGL has no compute and no shared memory, so each fragment (= one face slot)
|
|
378
|
+
// independently redoes the ENTIRE decode \u2014 candidates for all 5 channels,
|
|
379
|
+
// hypotheses, NMS \u2014 and emits the slot matching its own x. That's K\xD7 redundant
|
|
380
|
+
// work, which is fine here: the grid is \u2264 ~48\xD728 and K \u2264 6, and it keeps the
|
|
381
|
+
// WGSL and GLSL paths line-for-line comparable.
|
|
382
|
+
//
|
|
383
|
+
// Heatmap texture: (w * 2, h) \u2014 8 channels = 2 vec4 groups per pixel.
|
|
384
|
+
|
|
385
|
+
precision highp float;
|
|
386
|
+
precision highp int;
|
|
387
|
+
|
|
388
|
+
uniform sampler2D u_hm;
|
|
389
|
+
uniform int u_h;
|
|
390
|
+
uniform int u_w;
|
|
391
|
+
uniform int u_win;
|
|
392
|
+
uniform float u_thresh;
|
|
393
|
+
uniform float u_box_scale;
|
|
394
|
+
uniform int u_max_faces;
|
|
395
|
+
uniform float u_tol;
|
|
396
|
+
|
|
397
|
+
out vec4 fragColor;
|
|
398
|
+
|
|
399
|
+
const int N_KP = 5;
|
|
400
|
+
const int MAX_CAND = 5;
|
|
401
|
+
const float LAMBDA = 0.5;
|
|
402
|
+
const float MIN_SEP = 1.0;
|
|
403
|
+
const float MIN_EYE = 1.0;
|
|
404
|
+
|
|
405
|
+
float c_x[25];
|
|
406
|
+
float c_y[25];
|
|
407
|
+
float c_s[25];
|
|
408
|
+
int c_n[5];
|
|
409
|
+
|
|
410
|
+
float hmAt(int x, int y, int k) {
|
|
411
|
+
vec4 v = texelFetch(u_hm, ivec2(x * 2 + k / 4, y), 0);
|
|
412
|
+
return v[k % 4];
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
// ArcFace canonical template in the eye frame (origin = L-eye, +u along the
|
|
416
|
+
// L\u2192R eye vector, +w perpendicular), normalized by interocular distance.
|
|
417
|
+
float tmplU(int t) { return t == 0 ? 0.50002 : (t == 1 ? 0.08598 : 0.91410); }
|
|
418
|
+
float tmplW(int t) { return t == 0 ? 0.57150 : 1.15462; }
|
|
419
|
+
|
|
420
|
+
void main() {
|
|
421
|
+
int myFace = int(gl_FragCoord.x);
|
|
422
|
+
|
|
423
|
+
// \u2500\u2500 stage 1: local-maximum candidates, per channel \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
424
|
+
for (int k = 0; k < N_KP; k++) {
|
|
425
|
+
int pr[5];
|
|
426
|
+
int pc[5];
|
|
427
|
+
float ps[5];
|
|
428
|
+
int n = 0;
|
|
429
|
+
|
|
430
|
+
for (int y = 0; y < u_h; y++) {
|
|
431
|
+
for (int x = 0; x < u_w; x++) {
|
|
432
|
+
float v = hmAt(x, y, k);
|
|
433
|
+
if (v < u_thresh) continue;
|
|
434
|
+
|
|
435
|
+
bool isMax = true;
|
|
436
|
+
for (int dy = -1; dy <= 1; dy++) {
|
|
437
|
+
for (int dx = -1; dx <= 1; dx++) {
|
|
438
|
+
if (dx == 0 && dy == 0) continue;
|
|
439
|
+
int rr = y + dy, cc = x + dx;
|
|
440
|
+
if (rr < 0 || rr >= u_h || cc < 0 || cc >= u_w) continue;
|
|
441
|
+
float u = hmAt(cc, rr, k);
|
|
442
|
+
if (u > v || (u == v && rr * u_w + cc < y * u_w + x)) isMax = false;
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
if (!isMax) continue;
|
|
446
|
+
|
|
447
|
+
int slot = n;
|
|
448
|
+
if (n == MAX_CAND) {
|
|
449
|
+
if (v <= ps[MAX_CAND - 1]) continue;
|
|
450
|
+
slot = MAX_CAND - 1;
|
|
451
|
+
} else {
|
|
452
|
+
n++;
|
|
453
|
+
}
|
|
454
|
+
while (slot > 0 && ps[slot - 1] < v) {
|
|
455
|
+
ps[slot] = ps[slot - 1]; pr[slot] = pr[slot - 1]; pc[slot] = pc[slot - 1];
|
|
456
|
+
slot--;
|
|
457
|
+
}
|
|
458
|
+
ps[slot] = v; pr[slot] = y; pc[slot] = x;
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
int m = 0;
|
|
463
|
+
for (int i = 0; i < n; i++) {
|
|
464
|
+
float rx = float(pc[i]);
|
|
465
|
+
float ry = float(pr[i]);
|
|
466
|
+
if (u_win > 0) {
|
|
467
|
+
int r0 = max(0, pr[i] - u_win), r1 = min(u_h, pr[i] + u_win + 1);
|
|
468
|
+
int c0 = max(0, pc[i] - u_win), c1 = min(u_w, pc[i] + u_win + 1);
|
|
469
|
+
float wsum = 0.0, sy = 0.0, sx = 0.0;
|
|
470
|
+
for (int y = r0; y < r1; y++) {
|
|
471
|
+
for (int x = c0; x < c1; x++) {
|
|
472
|
+
float v = hmAt(x, y, k);
|
|
473
|
+
wsum += v; sy += v * float(y); sx += v * float(x);
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
wsum = max(wsum, 1e-6);
|
|
477
|
+
rx = sx / wsum; ry = sy / wsum;
|
|
478
|
+
}
|
|
479
|
+
bool dup = false;
|
|
480
|
+
for (int j = 0; j < m; j++) {
|
|
481
|
+
float dx = c_x[k * MAX_CAND + j] - rx;
|
|
482
|
+
float dy = c_y[k * MAX_CAND + j] - ry;
|
|
483
|
+
if (sqrt(dx * dx + dy * dy) < MIN_SEP) dup = true;
|
|
484
|
+
}
|
|
485
|
+
if (dup) continue;
|
|
486
|
+
c_x[k * MAX_CAND + m] = rx;
|
|
487
|
+
c_y[k * MAX_CAND + m] = ry;
|
|
488
|
+
c_s[k * MAX_CAND + m] = ps[i];
|
|
489
|
+
m++;
|
|
490
|
+
}
|
|
491
|
+
c_n[k] = m;
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
// \u2500\u2500 stage 2: eye-pair hypotheses \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
495
|
+
float h_score[25];
|
|
496
|
+
int h_kp[125];
|
|
497
|
+
int nh = 0;
|
|
498
|
+
float maxEye = float(u_w) * 0.45;
|
|
499
|
+
|
|
500
|
+
for (int i = 0; i < c_n[0]; i++) {
|
|
501
|
+
for (int j = 0; j < c_n[1]; j++) {
|
|
502
|
+
float ax = c_x[i], ay = c_y[i];
|
|
503
|
+
float bx = c_x[MAX_CAND + j], by = c_y[MAX_CAND + j];
|
|
504
|
+
float evx = bx - ax, evy = by - ay;
|
|
505
|
+
float len = sqrt(evx * evx + evy * evy);
|
|
506
|
+
if (len < MIN_EYE || len > maxEye) continue;
|
|
507
|
+
vec2 ex = vec2(evx / len, evy / len);
|
|
508
|
+
vec2 ey = vec2(-ex.y, ex.x);
|
|
509
|
+
|
|
510
|
+
float sc = c_s[i] + c_s[MAX_CAND + j];
|
|
511
|
+
float resid = 0.0;
|
|
512
|
+
int nMatch = 2, mouths = 0, nose = -1;
|
|
513
|
+
int mo[2];
|
|
514
|
+
mo[0] = -1; mo[1] = -1;
|
|
515
|
+
|
|
516
|
+
for (int t = 0; t < 3; t++) {
|
|
517
|
+
int kk = t + 2;
|
|
518
|
+
float px = ax + len * (tmplU(t) * ex.x + tmplW(t) * ey.x);
|
|
519
|
+
float py = ay + len * (tmplU(t) * ex.y + tmplW(t) * ey.y);
|
|
520
|
+
int best = -1;
|
|
521
|
+
float bestD = u_tol * len;
|
|
522
|
+
for (int q = 0; q < c_n[kk]; q++) {
|
|
523
|
+
float dx = c_x[kk * MAX_CAND + q] - px;
|
|
524
|
+
float dy = c_y[kk * MAX_CAND + q] - py;
|
|
525
|
+
float d = sqrt(dx * dx + dy * dy);
|
|
526
|
+
if (d < bestD) { bestD = d; best = q; }
|
|
527
|
+
}
|
|
528
|
+
if (best < 0) continue;
|
|
529
|
+
sc += c_s[kk * MAX_CAND + best];
|
|
530
|
+
resid += bestD / len;
|
|
531
|
+
nMatch++;
|
|
532
|
+
if (t == 0) nose = best; else { mo[t - 1] = best; mouths++; }
|
|
533
|
+
}
|
|
534
|
+
if (nose < 0 || mouths < 1) continue;
|
|
535
|
+
|
|
536
|
+
h_score[nh] = sc / float(nMatch) - LAMBDA * (resid / float(nMatch - 2));
|
|
537
|
+
h_kp[nh * N_KP + 0] = i;
|
|
538
|
+
h_kp[nh * N_KP + 1] = j;
|
|
539
|
+
h_kp[nh * N_KP + 2] = nose;
|
|
540
|
+
h_kp[nh * N_KP + 3] = mo[0];
|
|
541
|
+
h_kp[nh * N_KP + 4] = mo[1];
|
|
542
|
+
nh++;
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
// \u2500\u2500 stage 3/4: greedy NMS \u2192 the box for slot myFace \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
547
|
+
bool used[25];
|
|
548
|
+
for (int i = 0; i < N_KP * MAX_CAND; i++) used[i] = false;
|
|
549
|
+
int outN = 0;
|
|
550
|
+
|
|
551
|
+
for (int iter = 0; iter < 25; iter++) {
|
|
552
|
+
if (outN >= u_max_faces) break;
|
|
553
|
+
|
|
554
|
+
int best = -1;
|
|
555
|
+
float bestS = -1e8;
|
|
556
|
+
for (int q = 0; q < nh; q++) {
|
|
557
|
+
if (h_score[q] > bestS) { bestS = h_score[q]; best = q; }
|
|
558
|
+
}
|
|
559
|
+
if (best < 0) break;
|
|
560
|
+
h_score[best] = -1e9;
|
|
561
|
+
|
|
562
|
+
bool clash = false;
|
|
563
|
+
for (int t = 0; t < N_KP; t++) {
|
|
564
|
+
int ci = h_kp[best * N_KP + t];
|
|
565
|
+
if (ci < 0) continue;
|
|
566
|
+
if (used[t * MAX_CAND + ci]) clash = true;
|
|
567
|
+
}
|
|
568
|
+
if (clash) continue;
|
|
569
|
+
|
|
570
|
+
float x0 = 1e9, x1 = -1e9, y0 = 1e9, y1 = -1e9, score = 1e9;
|
|
571
|
+
for (int t = 0; t < N_KP; t++) {
|
|
572
|
+
int ci = h_kp[best * N_KP + t];
|
|
573
|
+
if (ci < 0) continue;
|
|
574
|
+
int e = t * MAX_CAND + ci;
|
|
575
|
+
used[e] = true;
|
|
576
|
+
x0 = min(x0, c_x[e]); x1 = max(x1, c_x[e]);
|
|
577
|
+
y0 = min(y0, c_y[e]); y1 = max(y1, c_y[e]);
|
|
578
|
+
score = min(score, c_s[e]);
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
if (outN == myFace) {
|
|
582
|
+
float halfPx = 0.5 * u_box_scale * max(x1 - x0, y1 - y0);
|
|
583
|
+
float cx = ((x0 + x1) * 0.5 + 0.5) / float(u_w);
|
|
584
|
+
float cy = ((y0 + y1) * 0.5 + 0.5) / float(u_h);
|
|
585
|
+
fragColor = vec4(cx, cy, halfPx / float(u_w), score);
|
|
586
|
+
return;
|
|
587
|
+
}
|
|
588
|
+
outN++;
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
fragColor = vec4(0.0); // no face in this slot
|
|
592
|
+
}
|
|
593
|
+
`;var P=class extends c{inputs;weights=[];output;dispatch;shader=Ne;constructor(e,t,r){if(super(e),t.c!==8)throw new Error(`FaceBoxesFromHeatmaps: expected 8-ch heatmaps (5 real), got ${t.c}`);if(r.maxFaces<1||r.maxFaces>6)throw new Error(`FaceBoxesFromHeatmaps: maxFaces must be 1..6, got ${r.maxFaces}`);let o=r.maxFaces;this.dispatch=[o,1];let i=this.makeTexture(null,o,1);this.output={h:1,w:o,c:4,texture:i,texW:o,texH:1},this.inputs=[t],this.samplers=[{name:"u_hm",texture:t.texture}],this.uniformInts={u_h:t.h,u_w:t.w,u_win:r.win,u_max_faces:o},this.uniformFloats={u_thresh:r.thresh,u_box_scale:r.boxScale,u_tol:r.tol},this.defaultSetup();}};var Ve=`#version 300 es
|
|
594
|
+
// Auto-reframe state update \u2192 1\xD71\xD78 tensor, i.e. a 2\xD71 texture of vec4 groups:
|
|
595
|
+
// x=0 (cx, cy, size, moving) \u2014 the view rect
|
|
596
|
+
// x=1 (subjX, subjY, subjHs, valid) \u2014 the incumbent subject, for hysteresis
|
|
597
|
+
// See reframe_state.wgsl for the full commentary \u2014 this mirrors it.
|
|
598
|
+
//
|
|
599
|
+
// A fragment shader writes ONE vec4, so both fragments redo the whole (tiny)
|
|
600
|
+
// computation and each emits its own group \u2014 same shape as face_boxes.glsl.
|
|
601
|
+
|
|
602
|
+
precision highp float;
|
|
603
|
+
precision highp int;
|
|
604
|
+
|
|
605
|
+
uniform sampler2D u_box; // 1\xD7K \u2014 (cx, cy, halfSide/W, score)
|
|
606
|
+
uniform sampler2D u_prev; // 1\xD71 \u2014 previous state
|
|
607
|
+
uniform sampler2D u_cmd; // 1\xD71 \u2014 .x = mode
|
|
608
|
+
uniform int u_k;
|
|
609
|
+
uniform float u_zoom;
|
|
610
|
+
uniform float u_gravity;
|
|
611
|
+
uniform float u_margin;
|
|
612
|
+
uniform float u_deadband;
|
|
613
|
+
uniform float u_ease;
|
|
614
|
+
uniform float u_aspect; // frame w/h
|
|
615
|
+
|
|
616
|
+
out vec4 fragColor;
|
|
617
|
+
|
|
618
|
+
const float MODE_HOLD = 1.0;
|
|
619
|
+
const float MODE_SOLVE = 2.0;
|
|
620
|
+
const float SWITCH_RATIO = 1.25;
|
|
621
|
+
const float TRACK_RADIUS_MIN = 0.1;
|
|
622
|
+
|
|
623
|
+
void main() {
|
|
624
|
+
int group = int(gl_FragCoord.x); // 0 = view rect, 1 = subject memory
|
|
625
|
+
vec4 prev = texelFetch(u_prev, ivec2(0, 0), 0);
|
|
626
|
+
vec4 prevS = texelFetch(u_prev, ivec2(1, 0), 0);
|
|
627
|
+
float mode = texelFetch(u_cmd, ivec2(0, 0), 0).x;
|
|
628
|
+
|
|
629
|
+
// Challenger = largest live face.
|
|
630
|
+
int chal = -1;
|
|
631
|
+
float chalHs = 0.0;
|
|
632
|
+
for (int i = 0; i < u_k; i++) {
|
|
633
|
+
vec4 b = texelFetch(u_box, ivec2(i, 0), 0);
|
|
634
|
+
if (b.w > 0.0 && b.z > chalHs) { chalHs = b.z; chal = i; }
|
|
635
|
+
}
|
|
636
|
+
if (chal < 0) {
|
|
637
|
+
// Hold, and keep the subject memory \u2014 a one-frame detection miss must not
|
|
638
|
+
// hand the camera to someone else.
|
|
639
|
+
fragColor = (group == 0) ? prev : prevS;
|
|
640
|
+
return;
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
// Incumbent = the live face nearest where the subject was (slot indices are
|
|
644
|
+
// not stable identities, so it's tracked by position).
|
|
645
|
+
int inc = -1;
|
|
646
|
+
float incD = 1e9;
|
|
647
|
+
if (prevS.w > 0.5) {
|
|
648
|
+
float radius = max(TRACK_RADIUS_MIN, prevS.z * 2.0);
|
|
649
|
+
for (int i = 0; i < u_k; i++) {
|
|
650
|
+
vec4 b = texelFetch(u_box, ivec2(i, 0), 0);
|
|
651
|
+
if (b.w <= 0.0) continue;
|
|
652
|
+
float d = length(vec2(b.x - prevS.x, b.y - prevS.y));
|
|
653
|
+
if (d < radius && d < incD) { incD = d; inc = i; }
|
|
654
|
+
}
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
int pick = chal;
|
|
658
|
+
if (inc >= 0 && chalHs <= texelFetch(u_box, ivec2(inc, 0), 0).z * SWITCH_RATIO) pick = inc;
|
|
659
|
+
vec4 subj = texelFetch(u_box, ivec2(pick, 0), 0);
|
|
660
|
+
if (group == 1) { fragColor = vec4(subj.x, subj.y, subj.z, 1.0); return; }
|
|
661
|
+
|
|
662
|
+
float halfX = subj.z;
|
|
663
|
+
float halfY = subj.z * u_aspect;
|
|
664
|
+
// Fallback = the full frame (no reframe) \u2014 see reframe_state.wgsl.
|
|
665
|
+
float wcx = 0.5, wcy = 0.5, ws = 1.0;
|
|
666
|
+
for (int t = 0; t <= 25; t++) {
|
|
667
|
+
float z = u_zoom + (1.0 - u_zoom) * (float(t) / 25.0);
|
|
668
|
+
float s = 1.0 / z;
|
|
669
|
+
float cx = clamp(0.5 + u_gravity * (subj.x - 0.5), s * 0.5, 1.0 - s * 0.5);
|
|
670
|
+
float cy = clamp(0.5 + u_gravity * (subj.y - 0.5), s * 0.5, 1.0 - s * 0.5);
|
|
671
|
+
if (abs(subj.x - cx) + halfX + u_margin <= s * 0.5 &&
|
|
672
|
+
abs(subj.y - cy) + halfY + u_margin <= s * 0.5) {
|
|
673
|
+
wcx = cx; wcy = cy; ws = s;
|
|
674
|
+
break;
|
|
675
|
+
}
|
|
676
|
+
}
|
|
677
|
+
if (prev.z <= 0.0 || mode == MODE_SOLVE) { fragColor = vec4(wcx, wcy, ws, 0.0); return; }
|
|
678
|
+
if (mode == MODE_HOLD) { fragColor = prev; return; }
|
|
679
|
+
|
|
680
|
+
float d = length(vec2(wcx - prev.x, wcy - prev.y)) + abs(ws - prev.z);
|
|
681
|
+
float moving = prev.w;
|
|
682
|
+
if (d > u_deadband) moving = 1.0;
|
|
683
|
+
else if (d < u_deadband * 0.3) moving = 0.0;
|
|
684
|
+
if (moving < 0.5) { fragColor = vec4(prev.xyz, 0.0); return; }
|
|
685
|
+
|
|
686
|
+
fragColor = vec4(
|
|
687
|
+
mix(prev.x, wcx, u_ease),
|
|
688
|
+
mix(prev.y, wcy, u_ease),
|
|
689
|
+
mix(prev.z, ws, u_ease),
|
|
690
|
+
1.0
|
|
691
|
+
);
|
|
692
|
+
}
|
|
693
|
+
`;var M=class extends c{inputs;weights=[];output;dispatch=[2,1];shader=Ve;constructor(e,t,r,o,i){super(e);let s=this.makeTexture(null,2,1);this.output={h:1,w:1,c:8,texture:s,texW:2,texH:1},this.inputs=[t,r,o],this.samplers=[{name:"u_box",texture:t.texture},{name:"u_prev",texture:r.texture},{name:"u_cmd",texture:o.texture}],this.uniformInts={u_k:t.w*t.h},this.uniformFloats={u_zoom:i.zoom,u_gravity:i.gravity,u_margin:i.margin,u_deadband:i.deadband,u_ease:i.ease,u_aspect:i.aspect},this.defaultSetup();}};var Xe=`#version 300 es
|
|
694
|
+
// Apply the reframe crop: sample \`src\` through the view rect. Same shape in and
|
|
695
|
+
// out. See reframe.wgsl for why this sits after the effect chain and touches
|
|
696
|
+
// only the foreground + alpha (never the background).
|
|
697
|
+
//
|
|
698
|
+
// rect = (cx, cy, size, moving), frame fractions; size \u2264 0 \u2192 identity.
|
|
699
|
+
|
|
700
|
+
precision highp float;
|
|
701
|
+
precision highp int;
|
|
702
|
+
|
|
703
|
+
uniform sampler2D u_src;
|
|
704
|
+
uniform sampler2D u_rect; // 1\xD71
|
|
705
|
+
uniform int u_h;
|
|
706
|
+
uniform int u_w;
|
|
707
|
+
|
|
708
|
+
out vec4 fragColor;
|
|
709
|
+
|
|
710
|
+
vec4 samp(int x, int y) {
|
|
711
|
+
return texelFetch(u_src, ivec2(clamp(x, 0, u_w - 1), clamp(y, 0, u_h - 1)), 0);
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
void main() {
|
|
715
|
+
int x = int(gl_FragCoord.x);
|
|
716
|
+
int y = int(gl_FragCoord.y);
|
|
717
|
+
|
|
718
|
+
vec4 r = texelFetch(u_rect, ivec2(0, 0), 0);
|
|
719
|
+
float s = r.z, rcx = r.x, rcy = r.y;
|
|
720
|
+
if (s <= 0.0) { s = 1.0; rcx = 0.5; rcy = 0.5; }
|
|
721
|
+
|
|
722
|
+
float fx = (rcx - s * 0.5) + ((float(x) + 0.5) / float(u_w)) * s;
|
|
723
|
+
float fy = (rcy - s * 0.5) + ((float(y) + 0.5) / float(u_h)) * s;
|
|
724
|
+
// fraction \u2192 texel index; an identity rect lands exactly on texel centres,
|
|
725
|
+
// making the op a bit-exact copy.
|
|
726
|
+
float sx = fx * float(u_w) - 0.5;
|
|
727
|
+
float sy = fy * float(u_h) - 0.5;
|
|
728
|
+
|
|
729
|
+
int x0 = int(floor(sx));
|
|
730
|
+
int y0 = int(floor(sy));
|
|
731
|
+
float tx = sx - float(x0);
|
|
732
|
+
float ty = sy - float(y0);
|
|
733
|
+
|
|
734
|
+
vec4 top = mix(samp(x0, y0), samp(x0 + 1, y0), tx);
|
|
735
|
+
vec4 bot = mix(samp(x0, y0 + 1), samp(x0 + 1, y0 + 1), tx);
|
|
736
|
+
fragColor = mix(top, bot, ty);
|
|
737
|
+
}
|
|
738
|
+
`;var O=class extends c{inputs;weights=[];output;dispatch;shader=Xe;constructor(e,t,r){super(e);let o=this.makeTexture(null,t.w,t.h);this.output={h:t.h,w:t.w,c:4,texture:o,texW:t.w,texH:t.h},this.inputs=[t,r],this.samplers=[{name:"u_src",texture:t.texture},{name:"u_rect",texture:r.texture}],this.uniformInts={u_h:t.h,u_w:t.w},this.defaultSetup(),this.dispatch=[t.w,t.h];}};var ze=`#version 300 es
|
|
739
|
+
// Box-driven square crop + bilinear resample + ((rgb - mean)/std) normalize.
|
|
740
|
+
// Reads the box tensor (face_box output: cx, cy, halfSide, score in frame
|
|
741
|
+
// fractions; halfSide as a fraction of frame WIDTH) and emits the landmark
|
|
742
|
+
// model's input, .w = 0. Sampling mirrors landmark training's warpAffine:
|
|
743
|
+
// src = center + (u - out/2) \xB7 side/out.
|
|
744
|
+
//
|
|
745
|
+
// frame texture: (w, h) \u2014 4-ch, 1 group. box texture: 1\xD71.
|
|
746
|
+
|
|
747
|
+
precision highp float;
|
|
748
|
+
precision highp int;
|
|
749
|
+
|
|
750
|
+
uniform sampler2D u_frame;
|
|
751
|
+
uniform sampler2D u_box;
|
|
752
|
+
uniform int u_in_h;
|
|
753
|
+
uniform int u_in_w;
|
|
754
|
+
uniform int u_out_h;
|
|
755
|
+
uniform int u_out_w;
|
|
756
|
+
uniform int u_slot; // box-tensor slot (multi-face); 0 for the single-face path
|
|
757
|
+
uniform float u_mean_r;
|
|
758
|
+
uniform float u_mean_g;
|
|
759
|
+
uniform float u_mean_b;
|
|
760
|
+
uniform float u_std_r;
|
|
761
|
+
uniform float u_std_g;
|
|
762
|
+
uniform float u_std_b;
|
|
763
|
+
|
|
764
|
+
out vec4 fragColor;
|
|
765
|
+
|
|
766
|
+
vec4 samp(int x, int y) {
|
|
767
|
+
return texelFetch(u_frame, ivec2(clamp(x, 0, u_in_w - 1), clamp(y, 0, u_in_h - 1)), 0);
|
|
768
|
+
}
|
|
769
|
+
|
|
770
|
+
void main() {
|
|
771
|
+
int x = int(gl_FragCoord.x);
|
|
772
|
+
int y = int(gl_FragCoord.y);
|
|
773
|
+
|
|
774
|
+
vec4 box = texelFetch(u_box, ivec2(u_slot, 0), 0);
|
|
775
|
+
float cx = box.x * float(u_in_w);
|
|
776
|
+
float cy = box.y * float(u_in_h);
|
|
777
|
+
float side = 2.0 * box.z * float(u_in_w);
|
|
778
|
+
|
|
779
|
+
float sx = clamp(cx + (float(x) - float(u_out_w) * 0.5) * side / float(u_out_w), 0.0, float(u_in_w - 1));
|
|
780
|
+
float sy = clamp(cy + (float(y) - float(u_out_h) * 0.5) * side / float(u_out_h), 0.0, float(u_in_h - 1));
|
|
781
|
+
|
|
782
|
+
int x0 = int(floor(sx));
|
|
783
|
+
int y0 = int(floor(sy));
|
|
784
|
+
float tx = sx - float(x0);
|
|
785
|
+
float ty = sy - float(y0);
|
|
786
|
+
|
|
787
|
+
vec4 top = mix(samp(x0, y0), samp(x0 + 1, y0), tx);
|
|
788
|
+
vec4 bot = mix(samp(x0, y0 + 1), samp(x0 + 1, y0 + 1), tx);
|
|
789
|
+
vec4 v = mix(top, bot, ty);
|
|
790
|
+
|
|
791
|
+
vec3 mean = vec3(u_mean_r, u_mean_g, u_mean_b);
|
|
792
|
+
vec3 std = vec3(u_std_r, u_std_g, u_std_b);
|
|
793
|
+
fragColor = vec4((v.rgb - mean) / std, 0.0);
|
|
794
|
+
}
|
|
795
|
+
`;var H=class extends c{inputs;weights=[];output;dispatch;shader=ze;constructor(e,t,r,o){super(e);let i=o.slot??0;if(i>=r.w*r.h)throw new Error(`CropResample: slot ${i} out of range for a ${r.h}\xD7${r.w} box tensor`);let s=this.makeTexture(null,o.outW,o.outH);this.output={h:o.outH,w:o.outW,c:4,texture:s,texW:o.outW,texH:o.outH},this.inputs=[t,r],this.samplers=[{name:"u_frame",texture:t.texture},{name:"u_box",texture:r.texture}],this.uniformInts={u_in_h:t.h,u_in_w:t.w,u_out_h:o.outH,u_out_w:o.outW,u_slot:i},this.uniformFloats={u_mean_r:o.mean[0],u_mean_g:o.mean[1],u_mean_b:o.mean[2],u_std_r:o.std[0],u_std_g:o.std[1],u_std_b:o.std[2]},this.defaultSetup(),this.dispatch=[o.outW,o.outH];}};var I=`#version 300 es
|
|
796
|
+
// Passthrough "compositor": writes the image directly to the canvas
|
|
797
|
+
// (default framebuffer). No alpha math, no background. Used by RenderOp
|
|
798
|
+
// when the renderer is in disabled state.
|
|
799
|
+
//
|
|
800
|
+
// Caller invariants:
|
|
801
|
+
// - canvas (viewport) === image h \xD7 w (no resampling here)
|
|
802
|
+
|
|
803
|
+
precision highp float;
|
|
804
|
+
|
|
805
|
+
uniform sampler2D u_image; // image as NHWC vec4 (RGBA)
|
|
806
|
+
|
|
807
|
+
out vec4 fragColor;
|
|
808
|
+
|
|
809
|
+
void main() {
|
|
810
|
+
// WebGL gl_FragCoord origin is bottom-left; tensor textures are stored
|
|
811
|
+
// top-down. Flip y so the displayed image is upright. (Matches what the
|
|
812
|
+
// existing composite_solid.glsl does.)
|
|
813
|
+
int H = textureSize(u_image, 0).y;
|
|
814
|
+
ivec2 px = ivec2(int(gl_FragCoord.x), H - 1 - int(gl_FragCoord.y));
|
|
815
|
+
vec3 rgb = texelFetch(u_image, px, 0).rgb;
|
|
816
|
+
fragColor = vec4(rgb, 1.0);
|
|
817
|
+
}
|
|
818
|
+
`;var Nt=`#version 300 es
|
|
819
|
+
const vec2 VERTS[6] = vec2[6](
|
|
820
|
+
vec2(-1.0,-1.0), vec2(1.0,-1.0), vec2(-1.0,1.0),
|
|
821
|
+
vec2(-1.0,1.0), vec2(1.0,-1.0), vec2(1.0,1.0)
|
|
822
|
+
);
|
|
823
|
+
void main() { gl_Position = vec4(VERTS[gl_VertexID], 0.0, 1.0); }`,Vt=`#version 300 es
|
|
824
|
+
precision highp float;
|
|
825
|
+
uniform sampler2D u_lm;
|
|
826
|
+
uniform sampler2D u_box;
|
|
827
|
+
uniform int u_slot;
|
|
828
|
+
uniform float u_thresh;
|
|
829
|
+
uniform float u_point_size;
|
|
830
|
+
uniform float u_canvas_w;
|
|
831
|
+
uniform float u_canvas_h;
|
|
832
|
+
|
|
833
|
+
void main() {
|
|
834
|
+
int i = gl_VertexID;
|
|
835
|
+
vec4 box = texelFetch(u_box, ivec2(u_slot, 0), 0);
|
|
836
|
+
if (box.w < u_thresh) {
|
|
837
|
+
gl_Position = vec4(2.0, 2.0, 2.0, 1.0); // clipped away
|
|
838
|
+
gl_PointSize = 0.0;
|
|
839
|
+
return;
|
|
840
|
+
}
|
|
841
|
+
vec4 g = texelFetch(u_lm, ivec2(i / 2, 0), 0);
|
|
842
|
+
float lx = g[(i % 2) * 2];
|
|
843
|
+
float ly = g[(i % 2) * 2 + 1];
|
|
844
|
+
|
|
845
|
+
float hsx = box.z;
|
|
846
|
+
float hsy = box.z * u_canvas_w / u_canvas_h;
|
|
847
|
+
float px = (box.x - hsx) + lx * 2.0 * hsx;
|
|
848
|
+
float py = (box.y - hsy) + ly * 2.0 * hsy;
|
|
849
|
+
|
|
850
|
+
gl_Position = vec4(px * 2.0 - 1.0, 1.0 - 2.0 * py, 0.0, 1.0);
|
|
851
|
+
gl_PointSize = u_point_size;
|
|
852
|
+
}`,Xt=`#version 300 es
|
|
853
|
+
precision highp float;
|
|
854
|
+
uniform vec3 u_color;
|
|
855
|
+
out vec4 fragColor;
|
|
856
|
+
void main() { fragColor = vec4(u_color, 1.0); }`;function $e(a,e,t,r){let o=a.createShader(a.VERTEX_SHADER);if(a.shaderSource(o,e),a.compileShader(o),!a.getShaderParameter(o,a.COMPILE_STATUS))throw new Error(`${r} vert compile error: ${a.getShaderInfoLog(o)}`);let i=a.createShader(a.FRAGMENT_SHADER);if(a.shaderSource(i,t),a.compileShader(i),!a.getShaderParameter(i,a.COMPILE_STATUS))throw new Error(`${r} frag compile error: ${a.getShaderInfoLog(i)}`);let s=a.createProgram();if(a.attachShader(s,o),a.attachShader(s,i),a.linkProgram(s),!a.getProgramParameter(s,a.LINK_STATUS))throw new Error(`${r} link error: ${a.getProgramInfoLog(s)}`);return s}var N=class{constructor(e,t,r,o,i){this.backend=e;if(r.c<i.count*2)throw new Error(`LandmarkOverlay: landmarks tensor holds ${r.c/2} points < count ${i.count}`);if(this.slot=i.slot??0,this.slot>=o.w*o.h)throw new Error(`LandmarkOverlay: slot ${this.slot} out of range for a ${o.h}\xD7${o.w} box tensor`);this.imageTex=t.texture,this.lmTex=r.texture,this.boxTex=o.texture,this.params=i,this.canvasW=t.w,this.canvasH=t.h;let s=e.gl;this.imgProgram=$e(s,Nt,I,"landmark_overlay img"),this.ptsProgram=$e(s,Vt,Xt,"landmark_overlay pts");}backend;imgProgram;ptsProgram;imageTex;lmTex;boxTex;params;canvasW;canvasH;slot;run(){let e=this.backend.gl;this.backend.bindDisplayFramebuffer(),e.bindVertexArray(null),(this.params.drawImage??true)&&(e.useProgram(this.imgProgram),e.activeTexture(e.TEXTURE0),e.bindTexture(e.TEXTURE_2D,this.imageTex),e.uniform1i(e.getUniformLocation(this.imgProgram,"u_image"),0),e.drawArrays(e.TRIANGLES,0,6)),e.useProgram(this.ptsProgram),e.activeTexture(e.TEXTURE0),e.bindTexture(e.TEXTURE_2D,this.lmTex),e.uniform1i(e.getUniformLocation(this.ptsProgram,"u_lm"),0),e.activeTexture(e.TEXTURE1),e.bindTexture(e.TEXTURE_2D,this.boxTex),e.uniform1i(e.getUniformLocation(this.ptsProgram,"u_box"),1),e.uniform1i(e.getUniformLocation(this.ptsProgram,"u_slot"),this.slot),e.uniform1f(e.getUniformLocation(this.ptsProgram,"u_thresh"),this.params.thresh),e.uniform1f(e.getUniformLocation(this.ptsProgram,"u_point_size"),this.params.pointSize),e.uniform1f(e.getUniformLocation(this.ptsProgram,"u_canvas_w"),this.canvasW),e.uniform1f(e.getUniformLocation(this.ptsProgram,"u_canvas_h"),this.canvasH),e.uniform3f(e.getUniformLocation(this.ptsProgram,"u_color"),this.params.color[0],this.params.color[1],this.params.color[2]),e.drawArrays(e.POINTS,0,this.params.count);}};var W=`#version 300 es
|
|
857
|
+
const vec2 VERTS[6] = vec2[6](
|
|
858
|
+
vec2(-1.0,-1.0), vec2(1.0,-1.0), vec2(-1.0,1.0),
|
|
859
|
+
vec2(-1.0,1.0), vec2(1.0,-1.0), vec2(1.0,1.0)
|
|
860
|
+
);
|
|
861
|
+
void main() { gl_Position = vec4(VERTS[gl_VertexID], 0.0, 1.0); }`,Le=`
|
|
862
|
+
uniform sampler2D u_lm;
|
|
863
|
+
uniform sampler2D u_box;
|
|
864
|
+
uniform float u_thresh;
|
|
865
|
+
uniform float u_canvas_w;
|
|
866
|
+
uniform float u_canvas_h;
|
|
867
|
+
uniform int u_grid;
|
|
868
|
+
|
|
869
|
+
vec3 lmFrame(int i, int face) {
|
|
870
|
+
vec4 box = texelFetch(u_box, ivec2(face, 0), 0);
|
|
871
|
+
int gi = face * 478 + i;
|
|
872
|
+
vec4 g = texelFetch(u_lm, ivec2(gi / 2, 0), 0);
|
|
873
|
+
float lx = g[(gi % 2) * 2];
|
|
874
|
+
float ly = g[(gi % 2) * 2 + 1];
|
|
875
|
+
float hsx = box.z;
|
|
876
|
+
float hsy = box.z * u_canvas_w / u_canvas_h;
|
|
877
|
+
return vec3((box.x - hsx) + lx * 2.0 * hsx, (box.y - hsy) + ly * 2.0 * hsy, box.w);
|
|
878
|
+
}
|
|
879
|
+
|
|
880
|
+
// Face 'face' owns tile (face % grid, face / grid). grid=1 (K=1) -> the whole
|
|
881
|
+
// atlas, i.e. the single-face layout unchanged.
|
|
882
|
+
vec2 tileUv(vec2 uv, int face) {
|
|
883
|
+
float g = float(u_grid);
|
|
884
|
+
return (uv + vec2(float(face % u_grid), float(face / u_grid))) / g;
|
|
885
|
+
}`,je=`#version 300 es
|
|
886
|
+
precision highp float;
|
|
887
|
+
layout(location = 0) in vec2 a_uv;
|
|
888
|
+
layout(location = 1) in float a_idx;
|
|
889
|
+
${Le}
|
|
890
|
+
out vec2 v_src;
|
|
891
|
+
void main() {
|
|
892
|
+
vec3 l = lmFrame(int(a_idx), gl_InstanceID);
|
|
893
|
+
if (l.z < u_thresh) { gl_Position = vec4(2.0, 2.0, 2.0, 1.0); return; }
|
|
894
|
+
v_src = l.xy;
|
|
895
|
+
gl_Position = vec4(tileUv(a_uv, gl_InstanceID) * 2.0 - 1.0, 0.0, 1.0);
|
|
896
|
+
}`,Ke=`
|
|
897
|
+
uniform sampler2D u_frame;
|
|
898
|
+
uniform float u_frame_w;
|
|
899
|
+
uniform float u_frame_h;
|
|
900
|
+
|
|
901
|
+
vec3 frameAt(int x, int y) {
|
|
902
|
+
return texelFetch(u_frame, ivec2(clamp(x, 0, int(u_frame_w) - 1), clamp(y, 0, int(u_frame_h) - 1)), 0).rgb;
|
|
903
|
+
}
|
|
904
|
+
vec3 frameBilinear(vec2 f) {
|
|
905
|
+
float sx = clamp(f.x * u_frame_w - 0.5, 0.0, u_frame_w - 1.0);
|
|
906
|
+
float sy = clamp(f.y * u_frame_h - 0.5, 0.0, u_frame_h - 1.0);
|
|
907
|
+
int x0 = int(floor(sx));
|
|
908
|
+
int y0 = int(floor(sy));
|
|
909
|
+
float tx = sx - float(x0);
|
|
910
|
+
float ty = sy - float(y0);
|
|
911
|
+
vec3 top = mix(frameAt(x0, y0), frameAt(x0 + 1, y0), tx);
|
|
912
|
+
vec3 bot = mix(frameAt(x0, y0 + 1), frameAt(x0 + 1, y0 + 1), tx);
|
|
913
|
+
return mix(top, bot, ty);
|
|
914
|
+
}`,qe=`#version 300 es
|
|
915
|
+
precision highp float;
|
|
916
|
+
precision highp int;
|
|
917
|
+
in vec2 v_src;
|
|
918
|
+
${Ke}
|
|
919
|
+
out vec4 fragColor;
|
|
920
|
+
void main() { fragColor = vec4(frameBilinear(v_src), 1.0); }`,Ye=`#version 300 es
|
|
921
|
+
precision highp float;
|
|
922
|
+
uniform sampler2D u_tex;
|
|
923
|
+
uniform vec2 u_dir;
|
|
924
|
+
uniform float u_sigma;
|
|
925
|
+
uniform int u_grid;
|
|
926
|
+
// The tile containing 'uv', as (lo.xy, hi.zw) - filter taps clamp to it so one
|
|
927
|
+
// face's skin can't bleed into a neighbour's tile.
|
|
928
|
+
vec4 tileBounds(vec2 uv) {
|
|
929
|
+
float g = float(u_grid);
|
|
930
|
+
vec2 t = floor(clamp(uv, vec2(0.0), vec2(0.99999)) * g);
|
|
931
|
+
return vec4(t / g, (t + vec2(1.0)) / g);
|
|
932
|
+
}
|
|
933
|
+
out vec4 fragColor;
|
|
934
|
+
void main() {
|
|
935
|
+
vec2 uv = gl_FragCoord.xy / 512.0;
|
|
936
|
+
vec4 tb = tileBounds(uv);
|
|
937
|
+
float ht = 0.5 / 512.0;
|
|
938
|
+
vec2 lo = tb.xy + ht, hi = tb.zw - ht;
|
|
939
|
+
float s = max(u_sigma, 0.001);
|
|
940
|
+
int R = int(clamp(ceil(s * 2.5), 1.0, 48.0));
|
|
941
|
+
vec4 sum = vec4(0.0);
|
|
942
|
+
float wsum = 0.0;
|
|
943
|
+
for (int i = -48; i <= 48; i++) {
|
|
944
|
+
if (i < -R || i > R) continue;
|
|
945
|
+
float w = exp(-float(i * i) / (2.0 * s * s));
|
|
946
|
+
sum += texture(u_tex, clamp(uv + u_dir * float(i), lo, hi)) * w;
|
|
947
|
+
wsum += w;
|
|
948
|
+
}
|
|
949
|
+
fragColor = sum / wsum;
|
|
950
|
+
}`,Qe=`#version 300 es
|
|
951
|
+
precision highp float;
|
|
952
|
+
uniform sampler2D u_atlas;
|
|
953
|
+
uniform sampler2D u_low;
|
|
954
|
+
uniform float u_detail;
|
|
955
|
+
out vec4 fragColor;
|
|
956
|
+
void main() {
|
|
957
|
+
vec2 uv = gl_FragCoord.xy / 512.0;
|
|
958
|
+
vec4 a = texture(u_atlas, uv);
|
|
959
|
+
vec4 lo = texture(u_low, uv);
|
|
960
|
+
fragColor = clamp(lo + (a - lo) * u_detail, 0.0, 1.0);
|
|
961
|
+
}`,Je=`#version 300 es
|
|
962
|
+
precision highp float;
|
|
963
|
+
uniform sampler2D u_tex;
|
|
964
|
+
uniform float u_sigma;
|
|
965
|
+
uniform int u_grid;
|
|
966
|
+
vec4 tileBounds(vec2 uv) {
|
|
967
|
+
float g = float(u_grid);
|
|
968
|
+
vec2 t = floor(clamp(uv, vec2(0.0), vec2(0.99999)) * g);
|
|
969
|
+
return vec4(t / g, (t + vec2(1.0)) / g);
|
|
970
|
+
}
|
|
971
|
+
out vec4 fragColor;
|
|
972
|
+
void main() {
|
|
973
|
+
vec2 uv = gl_FragCoord.xy / 512.0;
|
|
974
|
+
vec2 texel = vec2(1.0 / 512.0);
|
|
975
|
+
vec4 tb = tileBounds(uv);
|
|
976
|
+
vec2 blo = tb.xy + texel * 0.5, bhi = tb.zw - texel * 0.5;
|
|
977
|
+
float ss = max(u_sigma, 0.001);
|
|
978
|
+
int R = int(clamp(ceil(ss), 1.0, 12.0));
|
|
979
|
+
float sr = 0.15;
|
|
980
|
+
vec3 c = texture(u_tex, uv).rgb;
|
|
981
|
+
vec3 sum = vec3(0.0);
|
|
982
|
+
float wsum = 0.0;
|
|
983
|
+
for (int y = -12; y <= 12; y++) {
|
|
984
|
+
if (y < -R || y > R) continue;
|
|
985
|
+
for (int x = -12; x <= 12; x++) {
|
|
986
|
+
if (x < -R || x > R) continue;
|
|
987
|
+
vec3 sc = texture(u_tex, clamp(uv + texel * vec2(float(x), float(y)), blo, bhi)).rgb;
|
|
988
|
+
float ws = exp(-float(x * x + y * y) / (2.0 * ss * ss));
|
|
989
|
+
vec3 d = sc - c;
|
|
990
|
+
float wr = exp(-dot(d, d) / (2.0 * sr * sr));
|
|
991
|
+
sum += sc * ws * wr;
|
|
992
|
+
wsum += ws * wr;
|
|
993
|
+
}
|
|
994
|
+
}
|
|
995
|
+
fragColor = vec4(sum / wsum, 1.0);
|
|
996
|
+
}`,zt=`#version 300 es
|
|
997
|
+
precision highp float;
|
|
998
|
+
uniform sampler2D u_image;
|
|
999
|
+
out vec4 fragColor;
|
|
1000
|
+
void main() {
|
|
1001
|
+
int H = textureSize(u_image, 0).y;
|
|
1002
|
+
ivec2 px = ivec2(int(gl_FragCoord.x), H - 1 - int(gl_FragCoord.y));
|
|
1003
|
+
fragColor = vec4(texelFetch(u_image, px, 0).rgb, 1.0);
|
|
1004
|
+
}`,$t=`#version 300 es
|
|
1005
|
+
precision highp float;
|
|
1006
|
+
layout(location = 0) in vec2 a_uv;
|
|
1007
|
+
layout(location = 1) in float a_idx;
|
|
1008
|
+
${Le}
|
|
1009
|
+
out vec2 v_uv; // TILED atlas uv \u2014 the atlas is per-face
|
|
1010
|
+
out vec2 v_uv_mask; // UNTILED canonical uv \u2014 the weight mask is one shared asset
|
|
1011
|
+
out vec2 v_src;
|
|
1012
|
+
void main() {
|
|
1013
|
+
vec3 l = lmFrame(int(a_idx), gl_InstanceID);
|
|
1014
|
+
if (l.z < u_thresh) { gl_Position = vec4(2.0, 2.0, 2.0, 1.0); return; }
|
|
1015
|
+
v_uv = tileUv(a_uv, gl_InstanceID);
|
|
1016
|
+
v_uv_mask = a_uv;
|
|
1017
|
+
v_src = l.xy;
|
|
1018
|
+
gl_Position = vec4(l.x * 2.0 - 1.0, 1.0 - 2.0 * l.y, 0.0, 1.0);
|
|
1019
|
+
}`,Ze=`#version 300 es
|
|
1020
|
+
precision highp float;
|
|
1021
|
+
precision highp int;
|
|
1022
|
+
in vec2 v_uv;
|
|
1023
|
+
in vec2 v_uv_mask;
|
|
1024
|
+
in vec2 v_src;
|
|
1025
|
+
uniform sampler2D u_smoothed;
|
|
1026
|
+
uniform sampler2D u_weight;
|
|
1027
|
+
uniform float u_strength;
|
|
1028
|
+
${Ke}
|
|
1029
|
+
out vec4 fragColor;
|
|
1030
|
+
void main() {
|
|
1031
|
+
vec3 orig = frameBilinear(v_src);
|
|
1032
|
+
vec3 sm = texture(u_smoothed, v_uv).rgb;
|
|
1033
|
+
// v_uv_mask, not v_uv: the atlas is tiled per face, the weight mask is one
|
|
1034
|
+
// shared canonical asset. See face_touchup.wgsl fs_comp.
|
|
1035
|
+
float w = texture(u_weight, v_uv_mask).r * u_strength;
|
|
1036
|
+
fragColor = vec4(mix(orig, sm, w), 1.0);
|
|
1037
|
+
}`;function T(a,e,t,r){let o=(s,n,u)=>{let l=a.createShader(s);if(a.shaderSource(l,n),a.compileShader(l),!a.getShaderParameter(l,a.COMPILE_STATUS))throw new Error(`${r} ${u} compile error: ${a.getShaderInfoLog(l)}`);return l},i=a.createProgram();if(a.attachShader(i,o(a.VERTEX_SHADER,e,"vert")),a.attachShader(i,o(a.FRAGMENT_SHADER,t,"frag")),a.linkProgram(i),!a.getProgramParameter(i,a.LINK_STATUS))throw new Error(`${r} link error: ${a.getProgramInfoLog(i)}`);return i}var V=class{constructor(e,t,r,o,i,s){this.backend=e;let n=e.gl;if(this.frame=t,this.lm=r,this.box=o,this.count=i.count,this.params=s,this.slots=s.slots??1,this.slots!==1&&this.slots!==4)throw new Error(`FaceTouchup: slots must be 1 or 4, got ${this.slots}`);if(this.grid=this.slots===4?2:1,this.activeSlots=this.slots,o.w*o.h<this.slots)throw new Error(`FaceTouchup: slots ${this.slots} exceeds the ${o.h}\xD7${o.w} box tensor`);if(r.c<this.slots*956)throw new Error(`FaceTouchup: landmarks tensor holds ${r.c/956} faces < slots ${this.slots}`);this.progs={unwrap:T(n,je,qe,"touchup unwrap"),blur:T(n,W,Ye,"touchup blur"),combine:T(n,W,Qe,"touchup combine"),bilateral:T(n,W,Je,"touchup bilateral"),blit:T(n,W,zt,"touchup blit"),comp:T(n,$t,Ze,"touchup comp")},this.meshVao=n.createVertexArray(),n.bindVertexArray(this.meshVao);let u=n.createBuffer();n.bindBuffer(n.ARRAY_BUFFER,u),n.bufferData(n.ARRAY_BUFFER,i.uv,n.STATIC_DRAW),n.enableVertexAttribArray(0),n.vertexAttribPointer(0,2,n.FLOAT,false,0,0);let l=n.createBuffer();n.bindBuffer(n.ARRAY_BUFFER,l),n.bufferData(n.ARRAY_BUFFER,i.idx,n.STATIC_DRAW),n.enableVertexAttribArray(1),n.vertexAttribPointer(1,1,n.FLOAT,false,0,0),n.bindVertexArray(null);let p=h=>{let m=n.createTexture();return n.bindTexture(n.TEXTURE_2D,m),h?n.texImage2D(n.TEXTURE_2D,0,n.RGBA8,n.RGBA,n.UNSIGNED_BYTE,h):n.texImage2D(n.TEXTURE_2D,0,n.RGBA8,512,512,0,n.RGBA,n.UNSIGNED_BYTE,null),n.texParameteri(n.TEXTURE_2D,n.TEXTURE_MIN_FILTER,n.LINEAR),n.texParameteri(n.TEXTURE_2D,n.TEXTURE_MAG_FILTER,n.LINEAR),n.texParameteri(n.TEXTURE_2D,n.TEXTURE_WRAP_S,n.CLAMP_TO_EDGE),n.texParameteri(n.TEXTURE_2D,n.TEXTURE_WRAP_T,n.CLAMP_TO_EDGE),m};this.atlas=p(null),this.ping=p(null),this.low=p(null),this.smoothed=p(null),this.weight=p(i.weightMask),this.fbo=n.createFramebuffer();}backend;progs;meshVao;fbo;atlas;ping;low;smoothed;weight;frame;lm;box;count;params;slots;grid;activeSlots;bindTex(e,t,r,o){let i=this.backend.gl;i.activeTexture(i.TEXTURE0+t),i.bindTexture(i.TEXTURE_2D,o),i.uniform1i(i.getUniformLocation(e,r),t);}lmUniforms(e){let t=this.backend.gl;this.bindTex(e,4,"u_lm",this.lm.texture),this.bindTex(e,5,"u_box",this.box.texture),t.uniform1f(t.getUniformLocation(e,"u_thresh"),this.params.thresh),t.uniform1f(t.getUniformLocation(e,"u_canvas_w"),this.frame.w),t.uniform1f(t.getUniformLocation(e,"u_canvas_h"),this.frame.h),t.uniform1i(t.getUniformLocation(e,"u_grid"),this.grid);}frameUniforms(e){let t=this.backend.gl;this.bindTex(e,0,"u_frame",this.frame.texture),t.uniform1f(t.getUniformLocation(e,"u_frame_w"),this.frame.w),t.uniform1f(t.getUniformLocation(e,"u_frame_h"),this.frame.h);}atlasPass(e,t){let r=this.backend.gl;r.bindFramebuffer(r.FRAMEBUFFER,this.fbo),r.framebufferTexture2D(r.FRAMEBUFFER,r.COLOR_ATTACHMENT0,r.TEXTURE_2D,e,0),r.viewport(0,0,512,512),t();}run(){let e=this.backend.gl;if(this.atlasPass(this.atlas,()=>{e.clearColor(0,0,0,0),e.clear(e.COLOR_BUFFER_BIT),e.useProgram(this.progs.unwrap),this.frameUniforms(this.progs.unwrap),this.lmUniforms(this.progs.unwrap),e.bindVertexArray(this.meshVao),e.drawArraysInstanced(e.TRIANGLES,0,this.count,this.activeSlots),e.bindVertexArray(null);}),(this.params.style??"freq-sep")==="bilateral")this.atlasPass(this.smoothed,()=>{e.useProgram(this.progs.bilateral),this.bindTex(this.progs.bilateral,0,"u_tex",this.atlas),e.uniform1f(e.getUniformLocation(this.progs.bilateral,"u_sigma"),this.params.amount),e.uniform1i(e.getUniformLocation(this.progs.bilateral,"u_grid"),this.grid),e.drawArrays(e.TRIANGLES,0,6);});else {let t=(r,o,i,s)=>this.atlasPass(o,()=>{e.useProgram(this.progs.blur),this.bindTex(this.progs.blur,0,"u_tex",r),e.uniform2f(e.getUniformLocation(this.progs.blur,"u_dir"),i,s),e.uniform1f(e.getUniformLocation(this.progs.blur,"u_sigma"),this.params.amount),e.uniform1i(e.getUniformLocation(this.progs.blur,"u_grid"),this.grid),e.drawArrays(e.TRIANGLES,0,6);});t(this.atlas,this.ping,1/512,0),t(this.ping,this.low,0,1/512),this.atlasPass(this.smoothed,()=>{e.useProgram(this.progs.combine),this.bindTex(this.progs.combine,0,"u_atlas",this.atlas),this.bindTex(this.progs.combine,1,"u_low",this.low),e.uniform1f(e.getUniformLocation(this.progs.combine,"u_detail"),this.params.detail),e.drawArrays(e.TRIANGLES,0,6);});}this.backend.bindDisplayFramebuffer(),e.viewport(0,0,this.frame.w,this.frame.h),e.useProgram(this.progs.blit),this.bindTex(this.progs.blit,0,"u_image",this.frame.texture),e.bindVertexArray(null),e.drawArrays(e.TRIANGLES,0,6),e.useProgram(this.progs.comp),this.frameUniforms(this.progs.comp),this.lmUniforms(this.progs.comp),this.bindTex(this.progs.comp,1,"u_smoothed",this.smoothed),this.bindTex(this.progs.comp,2,"u_weight",this.weight),e.uniform1f(e.getUniformLocation(this.progs.comp,"u_strength"),this.params.strength),e.bindVertexArray(this.meshVao),e.drawArraysInstanced(e.TRIANGLES,0,this.count,this.activeSlots),e.bindVertexArray(null);}},jt=`#version 300 es
|
|
1038
|
+
precision highp float;
|
|
1039
|
+
uniform sampler2D u_image;
|
|
1040
|
+
out vec4 fragColor;
|
|
1041
|
+
void main() {
|
|
1042
|
+
ivec2 px = ivec2(gl_FragCoord.xy);
|
|
1043
|
+
fragColor = vec4(texelFetch(u_image, px, 0).rgb, 1.0);
|
|
1044
|
+
}`,Kt=`#version 300 es
|
|
1045
|
+
precision highp float;
|
|
1046
|
+
layout(location = 0) in vec2 a_uv;
|
|
1047
|
+
layout(location = 1) in float a_idx;
|
|
1048
|
+
${Le}
|
|
1049
|
+
out vec2 v_uv; // TILED atlas uv \u2014 the atlas is per-face
|
|
1050
|
+
out vec2 v_uv_mask; // UNTILED canonical uv \u2014 the weight mask is one shared asset
|
|
1051
|
+
out vec2 v_src;
|
|
1052
|
+
void main() {
|
|
1053
|
+
vec3 l = lmFrame(int(a_idx), gl_InstanceID);
|
|
1054
|
+
if (l.z < u_thresh) { gl_Position = vec4(2.0, 2.0, 2.0, 1.0); return; }
|
|
1055
|
+
v_uv = tileUv(a_uv, gl_InstanceID);
|
|
1056
|
+
v_uv_mask = a_uv;
|
|
1057
|
+
v_src = l.xy;
|
|
1058
|
+
gl_Position = vec4(l.x * 2.0 - 1.0, l.y * 2.0 - 1.0, 0.0, 1.0);
|
|
1059
|
+
}`,X=class{constructor(e,t,r,o,i,s){this.backend=e;let n=e.gl;if(this.inputs=[t,r,o],this.frame=t,this.lm=r,this.box=o,this.count=i.count,this.params=s,this.slots=s.slots??1,this.slots!==1&&this.slots!==4)throw new Error(`FaceTouchup: slots must be 1 or 4, got ${this.slots}`);if(this.grid=this.slots===4?2:1,this.activeSlots=this.slots,o.w*o.h<this.slots)throw new Error(`FaceTouchup: slots ${this.slots} exceeds the ${o.h}\xD7${o.w} box tensor`);if(r.c<this.slots*956)throw new Error(`FaceTouchup: landmarks tensor holds ${r.c/956} faces < slots ${this.slots}`);this.output=e.tensor(t.h,t.w,4),this.progs={unwrap:T(n,je,qe,"touchup-stage unwrap"),blur:T(n,W,Ye,"touchup-stage blur"),combine:T(n,W,Qe,"touchup-stage combine"),bilateral:T(n,W,Je,"touchup-stage bilateral"),blitT:T(n,W,jt,"touchup-stage blitT"),compT:T(n,Kt,Ze,"touchup-stage compT")},this.meshVao=n.createVertexArray(),n.bindVertexArray(this.meshVao);let u=n.createBuffer();n.bindBuffer(n.ARRAY_BUFFER,u),n.bufferData(n.ARRAY_BUFFER,i.uv,n.STATIC_DRAW),n.enableVertexAttribArray(0),n.vertexAttribPointer(0,2,n.FLOAT,false,0,0);let l=n.createBuffer();n.bindBuffer(n.ARRAY_BUFFER,l),n.bufferData(n.ARRAY_BUFFER,i.idx,n.STATIC_DRAW),n.enableVertexAttribArray(1),n.vertexAttribPointer(1,1,n.FLOAT,false,0,0),n.bindVertexArray(null);let p=h=>{let m=n.createTexture();return n.bindTexture(n.TEXTURE_2D,m),h?n.texImage2D(n.TEXTURE_2D,0,n.RGBA8,n.RGBA,n.UNSIGNED_BYTE,h):n.texImage2D(n.TEXTURE_2D,0,n.RGBA8,512,512,0,n.RGBA,n.UNSIGNED_BYTE,null),n.texParameteri(n.TEXTURE_2D,n.TEXTURE_MIN_FILTER,n.LINEAR),n.texParameteri(n.TEXTURE_2D,n.TEXTURE_MAG_FILTER,n.LINEAR),n.texParameteri(n.TEXTURE_2D,n.TEXTURE_WRAP_S,n.CLAMP_TO_EDGE),n.texParameteri(n.TEXTURE_2D,n.TEXTURE_WRAP_T,n.CLAMP_TO_EDGE),m};this.atlas=p(null),this.ping=p(null),this.low=p(null),this.smoothed=p(null),this.weightTex=p(i.weightMask),this.fbo=n.createFramebuffer();}backend;inputs;weights=[];output;progs;meshVao;fbo;atlas;ping;low;smoothed;weightTex;frame;lm;box;count;params;slots;grid;activeSlots;bindTex(e,t,r,o){let i=this.backend.gl;i.activeTexture(i.TEXTURE0+t),i.bindTexture(i.TEXTURE_2D,o),i.uniform1i(i.getUniformLocation(e,r),t);}lmUniforms(e){let t=this.backend.gl;this.bindTex(e,4,"u_lm",this.lm.texture),this.bindTex(e,5,"u_box",this.box.texture),t.uniform1f(t.getUniformLocation(e,"u_thresh"),this.params.thresh),t.uniform1f(t.getUniformLocation(e,"u_canvas_w"),this.frame.w),t.uniform1f(t.getUniformLocation(e,"u_canvas_h"),this.frame.h),t.uniform1i(t.getUniformLocation(e,"u_grid"),this.grid);}frameUniforms(e){let t=this.backend.gl;this.bindTex(e,0,"u_frame",this.frame.texture),t.uniform1f(t.getUniformLocation(e,"u_frame_w"),this.frame.w),t.uniform1f(t.getUniformLocation(e,"u_frame_h"),this.frame.h);}pass(e,t,r,o){let i=this.backend.gl;i.bindFramebuffer(i.FRAMEBUFFER,this.fbo),i.framebufferTexture2D(i.FRAMEBUFFER,i.COLOR_ATTACHMENT0,i.TEXTURE_2D,e,0),i.viewport(0,0,t,r),o();}setActiveSlots(e){this.activeSlots=Math.max(0,Math.min(e,this.slots));}run(){let e=this.backend.gl;if(this.pass(this.atlas,512,512,()=>{e.clearColor(0,0,0,0),e.clear(e.COLOR_BUFFER_BIT),e.useProgram(this.progs.unwrap),this.frameUniforms(this.progs.unwrap),this.lmUniforms(this.progs.unwrap),e.bindVertexArray(this.meshVao),e.drawArraysInstanced(e.TRIANGLES,0,this.count,this.activeSlots),e.bindVertexArray(null);}),(this.params.style??"freq-sep")==="bilateral")this.pass(this.smoothed,512,512,()=>{e.useProgram(this.progs.bilateral),this.bindTex(this.progs.bilateral,0,"u_tex",this.atlas),e.uniform1f(e.getUniformLocation(this.progs.bilateral,"u_sigma"),this.params.amount),e.uniform1i(e.getUniformLocation(this.progs.bilateral,"u_grid"),this.grid),e.drawArrays(e.TRIANGLES,0,6);});else {let t=(r,o,i,s)=>this.pass(o,512,512,()=>{e.useProgram(this.progs.blur),this.bindTex(this.progs.blur,0,"u_tex",r),e.uniform2f(e.getUniformLocation(this.progs.blur,"u_dir"),i,s),e.uniform1f(e.getUniformLocation(this.progs.blur,"u_sigma"),this.params.amount),e.uniform1i(e.getUniformLocation(this.progs.blur,"u_grid"),this.grid),e.drawArrays(e.TRIANGLES,0,6);});t(this.atlas,this.ping,1/512,0),t(this.ping,this.low,0,1/512),this.pass(this.smoothed,512,512,()=>{e.useProgram(this.progs.combine),this.bindTex(this.progs.combine,0,"u_atlas",this.atlas),this.bindTex(this.progs.combine,1,"u_low",this.low),e.uniform1f(e.getUniformLocation(this.progs.combine,"u_detail"),this.params.detail),e.drawArrays(e.TRIANGLES,0,6);});}this.pass(this.output.texture,this.frame.w,this.frame.h,()=>{e.useProgram(this.progs.blitT),this.bindTex(this.progs.blitT,0,"u_image",this.frame.texture),e.bindVertexArray(null),e.drawArrays(e.TRIANGLES,0,6),e.useProgram(this.progs.compT),this.frameUniforms(this.progs.compT),this.lmUniforms(this.progs.compT),this.bindTex(this.progs.compT,1,"u_smoothed",this.smoothed),this.bindTex(this.progs.compT,2,"u_weight",this.weightTex),e.uniform1f(e.getUniformLocation(this.progs.compT,"u_strength"),this.params.strength),e.bindVertexArray(this.meshVao),e.drawArraysInstanced(e.TRIANGLES,0,this.count,this.activeSlots),e.bindVertexArray(null);});}};var et=`#version 300 es
|
|
1060
|
+
// Flow-gated temporal stabilizer. Per pixel:
|
|
1061
|
+
// env = max(|flow.xy|, release\xB7envPrev.y) peak-hold
|
|
1062
|
+
// g = max(clamp((env - tLo)/(tHi - tLo), 0, 1), leak)
|
|
1063
|
+
// out = vec4((g\xB7pred + (1-g)\xB7ref).x, env, 0, 0)
|
|
1064
|
+
|
|
1065
|
+
precision highp float;
|
|
1066
|
+
precision highp int;
|
|
1067
|
+
|
|
1068
|
+
uniform sampler2D u_flow;
|
|
1069
|
+
uniform sampler2D u_pred;
|
|
1070
|
+
uniform sampler2D u_ref;
|
|
1071
|
+
uniform sampler2D u_env_prev;
|
|
1072
|
+
uniform int u_w;
|
|
1073
|
+
uniform int u_h;
|
|
1074
|
+
uniform float u_t_lo;
|
|
1075
|
+
uniform float u_t_hi;
|
|
1076
|
+
uniform float u_leak;
|
|
1077
|
+
uniform float u_release;
|
|
1078
|
+
uniform float u_t_div;
|
|
1079
|
+
uniform float u_div_scale;
|
|
1080
|
+
uniform int u_step_x;
|
|
1081
|
+
uniform int u_step_y;
|
|
1082
|
+
|
|
1083
|
+
out vec4 fragColor;
|
|
1084
|
+
|
|
1085
|
+
void main() {
|
|
1086
|
+
int x = int(gl_FragCoord.x);
|
|
1087
|
+
int y = int(gl_FragCoord.y);
|
|
1088
|
+
|
|
1089
|
+
float mag = length(texelFetch(u_flow, ivec2(x, y), 0).xy);
|
|
1090
|
+
float envPrev = texelFetch(u_env_prev, ivec2(x, y), 0).y;
|
|
1091
|
+
float env = max(mag, u_release * envPrev);
|
|
1092
|
+
|
|
1093
|
+
// Flow divergence over a \xB1step finite-difference (clamped to the edges).
|
|
1094
|
+
int xr = min(x + u_step_x, u_w - 1);
|
|
1095
|
+
int xl = max(x - u_step_x, 0);
|
|
1096
|
+
int yd = min(y + u_step_y, u_h - 1);
|
|
1097
|
+
int yu = max(y - u_step_y, 0);
|
|
1098
|
+
float dfx = texelFetch(u_flow, ivec2(xr, y), 0).x - texelFetch(u_flow, ivec2(xl, y), 0).x;
|
|
1099
|
+
float dfy = texelFetch(u_flow, ivec2(x, yd), 0).y - texelFetch(u_flow, ivec2(x, yu), 0).y;
|
|
1100
|
+
float divg = abs(dfx + dfy);
|
|
1101
|
+
|
|
1102
|
+
float gMag = clamp((env - u_t_lo) / max(u_t_hi - u_t_lo, 1e-3), 0.0, 1.0);
|
|
1103
|
+
float gDiv = clamp((divg - u_t_div) / max(u_div_scale, 1e-3), 0.0, 1.0);
|
|
1104
|
+
float g = max(max(gMag, gDiv), u_leak);
|
|
1105
|
+
|
|
1106
|
+
float pred = texelFetch(u_pred, ivec2(x, y), 0).x;
|
|
1107
|
+
float refv = texelFetch(u_ref, ivec2(x, y), 0).x;
|
|
1108
|
+
float stab = g * pred + (1.0 - g) * refv;
|
|
1109
|
+
|
|
1110
|
+
fragColor = vec4(stab, env, 0.0, 0.0);
|
|
1111
|
+
}
|
|
1112
|
+
`;var z=class extends c{inputs;weights=[];output;dispatch;shader=et;constructor(e,t,r,o,i,s){super(e);let n=t.w,u=t.h,l=this.makeTexture(null,n,u);this.output={h:u,w:n,c:4,texture:l,texW:n,texH:u},this.inputs=[t,r,o,i],this.samplers=[{name:"u_flow",texture:t.texture},{name:"u_pred",texture:r.texture},{name:"u_ref",texture:o.texture},{name:"u_env_prev",texture:i.texture}],this.uniformInts={u_w:n,u_h:u,u_step_x:s.stepX,u_step_y:s.stepY},this.uniformFloats={u_t_lo:s.tLo,u_t_hi:s.tHi,u_leak:s.leak,u_release:s.release,u_t_div:s.tDiv,u_div_scale:s.divScale},this.defaultSetup(),this.dispatch=[n,u];}};var tt=`#version 300 es
|
|
1113
|
+
// Bilinear upsample (arbitrary scale) \u2014 align_corners=False.
|
|
1114
|
+
//
|
|
1115
|
+
// Hardware texture filtering can't be used: adjacent texels in x belong to
|
|
1116
|
+
// different channel groups, not spatial neighbours. Manual 4-tap blend.
|
|
1117
|
+
//
|
|
1118
|
+
// Input: (in_W * c_groups, in_H)
|
|
1119
|
+
// Output: (out_W * c_groups, out_H)
|
|
1120
|
+
|
|
1121
|
+
precision highp float;
|
|
1122
|
+
precision highp int;
|
|
1123
|
+
|
|
1124
|
+
uniform sampler2D u_input;
|
|
1125
|
+
uniform int u_in_w;
|
|
1126
|
+
uniform int u_in_h;
|
|
1127
|
+
uniform int u_out_w;
|
|
1128
|
+
uniform int u_out_h;
|
|
1129
|
+
uniform int u_c_groups;
|
|
1130
|
+
|
|
1131
|
+
out vec4 fragColor;
|
|
1132
|
+
|
|
1133
|
+
void main() {
|
|
1134
|
+
ivec2 fc = ivec2(gl_FragCoord.xy);
|
|
1135
|
+
int x_out = fc.x / u_c_groups;
|
|
1136
|
+
int y_out = fc.y;
|
|
1137
|
+
int c_group = fc.x - x_out * u_c_groups;
|
|
1138
|
+
|
|
1139
|
+
float scale_x = float(u_in_w) / float(u_out_w);
|
|
1140
|
+
float scale_y = float(u_in_h) / float(u_out_h);
|
|
1141
|
+
float src_x = (float(x_out) + 0.5) * scale_x - 0.5;
|
|
1142
|
+
float src_y = (float(y_out) + 0.5) * scale_y - 0.5;
|
|
1143
|
+
|
|
1144
|
+
int x0 = int(floor(src_x));
|
|
1145
|
+
int y0 = int(floor(src_y));
|
|
1146
|
+
int x1 = x0 + 1;
|
|
1147
|
+
int y1 = y0 + 1;
|
|
1148
|
+
float fx = src_x - float(x0);
|
|
1149
|
+
float fy = src_y - float(y0);
|
|
1150
|
+
|
|
1151
|
+
x0 = clamp(x0, 0, u_in_w - 1);
|
|
1152
|
+
y0 = clamp(y0, 0, u_in_h - 1);
|
|
1153
|
+
x1 = clamp(x1, 0, u_in_w - 1);
|
|
1154
|
+
y1 = clamp(y1, 0, u_in_h - 1);
|
|
1155
|
+
|
|
1156
|
+
vec4 v00 = texelFetch(u_input, ivec2(x0 * u_c_groups + c_group, y0), 0);
|
|
1157
|
+
vec4 v10 = texelFetch(u_input, ivec2(x1 * u_c_groups + c_group, y0), 0);
|
|
1158
|
+
vec4 v01 = texelFetch(u_input, ivec2(x0 * u_c_groups + c_group, y1), 0);
|
|
1159
|
+
vec4 v11 = texelFetch(u_input, ivec2(x1 * u_c_groups + c_group, y1), 0);
|
|
1160
|
+
|
|
1161
|
+
fragColor = mix(mix(v00, v10, fx), mix(v01, v11, fx), fy);
|
|
1162
|
+
}
|
|
1163
|
+
`;var $=class extends c{inputs;weights=[];output;dispatch;shader=tt;constructor(e,t,r){super(e);let o=t.c/4,i=r.outW*o,s=this.makeTexture(null,i,r.outH);this.output={h:r.outH,w:r.outW,c:t.c,texture:s,texW:i,texH:r.outH},this.inputs=[t],this.samplers=[{name:"u_input",texture:t.texture}],this.uniformInts={u_in_w:t.w,u_in_h:t.h,u_out_w:r.outW,u_out_h:r.outH,u_c_groups:o},this.defaultSetup(),this.dispatch=[i,r.outH];}};var ot=`#version 300 es
|
|
1164
|
+
// Top-left crop: the output viewport is smaller than the input texture, so reading
|
|
1165
|
+
// the same fragment coord yields the top-left subregion (channel groups packed in
|
|
1166
|
+
// the x axis line up because group count is unchanged).
|
|
1167
|
+
|
|
1168
|
+
precision highp float;
|
|
1169
|
+
precision highp int;
|
|
1170
|
+
|
|
1171
|
+
uniform sampler2D u_input;
|
|
1172
|
+
out vec4 fragColor;
|
|
1173
|
+
|
|
1174
|
+
void main() {
|
|
1175
|
+
fragColor = texelFetch(u_input, ivec2(int(gl_FragCoord.x), int(gl_FragCoord.y)), 0);
|
|
1176
|
+
}
|
|
1177
|
+
`;var j=class extends c{inputs;weights=[];output;dispatch;shader=ot;constructor(e,t,r){super(e);let o=t.c/4,i=r.outW*o,s=this.makeTexture(null,i,r.outH);this.output={h:r.outH,w:r.outW,c:t.c,texture:s,texW:i,texH:r.outH},this.inputs=[t],this.samplers=[{name:"u_input",texture:t.texture}],this.defaultSetup(),this.dispatch=[i,r.outH];}};var rt=`#version 300 es
|
|
1178
|
+
// Bicubic upsample (arbitrary scale) \u2014 Keys cubic, a=-0.75 (PyTorch default
|
|
1179
|
+
// for mode='bicubic', align_corners=False).
|
|
1180
|
+
//
|
|
1181
|
+
// Direct 2D, 4\xD74 = 16 taps per output pixel. Hardware texture filtering
|
|
1182
|
+
// can't be used (NHWC vec4 layout means adjacent texels in x belong to
|
|
1183
|
+
// different channel groups, not spatial neighbours).
|
|
1184
|
+
|
|
1185
|
+
precision highp float;
|
|
1186
|
+
precision highp int;
|
|
1187
|
+
|
|
1188
|
+
uniform sampler2D u_input;
|
|
1189
|
+
uniform int u_in_w;
|
|
1190
|
+
uniform int u_in_h;
|
|
1191
|
+
uniform int u_out_w;
|
|
1192
|
+
uniform int u_out_h;
|
|
1193
|
+
uniform int u_c_groups;
|
|
1194
|
+
|
|
1195
|
+
const float A = -0.75;
|
|
1196
|
+
|
|
1197
|
+
float wcubic(float d) {
|
|
1198
|
+
float ad = abs(d);
|
|
1199
|
+
if (ad <= 1.0) return ((A + 2.0) * ad - (A + 3.0)) * ad * ad + 1.0;
|
|
1200
|
+
if (ad < 2.0) return ((A * ad - 5.0 * A) * ad + 8.0 * A) * ad - 4.0 * A;
|
|
1201
|
+
return 0.0;
|
|
1202
|
+
}
|
|
1203
|
+
|
|
1204
|
+
out vec4 fragColor;
|
|
1205
|
+
|
|
1206
|
+
void main() {
|
|
1207
|
+
ivec2 fc = ivec2(gl_FragCoord.xy);
|
|
1208
|
+
int x_out = fc.x / u_c_groups;
|
|
1209
|
+
int y_out = fc.y;
|
|
1210
|
+
int c_group = fc.x - x_out * u_c_groups;
|
|
1211
|
+
|
|
1212
|
+
float src_x = (float(x_out) + 0.5) * float(u_in_w) / float(u_out_w) - 0.5;
|
|
1213
|
+
float src_y = (float(y_out) + 0.5) * float(u_in_h) / float(u_out_h) - 0.5;
|
|
1214
|
+
|
|
1215
|
+
int x0 = int(floor(src_x));
|
|
1216
|
+
int y0 = int(floor(src_y));
|
|
1217
|
+
float fx = src_x - float(x0);
|
|
1218
|
+
float fy = src_y - float(y0);
|
|
1219
|
+
|
|
1220
|
+
// Weights for offsets {-1, 0, 1, 2} from x0/y0.
|
|
1221
|
+
float wx[4];
|
|
1222
|
+
float wy[4];
|
|
1223
|
+
wx[0] = wcubic(1.0 + fx); wx[1] = wcubic(fx); wx[2] = wcubic(1.0 - fx); wx[3] = wcubic(2.0 - fx);
|
|
1224
|
+
wy[0] = wcubic(1.0 + fy); wy[1] = wcubic(fy); wy[2] = wcubic(1.0 - fy); wy[3] = wcubic(2.0 - fy);
|
|
1225
|
+
|
|
1226
|
+
vec4 acc = vec4(0.0);
|
|
1227
|
+
for (int j = 0; j < 4; j++) {
|
|
1228
|
+
int sy = clamp(y0 + j - 1, 0, u_in_h - 1);
|
|
1229
|
+
for (int i = 0; i < 4; i++) {
|
|
1230
|
+
int sx = clamp(x0 + i - 1, 0, u_in_w - 1);
|
|
1231
|
+
vec4 v = texelFetch(u_input, ivec2(sx * u_c_groups + c_group, sy), 0);
|
|
1232
|
+
acc += (wx[i] * wy[j]) * v;
|
|
1233
|
+
}
|
|
1234
|
+
}
|
|
1235
|
+
fragColor = acc;
|
|
1236
|
+
}
|
|
1237
|
+
`;var K=class extends c{inputs;weights=[];output;dispatch;shader=rt;constructor(e,t,r){super(e);let o=t.c/4,i=r.outW*o,s=this.makeTexture(null,i,r.outH);this.output={h:r.outH,w:r.outW,c:t.c,texture:s,texW:i,texH:r.outH},this.inputs=[t],this.samplers=[{name:"u_input",texture:t.texture}],this.uniformInts={u_in_w:t.w,u_in_h:t.h,u_out_w:r.outW,u_out_h:r.outH,u_c_groups:o},this.defaultSetup(),this.dispatch=[i,r.outH];}};var it=`#version 300 es
|
|
1238
|
+
// Channel concat \u2014 concatenates two NHWC textures along the channel dimension.
|
|
1239
|
+
// Both inputs must share the same spatial dimensions (W, H). Channel counts are
|
|
1240
|
+
// multiples of 4 so each "group" is one vec4 texel.
|
|
1241
|
+
//
|
|
1242
|
+
// Input A: (W * a_c_groups, H)
|
|
1243
|
+
// Input B: (W * b_c_groups, H)
|
|
1244
|
+
// Output: (W * (a_c_groups + b_c_groups), H)
|
|
1245
|
+
|
|
1246
|
+
precision highp float;
|
|
1247
|
+
precision highp int;
|
|
1248
|
+
|
|
1249
|
+
uniform sampler2D u_input_a;
|
|
1250
|
+
uniform sampler2D u_input_b;
|
|
1251
|
+
uniform int u_a_c_groups;
|
|
1252
|
+
uniform int u_b_c_groups;
|
|
1253
|
+
|
|
1254
|
+
out vec4 fragColor;
|
|
1255
|
+
|
|
1256
|
+
void main() {
|
|
1257
|
+
ivec2 fc = ivec2(gl_FragCoord.xy);
|
|
1258
|
+
int out_groups = u_a_c_groups + u_b_c_groups;
|
|
1259
|
+
int x_spatial = fc.x / out_groups;
|
|
1260
|
+
int c_out = fc.x - x_spatial * out_groups;
|
|
1261
|
+
int y = fc.y;
|
|
1262
|
+
|
|
1263
|
+
if (c_out < u_a_c_groups) {
|
|
1264
|
+
fragColor = texelFetch(u_input_a, ivec2(x_spatial * u_a_c_groups + c_out, y), 0);
|
|
1265
|
+
} else {
|
|
1266
|
+
int c_b = c_out - u_a_c_groups;
|
|
1267
|
+
fragColor = texelFetch(u_input_b, ivec2(x_spatial * u_b_c_groups + c_b, y), 0);
|
|
1268
|
+
}
|
|
1269
|
+
}
|
|
1270
|
+
`;var q=class extends c{inputs;weights=[];output;dispatch;shader=it;constructor(e,t,r){super(e);let o=t.c/4,i=r.c/4,s=o+i,n=t.c+r.c,u=t.w*s,l=this.makeTexture(null,u,t.h);this.output={h:t.h,w:t.w,c:n,texture:l,texW:u,texH:t.h},this.inputs=[t,r],this.samplers=[{name:"u_input_a",texture:t.texture},{name:"u_input_b",texture:r.texture}],this.uniformInts={u_a_c_groups:o,u_b_c_groups:i},this.defaultSetup(),this.dispatch=[u,t.h];}};var nt=`#version 300 es
|
|
1271
|
+
// Bilinear upsample + sigmoid fused \u2014 sigmoid applied at write time, no intermediate buffer.
|
|
1272
|
+
// See bilinear_upsample.glsl for the manual 4-tap blend rationale.
|
|
1273
|
+
//
|
|
1274
|
+
// Input: (in_W * c_groups, in_H)
|
|
1275
|
+
// Output: (out_W * c_groups, out_H)
|
|
1276
|
+
|
|
1277
|
+
precision highp float;
|
|
1278
|
+
precision highp int;
|
|
1279
|
+
|
|
1280
|
+
uniform sampler2D u_input;
|
|
1281
|
+
uniform int u_in_w;
|
|
1282
|
+
uniform int u_in_h;
|
|
1283
|
+
uniform int u_out_w;
|
|
1284
|
+
uniform int u_out_h;
|
|
1285
|
+
uniform int u_c_groups;
|
|
1286
|
+
|
|
1287
|
+
out vec4 fragColor;
|
|
1288
|
+
|
|
1289
|
+
void main() {
|
|
1290
|
+
ivec2 fc = ivec2(gl_FragCoord.xy);
|
|
1291
|
+
int x_out = fc.x / u_c_groups;
|
|
1292
|
+
int y_out = fc.y;
|
|
1293
|
+
int c_group = fc.x - x_out * u_c_groups;
|
|
1294
|
+
|
|
1295
|
+
float scale_x = float(u_in_w) / float(u_out_w);
|
|
1296
|
+
float scale_y = float(u_in_h) / float(u_out_h);
|
|
1297
|
+
float src_x = (float(x_out) + 0.5) * scale_x - 0.5;
|
|
1298
|
+
float src_y = (float(y_out) + 0.5) * scale_y - 0.5;
|
|
1299
|
+
|
|
1300
|
+
int x0 = int(floor(src_x));
|
|
1301
|
+
int y0 = int(floor(src_y));
|
|
1302
|
+
int x1 = x0 + 1;
|
|
1303
|
+
int y1 = y0 + 1;
|
|
1304
|
+
float fx = src_x - float(x0);
|
|
1305
|
+
float fy = src_y - float(y0);
|
|
1306
|
+
|
|
1307
|
+
x0 = clamp(x0, 0, u_in_w - 1);
|
|
1308
|
+
y0 = clamp(y0, 0, u_in_h - 1);
|
|
1309
|
+
x1 = clamp(x1, 0, u_in_w - 1);
|
|
1310
|
+
y1 = clamp(y1, 0, u_in_h - 1);
|
|
1311
|
+
|
|
1312
|
+
vec4 v00 = texelFetch(u_input, ivec2(x0 * u_c_groups + c_group, y0), 0);
|
|
1313
|
+
vec4 v10 = texelFetch(u_input, ivec2(x1 * u_c_groups + c_group, y0), 0);
|
|
1314
|
+
vec4 v01 = texelFetch(u_input, ivec2(x0 * u_c_groups + c_group, y1), 0);
|
|
1315
|
+
vec4 v11 = texelFetch(u_input, ivec2(x1 * u_c_groups + c_group, y1), 0);
|
|
1316
|
+
|
|
1317
|
+
vec4 result = mix(mix(v00, v10, fx), mix(v01, v11, fx), fy);
|
|
1318
|
+
fragColor = 1.0 / (1.0 + exp(-result));
|
|
1319
|
+
}
|
|
1320
|
+
`;var Y=class extends c{inputs;weights=[];output;dispatch;shader=nt;constructor(e,t,r){super(e);let o=t.c/4,i=r.outW*o,s=this.makeTexture(null,i,r.outH);this.output={h:r.outH,w:r.outW,c:t.c,texture:s,texW:i,texH:r.outH},this.inputs=[t],this.samplers=[{name:"u_input",texture:t.texture}],this.uniformInts={u_in_w:t.w,u_in_h:t.h,u_out_w:r.outW,u_out_h:r.outH,u_c_groups:o},this.defaultSetup(),this.dispatch=[i,r.outH];}};var st=`#version 300 es
|
|
1321
|
+
// Bilinear upsample (input_a) + channel concat (with input_b) fused.
|
|
1322
|
+
// input_a is the decoder tensor at small spatial res (in_h \xD7 in_w), bilinearly resized to (out_h \xD7 out_w).
|
|
1323
|
+
// input_b is the encoder skip feature already at output resolution.
|
|
1324
|
+
// Output channels [0..a_groups-1] come from upsampled input_a.
|
|
1325
|
+
// Output channels [a_groups..out_groups-1] come from input_b (passthrough).
|
|
1326
|
+
|
|
1327
|
+
precision highp float;
|
|
1328
|
+
precision highp int;
|
|
1329
|
+
|
|
1330
|
+
uniform sampler2D u_input_a;
|
|
1331
|
+
uniform sampler2D u_input_b;
|
|
1332
|
+
uniform int u_in_w;
|
|
1333
|
+
uniform int u_in_h;
|
|
1334
|
+
uniform int u_out_w;
|
|
1335
|
+
uniform int u_out_h;
|
|
1336
|
+
uniform int u_a_c_groups;
|
|
1337
|
+
uniform int u_b_c_groups;
|
|
1338
|
+
|
|
1339
|
+
out vec4 fragColor;
|
|
1340
|
+
|
|
1341
|
+
void main() {
|
|
1342
|
+
ivec2 fc = ivec2(gl_FragCoord.xy);
|
|
1343
|
+
int out_groups = u_a_c_groups + u_b_c_groups;
|
|
1344
|
+
int x_out = fc.x / out_groups;
|
|
1345
|
+
int c_out = fc.x - x_out * out_groups;
|
|
1346
|
+
int y_out = fc.y;
|
|
1347
|
+
|
|
1348
|
+
if (c_out < u_a_c_groups) {
|
|
1349
|
+
// Bilinear sample from input_a at (x_out, y_out) for channel group c_out.
|
|
1350
|
+
float scale_x = float(u_in_w) / float(u_out_w);
|
|
1351
|
+
float scale_y = float(u_in_h) / float(u_out_h);
|
|
1352
|
+
float src_x = (float(x_out) + 0.5) * scale_x - 0.5;
|
|
1353
|
+
float src_y = (float(y_out) + 0.5) * scale_y - 0.5;
|
|
1354
|
+
|
|
1355
|
+
int x0 = int(floor(src_x));
|
|
1356
|
+
int y0 = int(floor(src_y));
|
|
1357
|
+
int x1 = x0 + 1;
|
|
1358
|
+
int y1 = y0 + 1;
|
|
1359
|
+
float fx = src_x - float(x0);
|
|
1360
|
+
float fy = src_y - float(y0);
|
|
1361
|
+
|
|
1362
|
+
x0 = clamp(x0, 0, u_in_w - 1);
|
|
1363
|
+
y0 = clamp(y0, 0, u_in_h - 1);
|
|
1364
|
+
x1 = clamp(x1, 0, u_in_w - 1);
|
|
1365
|
+
y1 = clamp(y1, 0, u_in_h - 1);
|
|
1366
|
+
|
|
1367
|
+
vec4 v00 = texelFetch(u_input_a, ivec2(x0 * u_a_c_groups + c_out, y0), 0);
|
|
1368
|
+
vec4 v10 = texelFetch(u_input_a, ivec2(x1 * u_a_c_groups + c_out, y0), 0);
|
|
1369
|
+
vec4 v01 = texelFetch(u_input_a, ivec2(x0 * u_a_c_groups + c_out, y1), 0);
|
|
1370
|
+
vec4 v11 = texelFetch(u_input_a, ivec2(x1 * u_a_c_groups + c_out, y1), 0);
|
|
1371
|
+
|
|
1372
|
+
fragColor = mix(mix(v00, v10, fx), mix(v01, v11, fx), fy);
|
|
1373
|
+
} else {
|
|
1374
|
+
int c_b = c_out - u_a_c_groups;
|
|
1375
|
+
fragColor = texelFetch(u_input_b, ivec2(x_out * u_b_c_groups + c_b, y_out), 0);
|
|
1376
|
+
}
|
|
1377
|
+
}
|
|
1378
|
+
`;var Q=class extends c{inputs;weights=[];output;dispatch;shader=st;constructor(e,t,r,o){super(e);let i=t.c/4,s=r.c/4,n=i+s,u=t.c+r.c,l=o.outW*n,p=this.makeTexture(null,l,o.outH);this.output={h:o.outH,w:o.outW,c:u,texture:p,texW:l,texH:o.outH},this.inputs=[t,r],this.samplers=[{name:"u_input_a",texture:t.texture},{name:"u_input_b",texture:r.texture}],this.uniformInts={u_in_w:t.w,u_in_h:t.h,u_out_w:o.outW,u_out_h:o.outH,u_a_c_groups:i,u_b_c_groups:s},this.defaultSetup(),this.dispatch=[l,o.outH];}};var at=`#version 300 es
|
|
1379
|
+
// Bilinear upsample + 1\xD71 pointwise conv fused.
|
|
1380
|
+
// For each output pixel + out group, bilinearly samples each in_group from input,
|
|
1381
|
+
// applies the 1\xD71 conv weight, and writes the activated result.
|
|
1382
|
+
//
|
|
1383
|
+
// Input: (in_W * in_groups, in_H)
|
|
1384
|
+
// Output: (out_W * out_groups, out_H)
|
|
1385
|
+
// Weights: (in_groups * 4, out_groups) (K=1, so kernel-row dimension collapses)
|
|
1386
|
+
// mat4[col][row] = weight(in_channel=col, out_channel=row)
|
|
1387
|
+
// Bias: (out_groups, 1)
|
|
1388
|
+
|
|
1389
|
+
precision highp float;
|
|
1390
|
+
precision highp int;
|
|
1391
|
+
|
|
1392
|
+
uniform sampler2D u_input;
|
|
1393
|
+
uniform sampler2D u_weights;
|
|
1394
|
+
uniform sampler2D u_bias;
|
|
1395
|
+
|
|
1396
|
+
uniform int u_in_w;
|
|
1397
|
+
uniform int u_in_h;
|
|
1398
|
+
uniform int u_out_w;
|
|
1399
|
+
uniform int u_out_h;
|
|
1400
|
+
uniform int u_in_c_groups;
|
|
1401
|
+
uniform int u_out_c_groups;
|
|
1402
|
+
uniform int u_activation; // 0 = none, 1 = relu6, 2 = relu
|
|
1403
|
+
|
|
1404
|
+
out vec4 fragColor;
|
|
1405
|
+
|
|
1406
|
+
void main() {
|
|
1407
|
+
int fx = int(gl_FragCoord.x);
|
|
1408
|
+
int fy = int(gl_FragCoord.y);
|
|
1409
|
+
int x_out = fx / u_out_c_groups;
|
|
1410
|
+
int y_out = fy;
|
|
1411
|
+
int o_group = fx - x_out * u_out_c_groups;
|
|
1412
|
+
|
|
1413
|
+
float scale_x = float(u_in_w) / float(u_out_w);
|
|
1414
|
+
float scale_y = float(u_in_h) / float(u_out_h);
|
|
1415
|
+
float src_x = (float(x_out) + 0.5) * scale_x - 0.5;
|
|
1416
|
+
float src_y = (float(y_out) + 0.5) * scale_y - 0.5;
|
|
1417
|
+
|
|
1418
|
+
int x0 = int(floor(src_x));
|
|
1419
|
+
int y0 = int(floor(src_y));
|
|
1420
|
+
int x1 = x0 + 1;
|
|
1421
|
+
int y1 = y0 + 1;
|
|
1422
|
+
float fx_w = src_x - float(x0);
|
|
1423
|
+
float fy_w = src_y - float(y0);
|
|
1424
|
+
|
|
1425
|
+
x0 = clamp(x0, 0, u_in_w - 1);
|
|
1426
|
+
y0 = clamp(y0, 0, u_in_h - 1);
|
|
1427
|
+
x1 = clamp(x1, 0, u_in_w - 1);
|
|
1428
|
+
y1 = clamp(y1, 0, u_in_h - 1);
|
|
1429
|
+
|
|
1430
|
+
vec4 result = texelFetch(u_bias, ivec2(o_group, 0), 0);
|
|
1431
|
+
|
|
1432
|
+
for (int i = 0; i < u_in_c_groups; i++) {
|
|
1433
|
+
vec4 v00 = texelFetch(u_input, ivec2(x0 * u_in_c_groups + i, y0), 0);
|
|
1434
|
+
vec4 v10 = texelFetch(u_input, ivec2(x1 * u_in_c_groups + i, y0), 0);
|
|
1435
|
+
vec4 v01 = texelFetch(u_input, ivec2(x0 * u_in_c_groups + i, y1), 0);
|
|
1436
|
+
vec4 v11 = texelFetch(u_input, ivec2(x1 * u_in_c_groups + i, y1), 0);
|
|
1437
|
+
|
|
1438
|
+
vec4 sampled = mix(mix(v00, v10, fx_w), mix(v01, v11, fx_w), fy_w);
|
|
1439
|
+
|
|
1440
|
+
int base = i * 4;
|
|
1441
|
+
mat4 w = mat4(
|
|
1442
|
+
texelFetch(u_weights, ivec2(base, o_group), 0),
|
|
1443
|
+
texelFetch(u_weights, ivec2(base + 1, o_group), 0),
|
|
1444
|
+
texelFetch(u_weights, ivec2(base + 2, o_group), 0),
|
|
1445
|
+
texelFetch(u_weights, ivec2(base + 3, o_group), 0)
|
|
1446
|
+
);
|
|
1447
|
+
result += w * sampled;
|
|
1448
|
+
}
|
|
1449
|
+
|
|
1450
|
+
if (u_activation == 1) result = clamp(result, 0.0, 6.0);
|
|
1451
|
+
else if (u_activation == 2) result = max(result, vec4(0.0));
|
|
1452
|
+
|
|
1453
|
+
fragColor = result;
|
|
1454
|
+
}
|
|
1455
|
+
`;var J=class extends c{inputs;weights;output;dispatch;shader=at;constructor(e,t,r,o){super(e);let i=t.c/4,s=o.outChannels/4,n=f$1(r.weights),u=f$1(r.bias),l=this.makeTexture(n,i*4,s),p=this.makeTexture(u,s,1),h=o.outW*s,m=this.makeTexture(null,h,o.outH);this.output={h:o.outH,w:o.outW,c:o.outChannels,texture:m,texW:h,texH:o.outH},this.inputs=[t],this.weights=[],this.samplers=[{name:"u_input",texture:t.texture},{name:"u_weights",texture:l},{name:"u_bias",texture:p}],this.uniformInts={u_in_w:t.w,u_in_h:t.h,u_out_w:o.outW,u_out_h:o.outH,u_in_c_groups:i,u_out_c_groups:s,u_activation:o.activation==="relu6"?1:0},this.defaultSetup(),this.dispatch=[h,o.outH];}};var ut=`#version 300 es
|
|
1456
|
+
// Conv2d + skip add fused \u2014 identical to conv2d.glsl with a skip texture added at write time.
|
|
1457
|
+
// See conv2d.glsl for tensor/weight layout details.
|
|
1458
|
+
|
|
1459
|
+
precision highp float;
|
|
1460
|
+
precision highp int;
|
|
1461
|
+
|
|
1462
|
+
uniform sampler2D u_input;
|
|
1463
|
+
uniform sampler2D u_skip;
|
|
1464
|
+
uniform sampler2D u_weights;
|
|
1465
|
+
uniform sampler2D u_bias;
|
|
1466
|
+
|
|
1467
|
+
uniform int u_in_w;
|
|
1468
|
+
uniform int u_in_h;
|
|
1469
|
+
uniform int u_in_c_groups;
|
|
1470
|
+
uniform int u_out_c_groups;
|
|
1471
|
+
uniform int u_kernel_h;
|
|
1472
|
+
uniform int u_kernel_w;
|
|
1473
|
+
uniform int u_stride;
|
|
1474
|
+
uniform int u_pad_top;
|
|
1475
|
+
uniform int u_pad_left;
|
|
1476
|
+
uniform int u_activation; // 0 = none, 1 = relu6, 2 = relu
|
|
1477
|
+
|
|
1478
|
+
out vec4 fragColor;
|
|
1479
|
+
|
|
1480
|
+
void main() {
|
|
1481
|
+
int fx = int(gl_FragCoord.x);
|
|
1482
|
+
int fy = int(gl_FragCoord.y);
|
|
1483
|
+
int x_out = fx / u_out_c_groups;
|
|
1484
|
+
int y_out = fy;
|
|
1485
|
+
int o_group = fx - x_out * u_out_c_groups;
|
|
1486
|
+
|
|
1487
|
+
vec4 result = texelFetch(u_bias, ivec2(o_group, 0), 0);
|
|
1488
|
+
|
|
1489
|
+
for (int ky = 0; ky < u_kernel_h; ky++) {
|
|
1490
|
+
for (int kx = 0; kx < u_kernel_w; kx++) {
|
|
1491
|
+
int in_y = y_out * u_stride + ky - u_pad_top;
|
|
1492
|
+
int in_x = x_out * u_stride + kx - u_pad_left;
|
|
1493
|
+
|
|
1494
|
+
if (in_y < 0 || in_y >= u_in_h || in_x < 0 || in_x >= u_in_w) continue;
|
|
1495
|
+
|
|
1496
|
+
int z = ky * u_kernel_w + kx;
|
|
1497
|
+
int w_row = z * u_out_c_groups + o_group;
|
|
1498
|
+
|
|
1499
|
+
for (int i = 0; i < u_in_c_groups; i++) {
|
|
1500
|
+
vec4 in_val = texelFetch(u_input, ivec2(in_x * u_in_c_groups + i, in_y), 0);
|
|
1501
|
+
|
|
1502
|
+
int base = i * 4;
|
|
1503
|
+
mat4 w = mat4(
|
|
1504
|
+
texelFetch(u_weights, ivec2(base, w_row), 0),
|
|
1505
|
+
texelFetch(u_weights, ivec2(base + 1, w_row), 0),
|
|
1506
|
+
texelFetch(u_weights, ivec2(base + 2, w_row), 0),
|
|
1507
|
+
texelFetch(u_weights, ivec2(base + 3, w_row), 0)
|
|
1508
|
+
);
|
|
1509
|
+
result += w * in_val;
|
|
1510
|
+
}
|
|
1511
|
+
}
|
|
1512
|
+
}
|
|
1513
|
+
|
|
1514
|
+
if (u_activation == 1) result = clamp(result, 0.0, 6.0);
|
|
1515
|
+
else if (u_activation == 2) result = max(result, vec4(0.0));
|
|
1516
|
+
|
|
1517
|
+
fragColor = result + texelFetch(u_skip, ivec2(fx, fy), 0);
|
|
1518
|
+
}
|
|
1519
|
+
`;var Z=class extends c{inputs;weights;output;dispatch;shader=ut;constructor(e$1,t,r,o,i){super(e$1);let s=c$1(t.h,i.kernel,i.stride,i.padding),n=c$1(t.w,i.kernel,i.stride,i.padding),u=t.c/4,l=i.outChannels/4,p=e(i.padding,t.h,s,i.kernel,i.stride),h=e(i.padding,t.w,n,i.kernel,i.stride),m=f$1(o.weights),x=f$1(o.bias),_=this.makeTexture(m,u*4,i.kernel*i.kernel*l),g=this.makeTexture(x,l,1),b=n*l,L=this.makeTexture(null,b,s);this.output={h:s,w:n,c:i.outChannels,texture:L,texW:b,texH:s},this.inputs=[t,r],this.weights=[],this.samplers=[{name:"u_input",texture:t.texture},{name:"u_skip",texture:r.texture},{name:"u_weights",texture:_},{name:"u_bias",texture:g}],this.uniformInts={u_in_w:t.w,u_in_h:t.h,u_in_c_groups:u,u_out_c_groups:l,u_kernel_h:i.kernel,u_kernel_w:i.kernel,u_stride:i.stride,u_pad_top:p,u_pad_left:h,u_activation:i.activation==="relu6"?1:0},this.defaultSetup(),this.dispatch=[b,s];}};var lt=`#version 300 es
|
|
1520
|
+
// proj_residual: bespoke 1\xD71 conv (no activation) + residual add, fused.
|
|
1521
|
+
// Specializes conv2d_add to kernel=1 / stride=1 / pad=0 / no activation. Both
|
|
1522
|
+
// inputs share the same spatial resolution. See conv2d.glsl for the weight
|
|
1523
|
+
// texture layout (here K=1, so the weight texture is (inGroups*4, outGroups)).
|
|
1524
|
+
|
|
1525
|
+
precision highp float;
|
|
1526
|
+
precision highp int;
|
|
1527
|
+
|
|
1528
|
+
uniform sampler2D u_input;
|
|
1529
|
+
uniform sampler2D u_skip;
|
|
1530
|
+
uniform sampler2D u_weights;
|
|
1531
|
+
uniform sampler2D u_bias;
|
|
1532
|
+
|
|
1533
|
+
uniform int u_in_c_groups;
|
|
1534
|
+
uniform int u_out_c_groups;
|
|
1535
|
+
|
|
1536
|
+
out vec4 fragColor;
|
|
1537
|
+
|
|
1538
|
+
void main() {
|
|
1539
|
+
int fx = int(gl_FragCoord.x);
|
|
1540
|
+
int fy = int(gl_FragCoord.y);
|
|
1541
|
+
int x_out = fx / u_out_c_groups;
|
|
1542
|
+
int o_group = fx - x_out * u_out_c_groups;
|
|
1543
|
+
|
|
1544
|
+
vec4 result = texelFetch(u_bias, ivec2(o_group, 0), 0);
|
|
1545
|
+
|
|
1546
|
+
for (int i = 0; i < u_in_c_groups; i++) {
|
|
1547
|
+
vec4 in_val = texelFetch(u_input, ivec2(x_out * u_in_c_groups + i, fy), 0);
|
|
1548
|
+
|
|
1549
|
+
int base = i * 4;
|
|
1550
|
+
mat4 w = mat4(
|
|
1551
|
+
texelFetch(u_weights, ivec2(base, o_group), 0),
|
|
1552
|
+
texelFetch(u_weights, ivec2(base + 1, o_group), 0),
|
|
1553
|
+
texelFetch(u_weights, ivec2(base + 2, o_group), 0),
|
|
1554
|
+
texelFetch(u_weights, ivec2(base + 3, o_group), 0)
|
|
1555
|
+
);
|
|
1556
|
+
result += w * in_val;
|
|
1557
|
+
}
|
|
1558
|
+
|
|
1559
|
+
fragColor = result + texelFetch(u_skip, ivec2(fx, fy), 0);
|
|
1560
|
+
}
|
|
1561
|
+
`;var ee=class extends c{inputs;weights;output;dispatch;shader=lt;constructor(e,t,r,o,i){super(e);let s=t.c/4,n=i.outChannels/4,u=f$1(o.weights),l=f$1(o.bias),p=this.makeTexture(u,s*4,n),h=this.makeTexture(l,n,1),m=t.w*n,x=this.makeTexture(null,m,t.h);this.output={h:t.h,w:t.w,c:i.outChannels,texture:x,texW:m,texH:t.h},this.inputs=[t,r],this.weights=[],this.samplers=[{name:"u_input",texture:t.texture},{name:"u_skip",texture:r.texture},{name:"u_weights",texture:p},{name:"u_bias",texture:h}],this.uniformInts={u_in_c_groups:s,u_out_c_groups:n},this.defaultSetup(),this.dispatch=[m,t.h];}};var ct=`#version 300 es
|
|
1562
|
+
// concat_conv2d: fuses [concat(a, b) \u2192 conv 3\xD73 (pad 1) \u2192 relu6] into one pass.
|
|
1563
|
+
// Both inputs already at output resolution. Weight cols [0, a_groups) read a,
|
|
1564
|
+
// [a_groups, I) read b. Weight texture layout matches conv2d.glsl
|
|
1565
|
+
// ((in_groups*4, 9*out_groups), in_groups = a_groups + b_groups).
|
|
1566
|
+
|
|
1567
|
+
precision highp float;
|
|
1568
|
+
precision highp int;
|
|
1569
|
+
|
|
1570
|
+
uniform sampler2D u_a;
|
|
1571
|
+
uniform sampler2D u_b;
|
|
1572
|
+
uniform sampler2D u_weights;
|
|
1573
|
+
uniform sampler2D u_bias;
|
|
1574
|
+
|
|
1575
|
+
uniform int u_w;
|
|
1576
|
+
uniform int u_h;
|
|
1577
|
+
uniform int u_a_groups;
|
|
1578
|
+
uniform int u_b_groups;
|
|
1579
|
+
uniform int u_out_c_groups;
|
|
1580
|
+
|
|
1581
|
+
out vec4 fragColor;
|
|
1582
|
+
|
|
1583
|
+
void main() {
|
|
1584
|
+
int fx = int(gl_FragCoord.x);
|
|
1585
|
+
int fy = int(gl_FragCoord.y);
|
|
1586
|
+
int x_out = fx / u_out_c_groups;
|
|
1587
|
+
int o_group = fx - x_out * u_out_c_groups;
|
|
1588
|
+
int A = u_a_groups;
|
|
1589
|
+
int B = u_b_groups;
|
|
1590
|
+
int I = A + B;
|
|
1591
|
+
|
|
1592
|
+
vec4 result = texelFetch(u_bias, ivec2(o_group, 0), 0);
|
|
1593
|
+
|
|
1594
|
+
for (int ky = 0; ky < 3; ky++) {
|
|
1595
|
+
for (int kx = 0; kx < 3; kx++) {
|
|
1596
|
+
int in_y = fy + ky - 1;
|
|
1597
|
+
int in_x = x_out + kx - 1;
|
|
1598
|
+
if (in_x < 0 || in_y < 0 || in_x >= u_w || in_y >= u_h) continue;
|
|
1599
|
+
|
|
1600
|
+
int z = ky * 3 + kx;
|
|
1601
|
+
int w_row = z * u_out_c_groups + o_group;
|
|
1602
|
+
|
|
1603
|
+
for (int i = 0; i < I; i++) {
|
|
1604
|
+
vec4 in_val = (i < A)
|
|
1605
|
+
? texelFetch(u_a, ivec2(in_x * A + i, in_y), 0)
|
|
1606
|
+
: texelFetch(u_b, ivec2(in_x * B + (i - A), in_y), 0);
|
|
1607
|
+
|
|
1608
|
+
int base = i * 4;
|
|
1609
|
+
mat4 w = mat4(
|
|
1610
|
+
texelFetch(u_weights, ivec2(base, w_row), 0),
|
|
1611
|
+
texelFetch(u_weights, ivec2(base + 1, w_row), 0),
|
|
1612
|
+
texelFetch(u_weights, ivec2(base + 2, w_row), 0),
|
|
1613
|
+
texelFetch(u_weights, ivec2(base + 3, w_row), 0)
|
|
1614
|
+
);
|
|
1615
|
+
result += w * in_val;
|
|
1616
|
+
}
|
|
1617
|
+
}
|
|
1618
|
+
}
|
|
1619
|
+
|
|
1620
|
+
fragColor = clamp(result, 0.0, 6.0);
|
|
1621
|
+
}
|
|
1622
|
+
`;var te=class extends c{inputs;weights;output;dispatch;shader=ct;constructor(e,t,r,o,i){super(e);let s=t.c/4,n=r.c/4,u=s+n,l=i.outChannels/4,p=f$1(o.weights),h=f$1(o.bias),m=this.makeTexture(p,u*4,9*l),x=this.makeTexture(h,l,1),_=t.w*l,g=this.makeTexture(null,_,t.h);this.output={h:t.h,w:t.w,c:i.outChannels,texture:g,texW:_,texH:t.h},this.inputs=[t,r],this.weights=[],this.samplers=[{name:"u_a",texture:t.texture},{name:"u_b",texture:r.texture},{name:"u_weights",texture:m},{name:"u_bias",texture:x}],this.uniformInts={u_w:t.w,u_h:t.h,u_a_groups:s,u_b_groups:n,u_out_c_groups:l},this.defaultSetup(),this.dispatch=[_,t.h];}};var pt=`#version 300 es
|
|
1623
|
+
// gates_fused: ConvGRU z + r gates, fused. Production config (c_up=2,
|
|
1624
|
+
// recurrent=1). u_in (.x=a, .y=b), h_prev (.x). weights 9 vec4 =
|
|
1625
|
+
// (z_w_b, z_w_h, r_w_b, r_w_h) in a (9,1) texture. bias .xy. output (z, r, 0, 0).
|
|
1626
|
+
|
|
1627
|
+
precision highp float;
|
|
1628
|
+
precision highp int;
|
|
1629
|
+
|
|
1630
|
+
uniform sampler2D u_u_in; // (W, H)
|
|
1631
|
+
uniform sampler2D u_h_prev; // (W, H)
|
|
1632
|
+
uniform sampler2D u_weights; // (9, 1)
|
|
1633
|
+
uniform sampler2D u_bias; // (1, 1)
|
|
1634
|
+
uniform int u_w;
|
|
1635
|
+
uniform int u_h;
|
|
1636
|
+
|
|
1637
|
+
out vec4 fragColor;
|
|
1638
|
+
|
|
1639
|
+
void main() {
|
|
1640
|
+
int x = int(gl_FragCoord.x);
|
|
1641
|
+
int y = int(gl_FragCoord.y);
|
|
1642
|
+
|
|
1643
|
+
vec2 b = texelFetch(u_bias, ivec2(0, 0), 0).xy;
|
|
1644
|
+
float z_pre = b.x;
|
|
1645
|
+
float r_pre = b.y;
|
|
1646
|
+
|
|
1647
|
+
for (int ky = 0; ky < 3; ky++) {
|
|
1648
|
+
for (int kx = 0; kx < 3; kx++) {
|
|
1649
|
+
int iy = y + ky - 1;
|
|
1650
|
+
int ix = x + kx - 1;
|
|
1651
|
+
if (iy < 0 || ix < 0 || iy >= u_h || ix >= u_w) continue;
|
|
1652
|
+
int kpos = ky * 3 + kx;
|
|
1653
|
+
float b_n = texelFetch(u_u_in, ivec2(ix, iy), 0).y;
|
|
1654
|
+
float h_n = texelFetch(u_h_prev, ivec2(ix, iy), 0).z;
|
|
1655
|
+
vec4 w = texelFetch(u_weights, ivec2(kpos, 0), 0);
|
|
1656
|
+
z_pre += w.x * b_n + w.y * h_n;
|
|
1657
|
+
r_pre += w.z * b_n + w.w * h_n;
|
|
1658
|
+
}
|
|
1659
|
+
}
|
|
1660
|
+
|
|
1661
|
+
float z = 1.0 / (1.0 + exp(-z_pre));
|
|
1662
|
+
float r = 1.0 / (1.0 + exp(-r_pre));
|
|
1663
|
+
fragColor = vec4(z, r, 0.0, 0.0);
|
|
1664
|
+
}
|
|
1665
|
+
`;var oe=class extends c{inputs;weights;output;dispatch;shader=pt;constructor(e,t,r,o){super(e);let i=this.makeTexture(f$1(o.weights),9,1),s=this.makeTexture(g(o.bias),1,1),n=t.w,u=this.makeTexture(null,n,t.h);this.output={h:t.h,w:t.w,c:4,texture:u,texW:n,texH:t.h},this.inputs=[t,r],this.weights=[],this.samplers=[{name:"u_u_in",texture:t.texture},{name:"u_h_prev",texture:r.texture},{name:"u_weights",texture:i},{name:"u_bias",texture:s}],this.uniformInts={u_w:t.w,u_h:t.h},this.defaultSetup(),this.dispatch=[n,t.h];}};var ht=`#version 300 es
|
|
1666
|
+
// cand_update_fused: ConvGRU candidate + state update + output, fused.
|
|
1667
|
+
// Production config (c_up=2, recurrent=1). u_in (.x=a, .y=b), h_prev (.x),
|
|
1668
|
+
// gates_out (.x=z, .y=r). weights 9 vec4 (.xy = b_w, rh_w) in a (9,1) texture.
|
|
1669
|
+
// bias .x, gamma .x. output (a, b_out, 0, 0).
|
|
1670
|
+
|
|
1671
|
+
precision highp float;
|
|
1672
|
+
precision highp int;
|
|
1673
|
+
|
|
1674
|
+
uniform sampler2D u_u_in; // (W, H)
|
|
1675
|
+
uniform sampler2D u_h_prev; // (W, H)
|
|
1676
|
+
uniform sampler2D u_gates_out; // (W, H)
|
|
1677
|
+
uniform sampler2D u_weights; // (9, 1)
|
|
1678
|
+
uniform sampler2D u_bias; // (1, 1)
|
|
1679
|
+
uniform sampler2D u_gamma; // (1, 1)
|
|
1680
|
+
uniform int u_w;
|
|
1681
|
+
uniform int u_h;
|
|
1682
|
+
|
|
1683
|
+
out vec4 fragColor;
|
|
1684
|
+
|
|
1685
|
+
void main() {
|
|
1686
|
+
int x = int(gl_FragCoord.x);
|
|
1687
|
+
int y = int(gl_FragCoord.y);
|
|
1688
|
+
|
|
1689
|
+
float cand_pre = texelFetch(u_bias, ivec2(0, 0), 0).x;
|
|
1690
|
+
for (int ky = 0; ky < 3; ky++) {
|
|
1691
|
+
for (int kx = 0; kx < 3; kx++) {
|
|
1692
|
+
int iy = y + ky - 1;
|
|
1693
|
+
int ix = x + kx - 1;
|
|
1694
|
+
if (iy < 0 || ix < 0 || iy >= u_h || ix >= u_w) continue;
|
|
1695
|
+
int kpos = ky * 3 + kx;
|
|
1696
|
+
float b_n = texelFetch(u_u_in, ivec2(ix, iy), 0).y;
|
|
1697
|
+
float h_n = texelFetch(u_h_prev, ivec2(ix, iy), 0).z;
|
|
1698
|
+
float r_n = texelFetch(u_gates_out, ivec2(ix, iy), 0).y;
|
|
1699
|
+
vec4 w = texelFetch(u_weights, ivec2(kpos, 0), 0);
|
|
1700
|
+
cand_pre += w.x * b_n + w.y * (r_n * h_n);
|
|
1701
|
+
}
|
|
1702
|
+
}
|
|
1703
|
+
|
|
1704
|
+
float h_til = tanh(cand_pre);
|
|
1705
|
+
vec4 u_cur = texelFetch(u_u_in, ivec2(x, y), 0);
|
|
1706
|
+
float z_cur = texelFetch(u_gates_out, ivec2(x, y), 0).x;
|
|
1707
|
+
float h_prev_cur = texelFetch(u_h_prev, ivec2(x, y), 0).z;
|
|
1708
|
+
float h_new = (1.0 - z_cur) * h_prev_cur + z_cur * h_til;
|
|
1709
|
+
float gamma = texelFetch(u_gamma, ivec2(0, 0), 0).x;
|
|
1710
|
+
float b_out = u_cur.y + gamma * h_new;
|
|
1711
|
+
fragColor = vec4(u_cur.x, b_out, h_new, 0.0);
|
|
1712
|
+
}
|
|
1713
|
+
`;var re=class extends c{inputs;weights;output;dispatch;shader=ht;constructor(e,t,r,o,i,s){super(e);let n=this.makeTexture(f$1(i.weights),9,1),u=this.makeTexture(g(i.bias),1,1),l=this.makeTexture(g(s),1,1),p=t.w,h=this.makeTexture(null,p,t.h);this.output={h:t.h,w:t.w,c:4,texture:h,texW:p,texH:t.h},this.inputs=[t,r,o],this.weights=[],this.samplers=[{name:"u_u_in",texture:t.texture},{name:"u_h_prev",texture:r.texture},{name:"u_gates_out",texture:o.texture},{name:"u_weights",texture:n},{name:"u_bias",texture:u},{name:"u_gamma",texture:l}],this.uniformInts={u_w:t.w,u_h:t.h},this.defaultSetup(),this.dispatch=[p,t.h];}};var mt=`#version 300 es
|
|
1714
|
+
// conv_expand: bespoke N\u21922 conv 3\xD73 (pad 1) + relu (wrapper expand_feat).
|
|
1715
|
+
// Input N ch (in_groups vec4); output 2ch in .xy (.zw = 0). Weights: 9 *
|
|
1716
|
+
// in_groups mat4x2 (8 floats each, col-major c0r0,c0r1,...,c3r0,c3r1) in a
|
|
1717
|
+
// 1-row texture \u2014 bounded small (feat_ch \u2264 32).
|
|
1718
|
+
|
|
1719
|
+
precision highp float;
|
|
1720
|
+
precision highp int;
|
|
1721
|
+
|
|
1722
|
+
uniform sampler2D u_input; // (W*in_groups, H)
|
|
1723
|
+
uniform sampler2D u_weights; // (ceil(9*in_groups*8/4), 1)
|
|
1724
|
+
uniform sampler2D u_bias; // (1, 1) \u2014 .xy
|
|
1725
|
+
uniform int u_w;
|
|
1726
|
+
uniform int u_h;
|
|
1727
|
+
uniform int u_in_groups;
|
|
1728
|
+
|
|
1729
|
+
out vec4 fragColor;
|
|
1730
|
+
|
|
1731
|
+
float wf(int i) { return texelFetch(u_weights, ivec2(i / 4, 0), 0)[i & 3]; }
|
|
1732
|
+
|
|
1733
|
+
void main() {
|
|
1734
|
+
int x = int(gl_FragCoord.x);
|
|
1735
|
+
int y = int(gl_FragCoord.y);
|
|
1736
|
+
|
|
1737
|
+
vec2 result = texelFetch(u_bias, ivec2(0, 0), 0).xy;
|
|
1738
|
+
|
|
1739
|
+
for (int ky = 0; ky < 3; ky++) {
|
|
1740
|
+
for (int kx = 0; kx < 3; kx++) {
|
|
1741
|
+
int iy = y + ky - 1;
|
|
1742
|
+
int ix = x + kx - 1;
|
|
1743
|
+
if (iy < 0 || ix < 0 || iy >= u_h || ix >= u_w) continue;
|
|
1744
|
+
int kpos = ky * 3 + kx;
|
|
1745
|
+
for (int ig = 0; ig < u_in_groups; ig++) {
|
|
1746
|
+
vec4 v = texelFetch(u_input, ivec2(ix * u_in_groups + ig, iy), 0);
|
|
1747
|
+
int base = (kpos * u_in_groups + ig) * 8; // mat4x2 = 8 floats
|
|
1748
|
+
result.x += wf(base + 0) * v.x + wf(base + 2) * v.y + wf(base + 4) * v.z + wf(base + 6) * v.w;
|
|
1749
|
+
result.y += wf(base + 1) * v.x + wf(base + 3) * v.y + wf(base + 5) * v.z + wf(base + 7) * v.w;
|
|
1750
|
+
}
|
|
1751
|
+
}
|
|
1752
|
+
}
|
|
1753
|
+
|
|
1754
|
+
fragColor = vec4(max(result, vec2(0.0)), 0.0, 0.0); // expand_feat is F.relu
|
|
1755
|
+
}
|
|
1756
|
+
`;var ie=class extends c{inputs;weights;output;dispatch;shader=mt;constructor(e,t,r){super(e);let o=t.c/4,i=this.makeTexture(f$1(r.weights),18*o,1),s=this.makeTexture(g(r.bias),1,1),n=t.w,u=this.makeTexture(null,n,t.h);this.output={h:t.h,w:t.w,c:4,texture:u,texW:n,texH:t.h},this.inputs=[t],this.weights=[],this.samplers=[{name:"u_input",texture:t.texture},{name:"u_weights",texture:i},{name:"u_bias",texture:s}],this.uniformInts={u_w:t.w,u_h:t.h,u_in_groups:o},this.defaultSetup(),this.dispatch=[n,t.h];}};var dt=`#version 300 es
|
|
1757
|
+
// cat_conv_6to2: fused concat(u[2], d[4]) \u2192 6\u21922 conv 3\xD73 (pad 1) + relu
|
|
1758
|
+
// (E up1_combine). Channel order v3a=(u.x,u.y,d.x), v3b=d.yzw. weights = 9*2
|
|
1759
|
+
// mat3x2 (6 floats each, col-major) in a 1-row (27-texel) texture.
|
|
1760
|
+
|
|
1761
|
+
precision highp float;
|
|
1762
|
+
precision highp int;
|
|
1763
|
+
|
|
1764
|
+
uniform sampler2D u_u_in; // (W, H) \u2014 .xy
|
|
1765
|
+
uniform sampler2D u_d_in; // (W, H) \u2014 full vec4
|
|
1766
|
+
uniform sampler2D u_weights; // (27, 1)
|
|
1767
|
+
uniform sampler2D u_bias; // (1, 1) \u2014 .xy
|
|
1768
|
+
uniform int u_w;
|
|
1769
|
+
uniform int u_h;
|
|
1770
|
+
|
|
1771
|
+
out vec4 fragColor;
|
|
1772
|
+
|
|
1773
|
+
float wf(int i) { return texelFetch(u_weights, ivec2(i / 4, 0), 0)[i & 3]; }
|
|
1774
|
+
|
|
1775
|
+
void main() {
|
|
1776
|
+
int x = int(gl_FragCoord.x);
|
|
1777
|
+
int y = int(gl_FragCoord.y);
|
|
1778
|
+
|
|
1779
|
+
vec2 result = texelFetch(u_bias, ivec2(0, 0), 0).xy;
|
|
1780
|
+
for (int ky = 0; ky < 3; ky++) {
|
|
1781
|
+
for (int kx = 0; kx < 3; kx++) {
|
|
1782
|
+
int iy = y + ky - 1;
|
|
1783
|
+
int ix = x + kx - 1;
|
|
1784
|
+
if (iy < 0 || ix < 0 || iy >= u_h || ix >= u_w) continue;
|
|
1785
|
+
int kpos = ky * 3 + kx;
|
|
1786
|
+
vec4 u = texelFetch(u_u_in, ivec2(ix, iy), 0);
|
|
1787
|
+
vec4 d = texelFetch(u_d_in, ivec2(ix, iy), 0);
|
|
1788
|
+
vec3 v3a = vec3(u.x, u.y, d.x);
|
|
1789
|
+
vec3 v3b = d.yzw;
|
|
1790
|
+
for (int ig = 0; ig < 2; ig++) {
|
|
1791
|
+
int base = (kpos * 2 + ig) * 6;
|
|
1792
|
+
vec3 v3 = (ig == 0) ? v3a : v3b;
|
|
1793
|
+
for (int col = 0; col < 3; col++) {
|
|
1794
|
+
result.x += wf(base + col * 2 + 0) * v3[col];
|
|
1795
|
+
result.y += wf(base + col * 2 + 1) * v3[col];
|
|
1796
|
+
}
|
|
1797
|
+
}
|
|
1798
|
+
}
|
|
1799
|
+
}
|
|
1800
|
+
|
|
1801
|
+
fragColor = vec4(max(result, vec2(0.0)), 0.0, 0.0); // up1_combine is F.relu
|
|
1802
|
+
}
|
|
1803
|
+
`;var ne=class extends c{inputs;weights;output;dispatch;shader=dt;constructor(e,t,r,o){super(e);let i=this.makeTexture(f$1(o.weights),27,1),s=this.makeTexture(g(o.bias),1,1),n=t.w,u=this.makeTexture(null,n,t.h);this.output={h:t.h,w:t.w,c:4,texture:u,texW:n,texH:t.h},this.inputs=[t,r],this.weights=[],this.samplers=[{name:"u_u_in",texture:t.texture},{name:"u_d_in",texture:r.texture},{name:"u_weights",texture:i},{name:"u_bias",texture:s}],this.uniformInts={u_w:t.w,u_h:t.h},this.defaultSetup(),this.dispatch=[n,t.h];}};var _t=`#version 300 es
|
|
1804
|
+
// down_adapter: stride-N 3\xD73 conv (mat4x4, 4\u21924) + relu, then 1\xD71 adapter
|
|
1805
|
+
// (4\u21923, last row 0). down_w = 9 mat4x4 (1-row, 36 texels); adapt_w = 1 mat4x4
|
|
1806
|
+
// (4 texels). Output 3ch in .xyz (.w=0). Symmetric pad. Weight packing matches
|
|
1807
|
+
// conv2d (col-major mat4x4 via the flat accessor).
|
|
1808
|
+
|
|
1809
|
+
precision highp float;
|
|
1810
|
+
precision highp int;
|
|
1811
|
+
|
|
1812
|
+
uniform sampler2D u_input; // (in_W, in_H) \u2014 in_c padded to 1 vec4
|
|
1813
|
+
uniform sampler2D u_down_w; // (36, 1)
|
|
1814
|
+
uniform sampler2D u_down_b; // (1, 1)
|
|
1815
|
+
uniform sampler2D u_adapt_w; // (4, 1)
|
|
1816
|
+
uniform sampler2D u_adapt_b; // (1, 1) \u2014 .xyz
|
|
1817
|
+
uniform int u_in_w;
|
|
1818
|
+
uniform int u_in_h;
|
|
1819
|
+
uniform int u_stride;
|
|
1820
|
+
uniform int u_pad;
|
|
1821
|
+
|
|
1822
|
+
out vec4 fragColor;
|
|
1823
|
+
|
|
1824
|
+
float dwf(int i) { return texelFetch(u_down_w, ivec2(i / 4, 0), 0)[i & 3]; }
|
|
1825
|
+
float awf(int i) { return texelFetch(u_adapt_w, ivec2(i / 4, 0), 0)[i & 3]; }
|
|
1826
|
+
|
|
1827
|
+
void main() {
|
|
1828
|
+
int x = int(gl_FragCoord.x);
|
|
1829
|
+
int y = int(gl_FragCoord.y);
|
|
1830
|
+
|
|
1831
|
+
vec4 d = texelFetch(u_down_b, ivec2(0, 0), 0);
|
|
1832
|
+
for (int ky = 0; ky < 3; ky++) {
|
|
1833
|
+
for (int kx = 0; kx < 3; kx++) {
|
|
1834
|
+
int iy = y * u_stride + ky - u_pad;
|
|
1835
|
+
int ix = x * u_stride + kx - u_pad;
|
|
1836
|
+
if (iy < 0 || ix < 0 || iy >= u_in_h || ix >= u_in_w) continue;
|
|
1837
|
+
int kpos = ky * 3 + kx;
|
|
1838
|
+
vec4 v = texelFetch(u_input, ivec2(ix, iy), 0);
|
|
1839
|
+
int m = kpos * 16;
|
|
1840
|
+
d.x += dwf(m + 0) * v.x + dwf(m + 4) * v.y + dwf(m + 8) * v.z + dwf(m + 12) * v.w;
|
|
1841
|
+
d.y += dwf(m + 1) * v.x + dwf(m + 5) * v.y + dwf(m + 9) * v.z + dwf(m + 13) * v.w;
|
|
1842
|
+
d.z += dwf(m + 2) * v.x + dwf(m + 6) * v.y + dwf(m + 10) * v.z + dwf(m + 14) * v.w;
|
|
1843
|
+
d.w += dwf(m + 3) * v.x + dwf(m + 7) * v.y + dwf(m + 11) * v.z + dwf(m + 15) * v.w;
|
|
1844
|
+
}
|
|
1845
|
+
}
|
|
1846
|
+
d = max(d, vec4(0.0)); // relu
|
|
1847
|
+
|
|
1848
|
+
vec4 ab = texelFetch(u_adapt_b, ivec2(0, 0), 0);
|
|
1849
|
+
vec4 a;
|
|
1850
|
+
a.x = awf(0) * d.x + awf(4) * d.y + awf(8) * d.z + awf(12) * d.w + ab.x;
|
|
1851
|
+
a.y = awf(1) * d.x + awf(5) * d.y + awf(9) * d.z + awf(13) * d.w + ab.y;
|
|
1852
|
+
a.z = awf(2) * d.x + awf(6) * d.y + awf(10) * d.z + awf(14) * d.w + ab.z;
|
|
1853
|
+
fragColor = vec4(a.xyz, 0.0);
|
|
1854
|
+
}
|
|
1855
|
+
`;var se=class extends c{inputs;weights;output;dispatch;shader=_t;constructor(e$1,t,r,o,i){super(e$1);let s=c$1(t.h,3,i.stride,1),n=c$1(t.w,3,i.stride,1),u=e(1,t.h,s,3,i.stride),l=this.makeTexture(f$1(r.weights),36,1),p=this.makeTexture(g(r.bias),1,1),h=this.makeTexture(f$1(o.weights),4,1),m=this.makeTexture(g(o.bias),1,1),x=n,_=this.makeTexture(null,x,s);this.output={h:s,w:n,c:4,texture:_,texW:x,texH:s},this.inputs=[t],this.weights=[],this.samplers=[{name:"u_input",texture:t.texture},{name:"u_down_w",texture:l},{name:"u_down_b",texture:p},{name:"u_adapt_w",texture:h},{name:"u_adapt_b",texture:m}],this.uniformInts={u_in_w:t.w,u_in_h:t.h,u_stride:i.stride,u_pad:u},this.defaultSetup(),this.dispatch=[x,s];}};var ft=`#version 300 es
|
|
1856
|
+
// up_final: cat(u[2], rgb[3]) \u2192 conv 3\xD73 5\u21921 \u2192 sigmoid (A/B alpha head).
|
|
1857
|
+
// weights 18 vec4 (1-row): [kpos]=(w0,w1,0,0) for u, [9+kpos]=(w2,w3,w4,0) rgb.
|
|
1858
|
+
|
|
1859
|
+
precision highp float;
|
|
1860
|
+
precision highp int;
|
|
1861
|
+
|
|
1862
|
+
uniform sampler2D u_u_gru; // (W, H) \u2014 .xy
|
|
1863
|
+
uniform sampler2D u_rgb; // (W, H) \u2014 .xyz
|
|
1864
|
+
uniform sampler2D u_weights; // (18, 1)
|
|
1865
|
+
uniform sampler2D u_bias; // (1, 1) \u2014 .x
|
|
1866
|
+
uniform int u_w;
|
|
1867
|
+
uniform int u_h;
|
|
1868
|
+
|
|
1869
|
+
out vec4 fragColor;
|
|
1870
|
+
|
|
1871
|
+
void main() {
|
|
1872
|
+
int x = int(gl_FragCoord.x);
|
|
1873
|
+
int y = int(gl_FragCoord.y);
|
|
1874
|
+
|
|
1875
|
+
float acc = texelFetch(u_bias, ivec2(0, 0), 0).x;
|
|
1876
|
+
for (int ky = 0; ky < 3; ky++) {
|
|
1877
|
+
for (int kx = 0; kx < 3; kx++) {
|
|
1878
|
+
int iy = y + ky - 1;
|
|
1879
|
+
int ix = x + kx - 1;
|
|
1880
|
+
if (iy < 0 || ix < 0 || iy >= u_h || ix >= u_w) continue;
|
|
1881
|
+
int kpos = ky * 3 + kx;
|
|
1882
|
+
vec4 u = texelFetch(u_u_gru, ivec2(ix, iy), 0);
|
|
1883
|
+
vec4 r = texelFetch(u_rgb, ivec2(ix, iy), 0);
|
|
1884
|
+
vec4 wu = texelFetch(u_weights, ivec2(kpos, 0), 0);
|
|
1885
|
+
vec4 wr = texelFetch(u_weights, ivec2(9 + kpos, 0), 0);
|
|
1886
|
+
acc += dot(wu.xy, u.xy);
|
|
1887
|
+
acc += dot(wr.xyz, r.xyz);
|
|
1888
|
+
}
|
|
1889
|
+
}
|
|
1890
|
+
|
|
1891
|
+
fragColor = vec4(1.0 / (1.0 + exp(-acc)), 0.0, 0.0, 0.0);
|
|
1892
|
+
}
|
|
1893
|
+
`;var ae=class extends c{inputs;weights;output;dispatch;shader=ft;constructor(e,t,r,o){super(e);let i=this.makeTexture(f$1(o.weights),18,1),s=this.makeTexture(g(o.bias),1,1),n=t.w,u=this.makeTexture(null,n,t.h);this.output={h:t.h,w:t.w,c:4,texture:u,texW:n,texH:t.h},this.inputs=[t,r],this.weights=[],this.samplers=[{name:"u_u_gru",texture:t.texture},{name:"u_rgb",texture:r.texture},{name:"u_weights",texture:i},{name:"u_bias",texture:s}],this.uniformInts={u_w:t.w,u_h:t.h},this.defaultSetup(),this.dispatch=[n,t.h];}};var xt=`#version 300 es
|
|
1894
|
+
// up_final_skip (C/D alpha head): cat(u[2], d_full[4], rgb[3]) \u2192 conv 9\u21921 \u2192
|
|
1895
|
+
// sigmoid. Weights = 27 vec4 (3 per kpos): [kpos*3+0]=(w0,w1,0,0) u;
|
|
1896
|
+
// [kpos*3+1]=(w2..w5) d_full; [kpos*3+2]=(w6,w7,w8,0) rgb.
|
|
1897
|
+
|
|
1898
|
+
precision highp float;
|
|
1899
|
+
precision highp int;
|
|
1900
|
+
|
|
1901
|
+
uniform sampler2D u_u_gru; // (W, H) \u2014 .xy
|
|
1902
|
+
uniform sampler2D u_d_full; // (W, H) \u2014 full vec4
|
|
1903
|
+
uniform sampler2D u_rgb; // (W, H) \u2014 .xyz
|
|
1904
|
+
uniform sampler2D u_weights; // (27, 1)
|
|
1905
|
+
uniform sampler2D u_bias; // (1, 1) \u2014 .x
|
|
1906
|
+
uniform int u_w;
|
|
1907
|
+
uniform int u_h;
|
|
1908
|
+
|
|
1909
|
+
out vec4 fragColor;
|
|
1910
|
+
|
|
1911
|
+
float wf(int i) { return texelFetch(u_weights, ivec2(i / 4, 0), 0)[i & 3]; }
|
|
1912
|
+
|
|
1913
|
+
void main() {
|
|
1914
|
+
int x = int(gl_FragCoord.x);
|
|
1915
|
+
int y = int(gl_FragCoord.y);
|
|
1916
|
+
|
|
1917
|
+
float acc = texelFetch(u_bias, ivec2(0, 0), 0).x;
|
|
1918
|
+
for (int ky = 0; ky < 3; ky++) {
|
|
1919
|
+
for (int kx = 0; kx < 3; kx++) {
|
|
1920
|
+
int iy = y + ky - 1;
|
|
1921
|
+
int ix = x + kx - 1;
|
|
1922
|
+
if (iy < 0 || ix < 0 || iy >= u_h || ix >= u_w) continue;
|
|
1923
|
+
int kpos = ky * 3 + kx;
|
|
1924
|
+
vec4 u = texelFetch(u_u_gru, ivec2(ix, iy), 0);
|
|
1925
|
+
vec4 d = texelFetch(u_d_full, ivec2(ix, iy), 0);
|
|
1926
|
+
vec4 r = texelFetch(u_rgb, ivec2(ix, iy), 0);
|
|
1927
|
+
int b0 = (kpos * 3 + 0) * 4, b1 = (kpos * 3 + 1) * 4, b2 = (kpos * 3 + 2) * 4;
|
|
1928
|
+
acc += wf(b0 + 0) * u.x + wf(b0 + 1) * u.y;
|
|
1929
|
+
acc += wf(b1 + 0) * d.x + wf(b1 + 1) * d.y + wf(b1 + 2) * d.z + wf(b1 + 3) * d.w;
|
|
1930
|
+
acc += wf(b2 + 0) * r.x + wf(b2 + 1) * r.y + wf(b2 + 2) * r.z;
|
|
1931
|
+
}
|
|
1932
|
+
}
|
|
1933
|
+
|
|
1934
|
+
fragColor = vec4(1.0 / (1.0 + exp(-acc)), 0.0, 0.0, 0.0);
|
|
1935
|
+
}
|
|
1936
|
+
`;var ue=class extends c{inputs;weights;output;dispatch;shader=xt;constructor(e,t,r,o,i){super(e);let s=this.makeTexture(f$1(i.weights),27,1),n=this.makeTexture(g(i.bias),1,1),u=t.w,l=this.makeTexture(null,u,t.h);this.output={h:t.h,w:t.w,c:4,texture:l,texW:u,texH:t.h},this.inputs=[t,r,o],this.weights=[],this.samplers=[{name:"u_u_gru",texture:t.texture},{name:"u_d_full",texture:r.texture},{name:"u_rgb",texture:o.texture},{name:"u_weights",texture:s},{name:"u_bias",texture:n}],this.uniformInts={u_w:t.w,u_h:t.h},this.defaultSetup(),this.dispatch=[u,t.h];}};var gt=`#version 300 es
|
|
1937
|
+
// Composite an RGBA image over a solid background color, gated by a
|
|
1938
|
+
// 1-channel alpha mask. Output: premultiplied RGBA.
|
|
1939
|
+
//
|
|
1940
|
+
// Assumes image and alpha textures are the same h\xD7w and that the canvas
|
|
1941
|
+
// (viewport) matches that resolution \u2014 no resampling here. The upscaler op
|
|
1942
|
+
// (separate) handles aligning alpha to the image resolution upstream.
|
|
1943
|
+
|
|
1944
|
+
precision highp float;
|
|
1945
|
+
|
|
1946
|
+
uniform sampler2D u_image; // image as NHWC vec4 (RGBA in vec4)
|
|
1947
|
+
uniform sampler2D u_alpha; // alpha as NHWC vec4 (value in .r)
|
|
1948
|
+
uniform vec3 u_bgColor; // straight-alpha background color, [0,1]
|
|
1949
|
+
|
|
1950
|
+
out vec4 fragColor;
|
|
1951
|
+
|
|
1952
|
+
void main() {
|
|
1953
|
+
// WebGL gl_FragCoord origin is bottom-left, but tensor textures are
|
|
1954
|
+
// stored top-down (matches NHWC + getImageData). Flip y when sampling so
|
|
1955
|
+
// the displayed image is upright. (WebGPU's @builtin(position) is already
|
|
1956
|
+
// top-down, so its compositor doesn't need this.)
|
|
1957
|
+
int H = textureSize(u_image, 0).y;
|
|
1958
|
+
ivec2 px = ivec2(int(gl_FragCoord.x), H - 1 - int(gl_FragCoord.y));
|
|
1959
|
+
vec3 fg = texelFetch(u_image, px, 0).rgb;
|
|
1960
|
+
float a = texelFetch(u_alpha, px, 0).r;
|
|
1961
|
+
|
|
1962
|
+
// Straight-alpha composite, then premultiply for the canvas's
|
|
1963
|
+
// premultiplied surface format.
|
|
1964
|
+
vec3 rgb = fg * a + u_bgColor * (1.0 - a);
|
|
1965
|
+
fragColor = vec4(rgb, 1.0);
|
|
1966
|
+
}
|
|
1967
|
+
`;var _o=`#version 300 es
|
|
1968
|
+
const vec2 VERTS[6] = vec2[6](
|
|
1969
|
+
vec2(-1.0,-1.0), vec2(1.0,-1.0), vec2(-1.0,1.0),
|
|
1970
|
+
vec2(-1.0,1.0), vec2(1.0,-1.0), vec2(1.0,1.0)
|
|
1971
|
+
);
|
|
1972
|
+
void main() { gl_Position = vec4(VERTS[gl_VertexID], 0.0, 1.0); }`,le=class{constructor(e,t,r,o){this.backend=e;if(t.h!==r.h||t.w!==r.w)throw new Error(`CompositeSolid: image (${t.h}\xD7${t.w}) and alpha (${r.h}\xD7${r.w}) must match. Run the upscaler first.`);let i=t,s=r;this.imageTex=i.texture,this.alphaTex=s.texture,this.bgColor=o;let n=e.gl,u=n.createShader(n.VERTEX_SHADER);n.shaderSource(u,_o),n.compileShader(u);let l=n.createShader(n.FRAGMENT_SHADER);if(n.shaderSource(l,gt),n.compileShader(l),!n.getShaderParameter(l,n.COMPILE_STATUS))throw new Error(`composite_solid GLSL compile error: ${n.getShaderInfoLog(l)}`);if(this.program=n.createProgram(),n.attachShader(this.program,u),n.attachShader(this.program,l),n.linkProgram(this.program),!n.getProgramParameter(this.program,n.LINK_STATUS))throw new Error(`composite_solid GLSL link error: ${n.getProgramInfoLog(this.program)}`)}backend;program;imageTex;alphaTex;bgColor;run(){let e=this.backend.gl;e.useProgram(this.program),e.activeTexture(e.TEXTURE0),e.bindTexture(e.TEXTURE_2D,this.imageTex),e.uniform1i(e.getUniformLocation(this.program,"u_image"),0),e.activeTexture(e.TEXTURE1),e.bindTexture(e.TEXTURE_2D,this.alphaTex),e.uniform1i(e.getUniformLocation(this.program,"u_alpha"),1),e.uniform3f(e.getUniformLocation(this.program,"u_bgColor"),this.bgColor[0],this.bgColor[1],this.bgColor[2]),this.backend.bindDisplayFramebuffer(),e.bindVertexArray(null),e.drawArrays(e.TRIANGLES,0,6);}};var bt=`#version 300 es
|
|
1973
|
+
// Same as composite_solid but bg is a texture (NHWC vec4 tensor) instead of
|
|
1974
|
+
// a uniform color. Caller invariants: image, alpha, bg all share h \xD7 w, and
|
|
1975
|
+
// canvas dimensions match.
|
|
1976
|
+
|
|
1977
|
+
precision highp float;
|
|
1978
|
+
precision highp int;
|
|
1979
|
+
|
|
1980
|
+
uniform sampler2D u_image;
|
|
1981
|
+
uniform sampler2D u_alpha;
|
|
1982
|
+
uniform sampler2D u_bg;
|
|
1983
|
+
|
|
1984
|
+
out vec4 fragColor;
|
|
1985
|
+
|
|
1986
|
+
void main() {
|
|
1987
|
+
// WebGL gl_FragCoord origin is bottom-left; tensor textures are top-down.
|
|
1988
|
+
int H = textureSize(u_image, 0).y;
|
|
1989
|
+
ivec2 px = ivec2(int(gl_FragCoord.x), H - 1 - int(gl_FragCoord.y));
|
|
1990
|
+
|
|
1991
|
+
vec3 fg = texelFetch(u_image, px, 0).rgb;
|
|
1992
|
+
float a = texelFetch(u_alpha, px, 0).r;
|
|
1993
|
+
vec3 bg = texelFetch(u_bg, px, 0).rgb;
|
|
1994
|
+
|
|
1995
|
+
vec3 rgb = fg * a + bg * (1.0 - a);
|
|
1996
|
+
fragColor = vec4(rgb, 1.0);
|
|
1997
|
+
}
|
|
1998
|
+
`;var xo=`#version 300 es
|
|
1999
|
+
const vec2 VERTS[6] = vec2[6](
|
|
2000
|
+
vec2(-1.0,-1.0), vec2(1.0,-1.0), vec2(-1.0,1.0),
|
|
2001
|
+
vec2(-1.0,1.0), vec2(1.0,-1.0), vec2(1.0,1.0)
|
|
2002
|
+
);
|
|
2003
|
+
void main() { gl_Position = vec4(VERTS[gl_VertexID], 0.0, 1.0); }`,ce=class{constructor(e,t,r,o){this.backend=e;if(t.h!==r.h||t.w!==r.w||t.h!==o.h||t.w!==o.w)throw new Error(`CompositeImage: image (${t.h}\xD7${t.w}), alpha (${r.h}\xD7${r.w}), and bg (${o.h}\xD7${o.w}) must all match. Run upscaler / resizer first.`);this.imageTex=t.texture,this.alphaTex=r.texture,this.bgTex=o.texture;let i=e.gl,s=i.createShader(i.VERTEX_SHADER);i.shaderSource(s,xo),i.compileShader(s);let n=i.createShader(i.FRAGMENT_SHADER);if(i.shaderSource(n,bt),i.compileShader(n),!i.getShaderParameter(n,i.COMPILE_STATUS))throw new Error(`composite_image GLSL compile error: ${i.getShaderInfoLog(n)}`);if(this.program=i.createProgram(),i.attachShader(this.program,s),i.attachShader(this.program,n),i.linkProgram(this.program),!i.getProgramParameter(this.program,i.LINK_STATUS))throw new Error(`composite_image GLSL link error: ${i.getProgramInfoLog(this.program)}`)}backend;program;imageTex;alphaTex;bgTex;run(){let e=this.backend.gl;e.useProgram(this.program),e.activeTexture(e.TEXTURE0),e.bindTexture(e.TEXTURE_2D,this.imageTex),e.uniform1i(e.getUniformLocation(this.program,"u_image"),0),e.activeTexture(e.TEXTURE1),e.bindTexture(e.TEXTURE_2D,this.alphaTex),e.uniform1i(e.getUniformLocation(this.program,"u_alpha"),1),e.activeTexture(e.TEXTURE2),e.bindTexture(e.TEXTURE_2D,this.bgTex),e.uniform1i(e.getUniformLocation(this.program,"u_bg"),2),this.backend.bindDisplayFramebuffer(),e.bindVertexArray(null),e.drawArrays(e.TRIANGLES,0,6);}};var vt=`#version 300 es
|
|
2004
|
+
// Like composite_image but bg is bilinearly sampled \u2014 bg is at a smaller
|
|
2005
|
+
// resolution than (image, alpha) at canvas h \xD7 w. Used by CompositorBlur to
|
|
2006
|
+
// skip the final full-res upsample in the blur pyramid.
|
|
2007
|
+
//
|
|
2008
|
+
// Tensor textures are top-down (origin at top-left of the source image),
|
|
2009
|
+
// while gl_FragCoord origin is bottom-left \u2014 flip y when computing px.
|
|
2010
|
+
|
|
2011
|
+
precision highp float;
|
|
2012
|
+
precision highp int;
|
|
2013
|
+
|
|
2014
|
+
uniform sampler2D u_image;
|
|
2015
|
+
uniform sampler2D u_alpha;
|
|
2016
|
+
uniform sampler2D u_bg;
|
|
2017
|
+
|
|
2018
|
+
uniform int u_out_w;
|
|
2019
|
+
uniform int u_out_h;
|
|
2020
|
+
uniform int u_bg_w;
|
|
2021
|
+
uniform int u_bg_h;
|
|
2022
|
+
|
|
2023
|
+
out vec4 fragColor;
|
|
2024
|
+
|
|
2025
|
+
void main() {
|
|
2026
|
+
int x = int(gl_FragCoord.x);
|
|
2027
|
+
int y = u_out_h - 1 - int(gl_FragCoord.y);
|
|
2028
|
+
|
|
2029
|
+
vec3 fg = texelFetch(u_image, ivec2(x, y), 0).rgb;
|
|
2030
|
+
float a = texelFetch(u_alpha, ivec2(x, y), 0).r;
|
|
2031
|
+
|
|
2032
|
+
// Bilinear sample bg at the corresponding location. align_corners=False.
|
|
2033
|
+
float src_x = (float(x) + 0.5) * (float(u_bg_w) / float(u_out_w)) - 0.5;
|
|
2034
|
+
float src_y = (float(y) + 0.5) * (float(u_bg_h) / float(u_out_h)) - 0.5;
|
|
2035
|
+
int x0 = clamp(int(floor(src_x)), 0, u_bg_w - 1);
|
|
2036
|
+
int x1 = clamp(int(floor(src_x)) + 1, 0, u_bg_w - 1);
|
|
2037
|
+
int y0 = clamp(int(floor(src_y)), 0, u_bg_h - 1);
|
|
2038
|
+
int y1 = clamp(int(floor(src_y)) + 1, 0, u_bg_h - 1);
|
|
2039
|
+
float wx = src_x - floor(src_x);
|
|
2040
|
+
float wy = src_y - floor(src_y);
|
|
2041
|
+
|
|
2042
|
+
vec3 tl = texelFetch(u_bg, ivec2(x0, y0), 0).rgb;
|
|
2043
|
+
vec3 tr = texelFetch(u_bg, ivec2(x1, y0), 0).rgb;
|
|
2044
|
+
vec3 bl = texelFetch(u_bg, ivec2(x0, y1), 0).rgb;
|
|
2045
|
+
vec3 br = texelFetch(u_bg, ivec2(x1, y1), 0).rgb;
|
|
2046
|
+
vec3 bg = (1.0 - wy) * ((1.0 - wx) * tl + wx * tr)
|
|
2047
|
+
+ wy * ((1.0 - wx) * bl + wx * br);
|
|
2048
|
+
|
|
2049
|
+
vec3 rgb = fg * a + bg * (1.0 - a);
|
|
2050
|
+
fragColor = vec4(rgb, 1.0);
|
|
2051
|
+
}
|
|
2052
|
+
`;var bo=`#version 300 es
|
|
2053
|
+
const vec2 VERTS[6] = vec2[6](
|
|
2054
|
+
vec2(-1.0,-1.0), vec2(1.0,-1.0), vec2(-1.0,1.0),
|
|
2055
|
+
vec2(-1.0,1.0), vec2(1.0,-1.0), vec2(1.0,1.0)
|
|
2056
|
+
);
|
|
2057
|
+
void main() { gl_Position = vec4(VERTS[gl_VertexID], 0.0, 1.0); }`,pe=class{constructor(e,t,r,o){this.backend=e;if(t.h!==r.h||t.w!==r.w)throw new Error(`CompositeImageBilinear: image (${t.h}\xD7${t.w}) and alpha (${r.h}\xD7${r.w}) must match.`);this.imageTex=t.texture,this.alphaTex=r.texture,this.bgTex=o.texture,this.outW=t.w,this.outH=t.h,this.bgW=o.w,this.bgH=o.h;let i=e.gl,s=i.createShader(i.VERTEX_SHADER);i.shaderSource(s,bo),i.compileShader(s);let n=i.createShader(i.FRAGMENT_SHADER);if(i.shaderSource(n,vt),i.compileShader(n),!i.getShaderParameter(n,i.COMPILE_STATUS))throw new Error(`composite_image_bilinear GLSL compile error: ${i.getShaderInfoLog(n)}`);if(this.program=i.createProgram(),i.attachShader(this.program,s),i.attachShader(this.program,n),i.linkProgram(this.program),!i.getProgramParameter(this.program,i.LINK_STATUS))throw new Error(`composite_image_bilinear GLSL link error: ${i.getProgramInfoLog(this.program)}`)}backend;program;imageTex;alphaTex;bgTex;outW;outH;bgW;bgH;run(){let e=this.backend.gl;e.useProgram(this.program),e.activeTexture(e.TEXTURE0),e.bindTexture(e.TEXTURE_2D,this.imageTex),e.uniform1i(e.getUniformLocation(this.program,"u_image"),0),e.activeTexture(e.TEXTURE1),e.bindTexture(e.TEXTURE_2D,this.alphaTex),e.uniform1i(e.getUniformLocation(this.program,"u_alpha"),1),e.activeTexture(e.TEXTURE2),e.bindTexture(e.TEXTURE_2D,this.bgTex),e.uniform1i(e.getUniformLocation(this.program,"u_bg"),2),e.uniform1i(e.getUniformLocation(this.program,"u_out_w"),this.outW),e.uniform1i(e.getUniformLocation(this.program,"u_out_h"),this.outH),e.uniform1i(e.getUniformLocation(this.program,"u_bg_w"),this.bgW),e.uniform1i(e.getUniformLocation(this.program,"u_bg_h"),this.bgH),this.backend.bindDisplayFramebuffer(),e.bindVertexArray(null),e.drawArrays(e.TRIANGLES,0,6);}};var vo=`#version 300 es
|
|
2058
|
+
const vec2 VERTS[6] = vec2[6](
|
|
2059
|
+
vec2(-1.0,-1.0), vec2(1.0,-1.0), vec2(-1.0,1.0),
|
|
2060
|
+
vec2(-1.0,1.0), vec2(1.0,-1.0), vec2(1.0,1.0)
|
|
2061
|
+
);
|
|
2062
|
+
void main() { gl_Position = vec4(VERTS[gl_VertexID], 0.0, 1.0); }`,he=class{constructor(e,t){this.backend=e;this.imageTex=t.texture;let r=e.gl,o=r.createShader(r.VERTEX_SHADER);r.shaderSource(o,vo),r.compileShader(o);let i=r.createShader(r.FRAGMENT_SHADER);if(r.shaderSource(i,I),r.compileShader(i),!r.getShaderParameter(i,r.COMPILE_STATUS))throw new Error(`composite_passthrough GLSL compile error: ${r.getShaderInfoLog(i)}`);if(this.program=r.createProgram(),r.attachShader(this.program,o),r.attachShader(this.program,i),r.linkProgram(this.program),!r.getProgramParameter(this.program,r.LINK_STATUS))throw new Error(`composite_passthrough GLSL link error: ${r.getProgramInfoLog(this.program)}`)}backend;program;imageTex;run(){let e=this.backend.gl;e.useProgram(this.program),e.activeTexture(e.TEXTURE0),e.bindTexture(e.TEXTURE_2D,this.imageTex),e.uniform1i(e.getUniformLocation(this.program,"u_image"),0),this.backend.bindDisplayFramebuffer(),e.bindVertexArray(null),e.drawArrays(e.TRIANGLES,0,6);}};var yt=`#version 300 es
|
|
2063
|
+
precision highp float;
|
|
2064
|
+
|
|
2065
|
+
// Input op \u2014 bilinear-sample a source texture (RGBA8 unorm uploaded from an
|
|
2066
|
+
// ImageBitmap or VideoFrame) at the target resolution. Output texture format
|
|
2067
|
+
// is RGBA32F or RGBA16F depending on backend.dtype; the framebuffer write
|
|
2068
|
+
// stores fragColor into whatever format is bound.
|
|
2069
|
+
|
|
2070
|
+
uniform sampler2D u_src;
|
|
2071
|
+
uniform int u_out_w;
|
|
2072
|
+
uniform int u_out_h;
|
|
2073
|
+
|
|
2074
|
+
out vec4 fragColor;
|
|
2075
|
+
|
|
2076
|
+
void main() {
|
|
2077
|
+
vec2 uv = (gl_FragCoord.xy + vec2(0.5)) / vec2(float(u_out_w), float(u_out_h));
|
|
2078
|
+
fragColor = texture(u_src, uv);
|
|
2079
|
+
}
|
|
2080
|
+
`;var wo=`#version 300 es
|
|
2081
|
+
const vec2 VERTS[6] = vec2[6](
|
|
2082
|
+
vec2(-1.0,-1.0), vec2(1.0,-1.0), vec2(-1.0,1.0),
|
|
2083
|
+
vec2(-1.0,1.0), vec2(1.0,-1.0), vec2(1.0,1.0)
|
|
2084
|
+
);
|
|
2085
|
+
void main() { gl_Position = vec4(VERTS[gl_VertexID], 0.0, 1.0); }`,me=class{constructor(e,t,r){this.backend=e;let o=e.gl;this.gl=o,this.output=e.tensor(t,r,4),this.srcTex=o.createTexture(),o.bindTexture(o.TEXTURE_2D,this.srcTex),o.texParameteri(o.TEXTURE_2D,o.TEXTURE_MIN_FILTER,o.LINEAR),o.texParameteri(o.TEXTURE_2D,o.TEXTURE_MAG_FILTER,o.LINEAR),o.texParameteri(o.TEXTURE_2D,o.TEXTURE_WRAP_S,o.CLAMP_TO_EDGE),o.texParameteri(o.TEXTURE_2D,o.TEXTURE_WRAP_T,o.CLAMP_TO_EDGE);let i=o.createShader(o.VERTEX_SHADER);o.shaderSource(i,wo),o.compileShader(i);let s=o.createShader(o.FRAGMENT_SHADER);if(o.shaderSource(s,yt),o.compileShader(s),!o.getShaderParameter(s,o.COMPILE_STATUS))throw new Error(`Input GLSL compile error: ${o.getShaderInfoLog(s)}`);if(this.program=o.createProgram(),o.attachShader(this.program,i),o.attachShader(this.program,s),o.linkProgram(this.program),!o.getProgramParameter(this.program,o.LINK_STATUS))throw new Error(`Input GLSL link error: ${o.getProgramInfoLog(this.program)}`);this.uSrc=o.getUniformLocation(this.program,"u_src"),this.uOutW=o.getUniformLocation(this.program,"u_out_w"),this.uOutH=o.getUniformLocation(this.program,"u_out_h");}backend;output;gl;program;srcTex;uOutW;uOutH;uSrc;source=null;setSource(e){this.source=e;}run(){if(!this.source)throw new Error("InputWebGL.run() called before setSource()");let e=this.gl;e.bindTexture(e.TEXTURE_2D,this.srcTex),e.texImage2D(e.TEXTURE_2D,0,e.RGBA,e.RGBA,e.UNSIGNED_BYTE,this.source),e.useProgram(this.program),e.activeTexture(e.TEXTURE0),e.bindTexture(e.TEXTURE_2D,this.srcTex),e.uniform1i(this.uSrc,0),e.uniform1i(this.uOutW,this.output.w),e.uniform1i(this.uOutH,this.output.h),e.bindFramebuffer(e.FRAMEBUFFER,this.backend.fbo),e.framebufferTexture2D(e.FRAMEBUFFER,e.COLOR_ATTACHMENT0,e.TEXTURE_2D,this.output.texture,0),e.viewport(0,0,this.output.texW,this.output.texH),e.bindVertexArray(null),e.drawArrays(e.TRIANGLES,0,6);}};var We=class a$1{constructor(e,t,r){this.gl=e;this.canvas=t;this.dtype=r;this.fbo=e.createFramebuffer(),this.textureFormat=r==="f16"?{internalFormat:e.RGBA16F,format:e.RGBA,type:e.HALF_FLOAT,bytesPerElement:2}:{internalFormat:e.RGBA32F,format:e.RGBA,type:e.FLOAT,bytesPerElement:4},this.ops={Conv2d:(o,i,s)=>new E(this,o,i,s),ConvTranspose2d:(o,i,s)=>new G(this,o,i,s),DepthwiseConv2d:(o,i,s)=>new F(this,o,i,s),Add:(o,i)=>new A(this,o,i),Sigmoid:o=>new S(this,o),Tanh:o=>new R(this,o),ElementwiseMul:(o,i)=>new D(this,o,i),Warp:(o,i,s)=>new B(this,o,i,s),FaceBoxFromHeatmaps:(o,i)=>new U(this,o,i),FaceBoxesFromHeatmaps:(o,i)=>new P(this,o,i),ReframeState:(o,i,s,n)=>new M(this,o,i,s,n),Reframe:(o,i)=>new O(this,o,i),CropResample:(o,i,s)=>new H(this,o,i,s),FaceTouchupStage:(o,i,s,n,u)=>new X(this,o,i,s,n,u),Stabilize:(o,i,s,n,u)=>new z(this,o,i,s,n,u),BilinearUpsample:(o,i)=>new $(this,o,i),Crop:(o,i)=>new j(this,o,i),BicubicUpsample:(o,i)=>new K(this,o,i),ChannelConcat:(o,i)=>new q(this,o,i),Conv2dAdd:(o,i,s,n)=>new Z(this,o,i,s,n),ProjResidual:(o,i,s,n)=>new ee(this,o,i,s,n),ConcatConv2d:(o,i,s,n)=>new te(this,o,i,s,n),GatesFused:(o,i,s)=>new oe(this,o,i,s),CandUpdateFused:(o,i,s,n,u)=>new re(this,o,i,s,n,u),ConvExpand:(o,i)=>new ie(this,o,i),CatConv6to2:(o,i,s)=>new ne(this,o,i,s),DownAdapter:(o,i,s,n)=>new se(this,o,i,s,n),UpFinal:(o,i,s)=>new ae(this,o,i,s),UpFinalSkip:(o,i,s,n)=>new ue(this,o,i,s,n),UpsampleConcat:(o,i,s)=>new Q(this,o,i,s),UpsampleConv1x1:(o,i,s)=>new J(this,o,i,s),UpsampleSigmoid:(o,i)=>new Y(this,o,i),Input:(o,i)=>new me(this,o,i)},this.presenters={CompositeSolid:(o,i,s)=>new le(this,o,i,s),CompositeImage:(o,i,s)=>new ce(this,o,i,s),CompositeImageBilinear:(o,i,s)=>new pe(this,o,i,s),CompositePassthrough:o=>new he(this,o),LandmarkOverlay:(o,i,s,n)=>new N(this,o,i,s,n),FaceTouchup:(o,i,s,n,u)=>new V(this,o,i,s,n,u)};}gl;canvas;dtype;ops;presenters;fbo;textureFormat;static isAvailable(){let e=null;try{return e=new OffscreenCanvas(1,1).getContext("webgl2"),!(!e||!e.getExtension("EXT_color_buffer_float"))}catch{return false}finally{e?.getExtension("WEBGL_lose_context")?.loseContext();}}static create(e){let t=e.canvas.getContext("webgl2");if(!t)throw new Error("WebGL2 not available");if(!t.getExtension("EXT_color_buffer_float"))throw new Error("EXT_color_buffer_float not available");return new a$1(t,e.canvas,e.dtype??"f32")}attachCanvas(e){throw new Error(`WebGLBackend.attachCanvas('${e}'): WebGL cannot render to a second canvas; use the renderer's snapshot-and-present path for preview output`)}bindDisplayFramebuffer(){this.gl.bindFramebuffer(this.gl.FRAMEBUFFER,null),this.gl.viewport(0,0,this.canvas.width,this.canvas.height);}toTextureView(e){if(e===null)return null;let t=this.dtype==="f16",r=e instanceof Uint16Array;return t===r?e:t?a(e):b(e)}tensor(e,t,r,o){let i=t*(r/4),s=e,n=this.gl,u=n.createTexture(),l=this.textureFormat,p=this.toTextureView(o??null);return n.bindTexture(n.TEXTURE_2D,u),n.texImage2D(n.TEXTURE_2D,0,l.internalFormat,i,s,0,l.format,l.type,p),n.texParameteri(n.TEXTURE_2D,n.TEXTURE_MIN_FILTER,n.NEAREST),n.texParameteri(n.TEXTURE_2D,n.TEXTURE_MAG_FILTER,n.NEAREST),n.texParameteri(n.TEXTURE_2D,n.TEXTURE_WRAP_S,n.CLAMP_TO_EDGE),n.texParameteri(n.TEXTURE_2D,n.TEXTURE_WRAP_T,n.CLAMP_TO_EDGE),{h:e,w:t,c:r,texture:u,texW:i,texH:s}}upload(e){return {data:e}}async readback(e){let t=this.gl,r=this.textureFormat;if(t.bindFramebuffer(t.FRAMEBUFFER,this.fbo),t.framebufferTexture2D(t.FRAMEBUFFER,t.COLOR_ATTACHMENT0,t.TEXTURE_2D,e.texture,0),this.dtype==="f16"){let i=new Uint16Array(e.texW*e.texH*4);return t.readPixels(0,0,e.texW,e.texH,r.format,t.HALF_FLOAT,i),t.bindFramebuffer(t.FRAMEBUFFER,null),b(i)}let o=new Float32Array(e.texW*e.texH*4);return t.readPixels(0,0,e.texW,e.texH,r.format,t.FLOAT,o),t.bindFramebuffer(t.FRAMEBUFFER,null),o}copyTensor(e,t){if(e.texW!==t.texW||e.texH!==t.texH)throw new Error(`copyTensor: size mismatch (src ${e.texW}\xD7${e.texH} vs dst ${t.texW}\xD7${t.texH})`);let r=this.gl;r.bindFramebuffer(r.FRAMEBUFFER,this.fbo),r.framebufferTexture2D(r.FRAMEBUFFER,r.COLOR_ATTACHMENT0,r.TEXTURE_2D,e.texture,0),r.bindTexture(r.TEXTURE_2D,t.texture),r.copyTexSubImage2D(r.TEXTURE_2D,0,0,0,0,0,e.texW,e.texH),r.bindFramebuffer(r.FRAMEBUFFER,null);}async sync(){let e=this.gl,t=e.fenceSync(e.SYNC_GPU_COMMANDS_COMPLETE,0);if(!t){e.finish();return}for(e.flush();;){let r=e.clientWaitSync(t,0,0);if(r===e.ALREADY_SIGNALED||r===e.CONDITION_SATISFIED){e.deleteSync(t);return}if(r===e.WAIT_FAILED)throw e.deleteSync(t),new Error("WebGLBackend.sync: clientWaitSync returned WAIT_FAILED");await new Promise(o=>setTimeout(o,1));}}destroy(){this.gl.deleteFramebuffer(this.fbo),this.gl.getExtension("WEBGL_lose_context")?.loseContext();}};function wt(a,e,t,r){let o=r.variant,i=o==="E"||o==="D",s=o==="D",n=e.h,u=e.w,l=[],p=null,h=null,m=0,x=0,_;if(i)if(s){if(!t.down2)throw new Error("variant D requires w.down2");m=Math.round(n/1.25),x=Math.round(u/1.25);let g=a.ops.Conv2d(e,t.down1,{outChannels:r.cHigh,kernel:3,stride:1,padding:1,activation:"relu"});l.push(g),h=g.output;let b=a.ops.BilinearUpsample(h,{outH:m,outW:x});l.push(b),p=b.output;let L=a.ops.DownAdapter(p,t.down2,t.adapter,{stride:2});l.push(L),_=L.output;}else {if(!t.down2)throw new Error("variant E requires w.down2");let g=a.ops.Conv2d(e,t.down1,{outChannels:r.cHigh,kernel:3,stride:2,padding:1,activation:"relu"});l.push(g),p=g.output,m=p.h,x=p.w;let b=a.ops.DownAdapter(p,t.down2,t.adapter,{stride:2});l.push(b),_=b.output;}else {let g=o==="A"?2:3,b=a.ops.DownAdapter(e,t.down1,t.adapter,{stride:g});l.push(b),_=b.output;}return {steps:l,adapted:_,d1:p,dFull:h,midH:m,midW:x}}function Tt(a,e,t,r,o,i,s,n,u){let l=u.variant,p=l==="E"||l==="D",h=l==="D",m=[],x=a.ops.ConvExpand(t,n.expandFeat);m.push(x);let _=x.output,g;if(p){if(!n.up1Combine)throw new Error("two-stage variant requires w.up1Combine");let L=a.ops.BilinearUpsample(_,{outH:i,outW:s});m.push(L);let Fe=a.ops.CatConv6to2(L.output,r,n.up1Combine);m.push(Fe);let Ae=a.ops.BilinearUpsample(Fe.output,{outH:e.h,outW:e.w});m.push(Ae),g=Ae.output;}else {let L=a.ops.BilinearUpsample(_,{outH:e.h,outW:e.w});m.push(L),g=L.output;}let b=h?a.ops.UpFinalSkip(g,o,e,n.upCombine):a.ops.UpFinal(g,e,n.upCombine);return m.push(b),{steps:m,alpha:b.output}}var Ce=class{inputs;output;encoderTaps;halfTap;steps;constructor(e,t,r,o,i,s){this.inputs=[t];let n=wt(e,t,o,i),u=new s(e,n.adapted,r),l=e.ops.BilinearUpsample(u.featLowRes,{outH:n.adapted.h,outW:n.adapted.w}),p=Tt(e,t,l.output,n.d1,n.dFull,n.midH,n.midW,o,i);this.steps=[...n.steps,u,l,...p.steps],this.output=p.alpha,this.encoderTaps=u.encoderTaps,this.halfTap=u.halfTap;}run(){for(let e of this.steps)e.run();}};var C=class{inputs;output;dwOp;pwOp;constructor(e,t,r,o){this.inputs=[t],this.dwOp=e.ops.DepthwiseConv2d(t,r.dw,{kernel:o.kernel,stride:o.stride,padding:o.padding,activation:"relu6"}),this.pwOp=e.ops.Conv2d(this.dwOp.output,r.pw,{outChannels:o.outChannels,kernel:1,stride:1,padding:0,activation:"none"}),this.output=this.pwOp.output;}run(){this.dwOp.run(),this.pwOp.run();}};var f=class{inputs;output;expandOp;dwOp;projOp;constructor(e,t,r,o){this.inputs=[t];let i=o.midChannels!==o.inChannels,s=o.stride===1&&o.inChannels===o.outChannels;this.expandOp=i?e.ops.Conv2d(t,r.expand,{outChannels:o.midChannels,kernel:1,stride:1,padding:0,activation:"relu6"}):null;let n=this.expandOp?this.expandOp.output:t;this.dwOp=e.ops.DepthwiseConv2d(n,r.dw,{kernel:o.kernel,stride:o.stride,padding:o.padding,activation:"relu6"}),this.projOp=s?e.ops.ProjResidual(this.dwOp.output,t,r.proj,{outChannels:o.outChannels}):e.ops.Conv2d(this.dwOp.output,r.proj,{outChannels:o.outChannels,kernel:1,stride:1,padding:0,activation:"none"}),this.output=this.projOp.output;}run(){this.expandOp?.run(),this.dwOp.run(),this.projOp.run();}};var y=class{inputs;output;upOp;concatConvOp;conv2Op;constructor(e,t,r,o,i){this.inputs=[t,r],this.upOp=e.ops.BilinearUpsample(t,{outH:r.h,outW:r.w}),this.concatConvOp=e.ops.ConcatConv2d(this.upOp.output,r,o.conv1,{outChannels:i.outChannels}),this.conv2Op=e.ops.Conv2d(this.concatConvOp.output,o.conv2,{outChannels:i.outChannels,kernel:3,stride:1,padding:1,activation:"relu6"}),this.output=this.conv2Op.output;}run(){this.upOp.run(),this.concatConvOp.run(),this.conv2Op.run();}};var de=class{output;featLowRes;encoderTaps;halfTap;stem;s0;s1b0;s1b1;s2b0;s2b1;s3b0;s3b1;s3b2;s4b0;s4b1;s4b2;bottleneck;dec0;dec1;finalUp;outConv;alpha;constructor(e,t,r){this.stem=e.ops.Conv2d(t,r.encoder.stem,{outChannels:32,kernel:3,stride:2,padding:"same",activation:"relu6"}),this.s0=new C(e,this.stem.output,r.encoder.s0,{outChannels:16,kernel:3,stride:1,padding:1}),this.s1b0=new f(e,this.s0.output,r.encoder.s1[0],{inChannels:16,midChannels:96,outChannels:24,kernel:3,stride:2,padding:"same"}),this.s1b1=new f(e,this.s1b0.output,r.encoder.s1[1],{inChannels:24,midChannels:144,outChannels:24,kernel:3,stride:1,padding:1}),this.s2b0=new f(e,this.s1b1.output,r.encoder.s2[0],{inChannels:24,midChannels:144,outChannels:40,kernel:5,stride:2,padding:"same"}),this.s2b1=new f(e,this.s2b0.output,r.encoder.s2[1],{inChannels:40,midChannels:240,outChannels:40,kernel:5,stride:1,padding:2}),this.s3b0=new f(e,this.s2b1.output,r.encoder.s3[0],{inChannels:40,midChannels:240,outChannels:80,kernel:3,stride:2,padding:"same"}),this.s3b1=new f(e,this.s3b0.output,r.encoder.s3[1],{inChannels:80,midChannels:480,outChannels:80,kernel:3,stride:1,padding:1}),this.s3b2=new f(e,this.s3b1.output,r.encoder.s3[2],{inChannels:80,midChannels:480,outChannels:80,kernel:3,stride:1,padding:1}),this.s4b0=new f(e,this.s3b2.output,r.encoder.s4[0],{inChannels:80,midChannels:480,outChannels:112,kernel:5,stride:1,padding:2}),this.s4b1=new f(e,this.s4b0.output,r.encoder.s4[1],{inChannels:112,midChannels:672,outChannels:112,kernel:5,stride:1,padding:2}),this.s4b2=new f(e,this.s4b1.output,r.encoder.s4[2],{inChannels:112,midChannels:672,outChannels:112,kernel:5,stride:1,padding:2}),this.bottleneck=e.ops.Conv2d(this.s4b2.output,r.bottleneck,{outChannels:128,kernel:1,stride:1,padding:0,activation:"relu6"}),this.dec0=new y(e,this.bottleneck.output,this.s2b1.output,r.decoder.blocks[0],{outChannels:64}),this.dec1=new y(e,this.dec0.output,this.s1b1.output,r.decoder.blocks[1],{outChannels:32}),this.finalUp=e.ops.UpsampleConv1x1(this.dec1.output,r.decoder.finalUpsample,{outH:this.dec1.output.h*2,outW:this.dec1.output.w*2,outChannels:32,activation:"relu6"}),this.featLowRes=this.finalUp.output,this.encoderTaps=[this.s1b1.output,this.s2b1.output,this.s4b2.output],this.halfTap=this.s0.output,this.outConv=e.ops.Conv2d(this.finalUp.output,r.decoder.outputConv,{outChannels:4,kernel:1,stride:1,padding:0,activation:"none"}),this.alpha=e.ops.UpsampleSigmoid(this.outConv.output,{outH:this.outConv.output.h*2,outW:this.outConv.output.w*2}),this.output=this.alpha.output;}run(){this.stem.run(),this.s0.run(),this.s1b0.run(),this.s1b1.run(),this.s2b0.run(),this.s2b1.run(),this.s3b0.run(),this.s3b1.run(),this.s3b2.run(),this.s4b0.run(),this.s4b1.run(),this.s4b2.run(),this.bottleneck.run(),this.dec0.run(),this.dec1.run(),this.finalUp.run(),this.outConv.run(),this.alpha.run();}};var _e=class{output;featLowRes;encoderTaps;stem;s0;s1b0;s1b1;s2b0;s2b1;s3b0;s3b1;s3b2;s4b0;s4b1;s4b2;s5b0;s5b1;s5b2;s5b3;s6b0;bottleneck;dec0;dec1;dec2;finalUp;outConv;alpha;constructor(e,t,r){this.stem=e.ops.Conv2d(t,r.encoder.stem,{outChannels:32,kernel:3,stride:2,padding:"same",activation:"relu6"}),this.s0=new C(e,this.stem.output,r.encoder.s0,{outChannels:16,kernel:3,stride:1,padding:1}),this.s1b0=new f(e,this.s0.output,r.encoder.s1[0],{inChannels:16,midChannels:96,outChannels:24,kernel:3,stride:2,padding:"same"}),this.s1b1=new f(e,this.s1b0.output,r.encoder.s1[1],{inChannels:24,midChannels:144,outChannels:24,kernel:3,stride:1,padding:1}),this.s2b0=new f(e,this.s1b1.output,r.encoder.s2[0],{inChannels:24,midChannels:144,outChannels:40,kernel:5,stride:2,padding:"same"}),this.s2b1=new f(e,this.s2b0.output,r.encoder.s2[1],{inChannels:40,midChannels:240,outChannels:40,kernel:5,stride:1,padding:2}),this.s3b0=new f(e,this.s2b1.output,r.encoder.s3[0],{inChannels:40,midChannels:240,outChannels:80,kernel:3,stride:2,padding:"same"}),this.s3b1=new f(e,this.s3b0.output,r.encoder.s3[1],{inChannels:80,midChannels:480,outChannels:80,kernel:3,stride:1,padding:1}),this.s3b2=new f(e,this.s3b1.output,r.encoder.s3[2],{inChannels:80,midChannels:480,outChannels:80,kernel:3,stride:1,padding:1}),this.s4b0=new f(e,this.s3b2.output,r.encoder.s4[0],{inChannels:80,midChannels:480,outChannels:112,kernel:5,stride:1,padding:2}),this.s4b1=new f(e,this.s4b0.output,r.encoder.s4[1],{inChannels:112,midChannels:672,outChannels:112,kernel:5,stride:1,padding:2}),this.s4b2=new f(e,this.s4b1.output,r.encoder.s4[2],{inChannels:112,midChannels:672,outChannels:112,kernel:5,stride:1,padding:2}),this.s5b0=new f(e,this.s4b2.output,r.encoder.s5[0],{inChannels:112,midChannels:672,outChannels:192,kernel:5,stride:2,padding:"same"}),this.s5b1=new f(e,this.s5b0.output,r.encoder.s5[1],{inChannels:192,midChannels:1152,outChannels:192,kernel:5,stride:1,padding:2}),this.s5b2=new f(e,this.s5b1.output,r.encoder.s5[2],{inChannels:192,midChannels:1152,outChannels:192,kernel:5,stride:1,padding:2}),this.s5b3=new f(e,this.s5b2.output,r.encoder.s5[3],{inChannels:192,midChannels:1152,outChannels:192,kernel:5,stride:1,padding:2}),this.s6b0=new f(e,this.s5b3.output,r.encoder.s6[0],{inChannels:192,midChannels:1152,outChannels:320,kernel:3,stride:1,padding:1}),this.bottleneck=e.ops.Conv2d(this.s6b0.output,r.bottleneck,{outChannels:128,kernel:1,stride:1,padding:0,activation:"relu6"}),this.dec0=new y(e,this.bottleneck.output,this.s4b2.output,r.decoder.blocks[0],{outChannels:64}),this.dec1=new y(e,this.dec0.output,this.s2b1.output,r.decoder.blocks[1],{outChannels:32}),this.dec2=new y(e,this.dec1.output,this.s1b1.output,r.decoder.blocks[2],{outChannels:16}),this.finalUp=e.ops.UpsampleConv1x1(this.dec2.output,r.decoder.finalUpsample,{outH:this.dec2.output.h*2,outW:this.dec2.output.w*2,outChannels:16,activation:"relu6"}),this.featLowRes=this.finalUp.output,this.encoderTaps=[this.s1b1.output,this.s2b1.output,this.s4b2.output,this.s6b0.output],this.outConv=e.ops.Conv2d(this.finalUp.output,r.decoder.outputConv,{outChannels:4,kernel:1,stride:1,padding:0,activation:"none"}),this.alpha=e.ops.UpsampleSigmoid(this.outConv.output,{outH:this.outConv.output.h*2,outW:this.outConv.output.w*2}),this.output=this.alpha.output;}run(){this.stem.run(),this.s0.run(),this.s1b0.run(),this.s1b1.run(),this.s2b0.run(),this.s2b1.run(),this.s3b0.run(),this.s3b1.run(),this.s3b2.run(),this.s4b0.run(),this.s4b1.run(),this.s4b2.run(),this.s5b0.run(),this.s5b1.run(),this.s5b2.run(),this.s5b3.run(),this.s6b0.run(),this.bottleneck.run(),this.dec0.run(),this.dec1.run(),this.dec2.run(),this.finalUp.run(),this.outConv.run(),this.alpha.run();}};var Ee=[[{in:24,mid:144,out:32,k:3,s:2},{in:32,mid:192,out:32,k:3,s:1},{in:32,mid:192,out:32,k:3,s:1}],[{in:32,mid:192,out:48,k:5,s:2},{in:48,mid:288,out:48,k:5,s:1},{in:48,mid:288,out:48,k:5,s:1}],[{in:48,mid:288,out:96,k:3,s:2},{in:96,mid:576,out:96,k:3,s:1},{in:96,mid:576,out:96,k:3,s:1},{in:96,mid:576,out:96,k:3,s:1},{in:96,mid:576,out:96,k:3,s:1}],[{in:96,mid:576,out:136,k:5,s:1},{in:136,mid:816,out:136,k:5,s:1},{in:136,mid:816,out:136,k:5,s:1},{in:136,mid:816,out:136,k:5,s:1},{in:136,mid:816,out:136,k:5,s:1}],[{in:136,mid:816,out:232,k:5,s:2},{in:232,mid:1392,out:232,k:5,s:1},{in:232,mid:1392,out:232,k:5,s:1},{in:232,mid:1392,out:232,k:5,s:1},{in:232,mid:1392,out:232,k:5,s:1},{in:232,mid:1392,out:232,k:5,s:1}],[{in:232,mid:1392,out:384,k:3,s:1}]],fe=class{output;featLowRes;encoderTaps;stem;s0;stages;bottleneck;dec0;dec1;dec2;finalUp;outConv;alpha;constructor(e,t,r){this.stem=e.ops.Conv2d(t,r.encoder.stem,{outChannels:32,kernel:3,stride:2,padding:"same",activation:"relu6"}),this.s0=new C(e,this.stem.output,r.encoder.s0,{outChannels:24,kernel:3,stride:1,padding:1});let o=[r.encoder.s1,r.encoder.s2,r.encoder.s3,r.encoder.s4,r.encoder.s5,r.encoder.s6];this.stages=[];let i=this.s0.output;for(let h=0;h<Ee.length;h++){let m=[];for(let x=0;x<Ee[h].length;x++){let _=Ee[h][x],g=new f(e,i,o[h][x],{inChannels:_.in,midChannels:_.mid,outChannels:_.out,kernel:_.k,stride:_.s,padding:_.s===2?"same":(_.k-1)/2});m.push(g),i=g.output;}this.stages.push(m);}let s=h=>this.stages[h][this.stages[h].length-1].output,n=s(0),u=s(1),l=s(3),p=s(5);this.bottleneck=e.ops.Conv2d(p,r.bottleneck,{outChannels:256,kernel:1,stride:1,padding:0,activation:"relu6"}),this.dec0=new y(e,this.bottleneck.output,l,r.decoder.blocks[0],{outChannels:128}),this.dec1=new y(e,this.dec0.output,u,r.decoder.blocks[1],{outChannels:64}),this.dec2=new y(e,this.dec1.output,n,r.decoder.blocks[2],{outChannels:32}),this.finalUp=e.ops.UpsampleConv1x1(this.dec2.output,r.decoder.finalUpsample,{outH:this.dec2.output.h*2,outW:this.dec2.output.w*2,outChannels:32,activation:"relu6"}),this.featLowRes=this.finalUp.output,this.encoderTaps=[n,u,l,p],this.outConv=e.ops.Conv2d(this.finalUp.output,r.decoder.outputConv,{outChannels:4,kernel:1,stride:1,padding:0,activation:"none"}),this.alpha=e.ops.UpsampleSigmoid(this.outConv.output,{outH:this.outConv.output.h*2,outW:this.outConv.output.w*2}),this.output=this.alpha.output;}run(){this.stem.run(),this.s0.run();for(let e of this.stages)for(let t of e)t.run();this.bottleneck.run(),this.dec0.run(),this.dec1.run(),this.dec2.run(),this.finalUp.run(),this.outConv.run(),this.alpha.run();}};var kt=de,Lt=_e,To=fe,ko={xs:{base:kt,wrapper:{variant:"B",cHigh:4,cLow:4,cUp:2},canvasRes:{w:384,h:240},baseRes:{w:128,h:80},flowFuseStem:true},small:{base:kt,wrapper:{variant:"A",cHigh:4,cLow:4,cUp:2},canvasRes:{w:384,h:224},baseRes:{w:192,h:112}},medium:{base:Lt,wrapper:{variant:"A",cHigh:4,cLow:4,cUp:2},canvasRes:{w:512,h:320},baseRes:{w:256,h:160}},large:{base:Lt,wrapper:{variant:"D",cHigh:4,cLow:4,cUp:2},canvasRes:{w:640,h:400},baseRes:{w:256,h:160}},xl:{base:To,wrapper:{variant:"E",cHigh:4,cLow:4,cUp:2},canvasRes:{w:1280,h:768},baseRes:{w:320,h:192}}};var Lo=a=>typeof a=="object"&&a!==null&&typeof a.offset=="number"&&typeof a.length=="number";function Wo(a){if(a.byteLength<4)throw new Error("weights buffer too small");let e=new DataView(a,0,4).getUint32(0,true),t=4+e;if(a.byteLength<t)throw new Error("weights buffer truncated (header)");let r=new Uint8Array(a,4,e),o=JSON.parse(new TextDecoder().decode(r)),i=o.__dtype__??"f32",s=i==="f16"?2:4;if(t%s!==0)throw new Error(`payload not ${s}-byte aligned (header=${e})`);let n=(a.byteLength-t)/s,u=l=>{if(Lo(l)){let{offset:p,length:h}=l;if(p+h>n)throw new Error(`array ref out of range: offset=${p} length=${h}`);let m=t+p*s;return i==="f16"?new Uint16Array(a,m,h):new Float32Array(a,m,h)}if(Array.isArray(l))return l.map(u);if(typeof l=="object"&&l!==null){let p={};for(let h of Object.keys(l))h!=="__dtype__"&&(p[h]=u(l[h]));return p}return l};return u(o)}var xe=class{op;constructor(e,t,r,o){this.op=e.ops.BilinearUpsample(t,{outH:r,outW:o});}get output(){return this.op.output}run(){this.op.run();}};var ge=class{op;constructor(e,t,r,o){this.op=e.ops.BicubicUpsample(t,{outH:r,outW:o});}get output(){return this.op.output}run(){this.op.run();}};var be=class{presenter;constructor(e,t,r,o,i="main"){this.presenter=e.presenters.CompositeSolid(t,r,o,i);}run(){this.presenter.run();}};var ve=class{presenter;constructor(e,t,r,o,i="main"){this.presenter=e.presenters.CompositeImage(t,r,o,i);}run(){this.presenter.run();}};var ye=class{downs=[];ups=[];constructor(e,t,r){let o=Co(r),i=t;for(let s=0;s<o;s++){let n=e.ops.BilinearUpsample(i,{outH:Math.max(1,Math.floor(i.h/2)),outW:Math.max(1,Math.floor(i.w/2))});this.downs.push(n),i=n.output;}for(let s=o-1;s>=1;s--){let n=this.downs[s-1].output,u=e.ops.BilinearUpsample(i,{outH:n.h,outW:n.w});this.ups.push(u),i=u.output;}}get output(){return this.ups.length>0?this.ups[this.ups.length-1].output:this.downs[0].output}run(){for(let e of this.downs)e.run();for(let e of this.ups)e.run();}};function Co(a){let e=Math.max(1,3*a);return Math.max(2,Math.min(6,Math.round(Math.log2(e))))}var Eo=.05,we=class{blur;presenter;constructor(e,t,r,o,i="main"){o<=Eo?(this.blur=null,this.presenter=e.presenters.CompositeImage(t,r,t,i)):(this.blur=new ye(e,t,o),this.presenter=e.presenters.CompositeImageBilinear(t,r,this.blur.output,i));}run(){this.blur?.run(),this.presenter.run();}};var Ge=class{constructor(e){this.backend=e;let t=e.canvas;this.displayInput=e.ops.Input(t.height,t.width),this.image=this.displayInput.output;}backend;displayInput;image;network=null;networkInput=null;upscaler=null;upscalerMode="bilinear";bgConfig={mode:"solid",color:[0,0,0]};effectChain=[];viewRect=null;viewFg=null;viewAlpha=null;displayDirty=false;compositors=new Map;attachNetwork(e,t,r){this.network=e,this.networkInput=t,this.upscalerMode=r.upscaler,this.bgConfig=r.background,this.upscaler=this.makeUpscaler(),this.rebuildView(),this.compositors.clear();}hasNetwork(){return this.network!==null}setSource(e){this.networkInput?.setSource(e),this.displayInput.setSource(e),this.displayDirty=true;}setUpscaler(e){e!==this.upscalerMode&&(this.upscalerMode=e,this.network&&(this.upscaler=this.makeUpscaler(),this.rebuildView(),this.compositors.clear()));}setBackground(e){this.bgConfig=e;}get displayImage(){return this.image}fgImage(){return this.viewFg?this.viewFg.output:this.chainTail()}chainTail(){return this.effectChain.length?this.effectChain[this.effectChain.length-1].output:this.image}alphaImage(){if(!this.upscaler)throw new Error("RenderOp.alphaImage called before attachNetwork");return this.viewAlpha?this.viewAlpha.output:this.upscaler.output}setViewTransform(e){this.viewRect=e,this.rebuildView(),this.compositors.clear();}rebuildView(){this.viewFg=null,this.viewAlpha=null,this.viewRect&&(this.viewFg=this.backend.ops.Reframe(this.chainTail(),this.viewRect),this.upscaler&&(this.viewAlpha=this.backend.ops.Reframe(this.upscaler.output,this.viewRect)));}setEffectChain(e){this.effectChain=e,this.rebuildView(),this.compositors.clear();}runEffects(){for(let e of this.effectChain)e.run();this.viewFg?.run(),this.viewAlpha?.run();}run(){this.runModel(),this.runDisplay();}runDisplay(){this.refreshDisplayInput(),this.runEffects(),this.compositeMain("effect");}runFgPassthrough(){this.refreshDisplayInput(),this.runEffects(),this.compositeMain("fg");}runPassthrough(){this.refreshDisplayInput(),this.compositeMain("raw");}compositeMain(e){let t=e==="effect"?this.bgConfig:e==="fg"?{mode:"fg-passthrough"}:{mode:"passthrough"};this.compositeTo("main",t);}refreshDisplayInput(){this.displayDirty&&(this.displayInput.run(),this.displayDirty=false);}compositeTo(e,t){let r=this.compositors.get(e);if(r&&Go(r.spec,t)){r.handle.run();return}let o=this.buildCompositor(e,t);this.compositors.set(e,{spec:t,handle:o}),o.run();}applyAlpha(e){if(!this.network||!this.upscaler)throw new Error("RenderOp.applyAlpha called before attachNetwork");this.backend.copyTensor(e,this.network.output),this.upscaler.run();}runModel(){if(!this.network||!this.networkInput||!this.upscaler)throw new Error("RenderOp.runModel called before attachNetwork");this.networkInput.run(),this.network.run(),this.upscaler.run();}makeUpscaler(){if(!this.network)throw new Error("makeUpscaler called with no network");let{backend:e,network:t,image:r}=this;return this.upscalerMode==="bicubic"?new ge(e,t.output,r.h,r.w):new xe(e,t.output,r.h,r.w)}buildCompositor(e,t){let{backend:r,image:o}=this;if(t.mode==="passthrough")return r.presenters.CompositePassthrough(o,e);let i=this.fgImage();if(t.mode==="fg-passthrough")return r.presenters.CompositePassthrough(i,e);if(!this.upscaler)throw new Error("RenderOp.compositeTo (effect spec) called before attachNetwork");let s=this.alphaImage();switch(t.mode){case "solid":return new be(r,i,s,t.color,e);case "image":return new ve(r,i,s,t.image,e);case "blur":return new we(r,i,s,t.sigma,e)}}};function Go(a,e){if(a.mode!==e.mode)return false;switch(e.mode){case "passthrough":return true;case "fg-passthrough":return true;case "solid":{let t=a.color;return t[0]===e.color[0]&&t[1]===e.color[1]&&t[2]===e.color[2]}case "blur":return a.sigma===e.sigma;case "image":return a.image===e.image}}export{Ge as RenderOp,ko as TIER_CONFIG,Ce as TierModel,We as WebGLBackend,Wo as loadWeightsFromBinary};
|