Skip to content

Instantly share code, notes, and snippets.

What would you like to do?
compensated Lanczos3 pass X (from mpc-be, adapted for mpc-hc user shader)
// compensated Lanczos3, pass X
// originally from mpc-be:
// adapted for use in mpc-hc (as zoomX=2) by butterw (license: GPL v3)
// use as a pre-resize shader, input resolution should match the screen resolution (no player resize involved)
// pass X perf: (6 texture, 79 arithmetic)
// A catmull-rom resizer (true separable kernel) is also available: resizer_catmull4_x.hlsl. Catmull-Rom spline4, pass X: (4 texture, 22 arithmetic)
sampler s0: register(s0);
float2 p0: register(c0); // W, H
float2 p1: register(c1); //px, py
#define PI 3.14159265 //acos(-1)
float4 main(float2 tex: TEXCOORD0): COLOR {
float coord = 0.5*tex.x*p0.x; // butterw: Any resize ratio is possible. coord = tex.x*p0.x/zoomX here with zoomX=2.;
float t = frac(coord);
coord = (coord-t + 0.5)*p1.x;
// original pixels
float4 Q2 = tex2D(s0, float2(coord, tex.y)); // nearest original pixel to the left
// if (!t) return Q2; // float4(1, 0, 0, 1); butterw: no longer required
// case t == 0. is required to return sample Q2, because of a possible division by 0.
float4 Q0 = tex2D(s0, float2(coord -2*p1.x, tex.y));
float4 Q1 = tex2D(s0, float2(coord -p1.x, tex.y));
float4 Q3 = tex2D(s0, float2(coord +p1.x, tex.y));
float4 Q4 = tex2D(s0, float2(coord +2*p1.x, tex.y));
float4 Q5 = tex2D(s0, float2(coord +3*p1.x, tex.y));
// calculate weights
float3 wset0 = t*PI + float3(2, 1, 0)*PI;
float3 wset1 = -t*PI + float3(1, 2, 3)*PI;
float3 wset0s = wset0*.5;
float3 wset1s = wset1*.5;
float3 w0 = sin(wset0) *sin(wset0s)/(wset0*wset0s);
float3 w1 = sin(wset1) *sin(wset1s)/(wset1*wset1s);
float wc = 1. -dot(1., w0+w1); // compensate truncated window factor by linear factoring on the two nearest samples
w0.z+= wc*(1.-t);
w1.x+= wc*t;
return w0.x*Q0 + w0.y*Q1 + w0.z*Q2 + w1.x*Q3 + w1.y*Q4 + w1.z*Q5; // interpolation output
in mpc-be resizer was:
// float t = frac(tex.x);
// float2 pos = tex-float2(t, 0.);
// float4 Q1 = tex2D(s0, (pos+float2(-.5, .5))*dxdy);
The mpc-be resizer uses pixel scale for the tex.x coordinate.
ex tex.x: 421.5 for a 1000x1000 output frame, whereas the typical hlsl scale, used in mpc-hc/be user shaders is [0, 1.]
For 2x magnification, the corresponding input texel center would be at: 210.75 -0.75 +0.5=210.5 in output frame coordinates, given the half-pixel offset of texel centers in hlsl.
butterw: Changed to: tex.x in [0, 1.0] for mpc-hc user shader
float2 p0: register(c0); //W, H
float2 p1: register(c1); //px, py
float coord = 0.5*tex.x*p0.x; // butterw: for 2x Magnification (any float value possible). coord = 1./ZoomX*tex.x*p0.x; (tex.x - p1.x)*0.5*p0.x;
float t = frac(coord);
coord = (coord-t + 0.5)*p1.x; //texel centers are at half pixel offset in hlsl.
>> float4 Q1 = tex2D(s0, float2(coord - p1.x, tex.y));
could use a getX(x_poffset) function, but it has the same perf:
#define getX(x_poffset) float4 tex2D(s0, float2(coord+x_poffset*p1.x, tex.y))
>> float4 Q1 = getX(-1);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment