33
44float lanczosWeight(float x, float r) {
55 const float PI_SQ = 9.8696044010893586188344910 ;
6- if (x == 0.0 )
6+ // Use the analytic limit near zero to avoid unstable GPU sine/division results.
7+ if (abs (x) < 0.0001 )
78 return 1 .;
89 return (r * sin (M_PI * x) * sin (M_PI * (x / r) )) / (PI_SQ * x* x);
910 }
1011
11- float lanczosWeight(vec2 x, float r) {
12- return lanczosWeight(x.x, r) * lanczosWeight(x.y, r);
13- }
14-
1512vec3 lanczosUpscale(in sampler2D img, vec2 coord) {
1613 const int r = 2 ;
1714
@@ -20,20 +17,34 @@ vec3 lanczosUpscale(in sampler2D img, vec2 coord) {
2017 coord += - 0.5 * resInv;
2118 vec2 ccoord = floor (coord * res) * resInv;
2219
20+ // Evaluate each one-dimensional weight once.
21+ // Keep the original footprint, including its omitted four corner samples.
22+ vec2 weights[5 ];
23+ [[unroll]]
24+ for (int i = - r; i <= r; ++ i) {
25+ vec2 d = ((vec2 (i) * resInv + ccoord - coord) * res);
26+ weights[i+ r] = vec2 (lanczosWeight(d.x, float (r)), lanczosWeight(d.y, float (r)));
27+ }
28+
29+ // The weights at offsets zero and one have the same sign.
30+ // A bilinear read combines them without replacing the Lanczos kernel.
31+ // The caller must use a linear, clamp-to-edge sampler.
32+ vec2 centerWeight = weights[2 ] + weights[3 ];
33+ vec2 centerOffset = clamp (weights[3 ] / centerWeight, vec2 (0 ), vec2 (1 ));
34+ vec2 offsets[4 ] = vec2 [4 ](vec2 (- 2 ), vec2 (- 1 ), centerOffset, vec2 (2 ));
35+ vec2 merged[4 ] = vec2 [4 ](weights[0 ], weights[1 ], centerWeight, weights[4 ]);
36+
2337 vec3 total = vec3 (0 );
2438 [[unroll]]
25- for (int x = - r ; x <= r ; x++ ) {
39+ for (int x = 0 ; x < 4 ; x++ ) {
2640 [[unroll]]
27- for (int y = - r ; y <= r ; y++ ) {
28- if (abs (x) == r && abs (y) == r )
41+ for (int y = 0 ; y < 4 ; y++ ) {
42+ if ((x == 0 || x == 3 ) && (y == 0 || y == 3 ) )
2943 continue ;
3044
31- vec2 offs = vec2 (x,y);
32- vec2 sco = offs * resInv + ccoord;
33- vec2 d = ((sco - coord) * res);
34-
45+ vec2 sco = vec2 (offsets[x].x, offsets[y].y) * resInv + ccoord;
3546 vec3 val = textureLod(img, sco+ 0.5 * resInv, 0.0 ).rgb;
36- float weight = lanczosWeight(d, float (r)) ;
47+ float weight = merged[x].x * merged[y].y ;
3748
3849 total += val * weight;
3950 }
0 commit comments