Skip to content

Instantly share code, notes, and snippets.

@igv
Last active May 11, 2023 06:13
Embed
What would you like to do?
Requires linear-downscaling=no.
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 3.0 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library.
//!HOOK POSTKERNEL
//!BIND HOOKED
//!BIND PREKERNEL
//!SAVE L2
//!WIDTH NATIVE_CROPPED.w
//!WHEN NATIVE_CROPPED.h POSTKERNEL.h >
//!COMPONENTS 3
//!DESC SSimDownscaler L2 pass 1
#define axis 1
#define offset vec2(0,0)
#define MN(B,C,x) (x < 1.0 ? ((2.-1.5*B-(C))*x + (-3.+2.*B+C))*x*x + (1.-(B)/3.) : (((-(B)/6.-(C))*x + (B+5.*C))*x + (-2.*B-8.*C))*x+((4./3.)*B+4.*C))
#define Kernel(x) MN(.0, .5, abs(x))
#define taps 2.0
vec4 hook() {
vec2 base = PREKERNEL_pt * (PREKERNEL_pos * input_size + tex_offset);
float low = ceil((PREKERNEL_pos - taps*POSTKERNEL_pt) * input_size - offset + tex_offset - 0.5)[axis];
float high = floor((PREKERNEL_pos + taps*POSTKERNEL_pt) * input_size - offset + tex_offset - 0.5)[axis];
float W = 0.0;
vec4 avg = vec4(0);
vec2 pos = base;
for (float k = low; k <= high; k++) {
pos[axis] = PREKERNEL_pt[axis] * (k - offset[axis] + 0.5);
float rel = (pos[axis] - base[axis])*POSTKERNEL_size[axis];
float w = Kernel(rel);
vec4 tex = textureLod(PREKERNEL_raw, pos, 0.0) * PREKERNEL_mul;
avg += w * tex * tex;
W += w;
}
avg /= W;
return avg;
}
//!HOOK POSTKERNEL
//!BIND HOOKED
//!BIND L2
//!SAVE L2
//!WHEN NATIVE_CROPPED.w POSTKERNEL.w >
//!COMPONENTS 3
//!DESC SSimDownscaler L2 pass 2
#define axis 0
#define offset vec2(0,0)
#define MN(B,C,x) (x < 1.0 ? ((2.-1.5*B-(C))*x + (-3.+2.*B+C))*x*x + (1.-(B)/3.) : (((-(B)/6.-(C))*x + (B+5.*C))*x + (-2.*B-8.*C))*x+((4./3.)*B+4.*C))
#define Kernel(x) MN(.0, .5, abs(x))
#define taps 2.0
vec4 hook() {
float low = ceil((L2_pos - taps*POSTKERNEL_pt) * L2_size - offset - 0.5)[axis];
float high = floor((L2_pos + taps*POSTKERNEL_pt) * L2_size - offset - 0.5)[axis];
float W = 0.0;
vec4 avg = vec4(0);
vec2 pos = L2_pos;
for (float k = low; k <= high; k++) {
pos[axis] = L2_pt[axis] * (k - offset[axis] + 0.5);
float rel = (pos[axis] - L2_pos[axis])*POSTKERNEL_size[axis];
float w = Kernel(rel);
avg += w * textureLod(L2_raw, pos, 0.0) * L2_mul;
W += w;
}
avg /= W;
return avg;
}
//!HOOK POSTKERNEL
//!BIND HOOKED
//!BIND L2
//!SAVE MR
//!WHEN NATIVE_CROPPED.h POSTKERNEL.h >
//!COMPONENTS 4
//!DESC SSimDownscaler mean & R
#define oversharp 0.0
#define sigma_nsq 10. / (255.*255.)
#define locality 2.0
#define offset vec2(0,0)
#define Kernel(x) pow(1.0 / locality, abs(x))
#define taps 3.0
#define Luma(rgb) ( dot(rgb, vec3(0.2126, 0.7152, 0.0722)) )
mat3x3 ScaleH(vec2 pos) {
float low = ceil(-0.5*taps - offset)[0];
float high = floor(0.5*taps - offset)[0];
float W = 0.0;
mat3x3 avg = mat3x3(0);
for (float k = low; k <= high; k++) {
pos[0] = HOOKED_pos[0] + HOOKED_pt[0] * k;
float rel = k + offset[0];
float w = Kernel(rel);
vec3 L = POSTKERNEL_tex(pos).rgb;
avg += w * mat3x3(L, L*L, L2_tex(pos).rgb);
W += w;
}
avg /= W;
return avg;
}
vec4 hook() {
vec2 pos = HOOKED_pos;
float low = ceil(-0.5*taps - offset)[1];
float high = floor(0.5*taps - offset)[1];
float W = 0.0;
mat3x3 avg = mat3x3(0);
for (float k = low; k <= high; k++) {
pos[1] = HOOKED_pos[1] + HOOKED_pt[1] * k;
float rel = k + offset[1];
float w = Kernel(rel);
avg += w * ScaleH(pos);
W += w;
}
avg /= W;
float Sl = Luma(max(avg[1] - avg[0] * avg[0], 0.));
float Sh = Luma(max(avg[2] - avg[0] * avg[0], 0.));
return vec4(avg[0], mix(sqrt((Sh + sigma_nsq) / (Sl + sigma_nsq)) * (1. + oversharp), clamp(Sh / Sl, 0., 1.), int(Sl > Sh)));
}
//!HOOK POSTKERNEL
//!BIND HOOKED
//!BIND MR
//!WHEN NATIVE_CROPPED.h POSTKERNEL.h >
//!DESC SSimDownscaler final pass
#define locality 2.0
#define offset vec2(0,0)
#define Kernel(x) pow(1.0 / locality, abs(x))
#define taps 3.0
#define Gamma(x) ( pow(x, vec3(1.0/2.0)) )
#define GammaInv(x) ( pow(clamp(x, 0.0, 1.0), vec3(2.0)) )
mat3x3 ScaleH(vec2 pos) {
float low = ceil(-0.5*taps - offset)[0];
float high = floor(0.5*taps - offset)[0];
float W = 0.0;
mat3x3 avg = mat3x3(0);
for (float k = low; k <= high; k++) {
pos[0] = HOOKED_pos[0] + HOOKED_pt[0] * k;
float rel = k + offset[0];
float w = Kernel(rel);
vec4 MR = MR_tex(pos);
avg += w * mat3x3(MR.a*MR.rgb, MR.rgb, MR.aaa);
W += w;
}
avg /= W;
return avg;
}
vec4 hook() {
vec2 pos = HOOKED_pos;
float low = ceil(-0.5*taps - offset)[1];
float high = floor(0.5*taps - offset)[1];
float W = 0.0;
mat3x3 avg = mat3x3(0);
for (float k = low; k <= high; k++) {
pos[1] = HOOKED_pos[1] + HOOKED_pt[1] * k;
float rel = k + offset[1];
float w = Kernel(rel);
avg += w * ScaleH(pos);
W += w;
}
avg /= W;
vec4 L = POSTKERNEL_texOff(0);
return vec4(avg[1] + avg[2] * L.rgb - avg[0], L.a);
}
Copy link

ghost commented Oct 25, 2021

I see, thanks for answering. It has been very informative.

@cybergade
Copy link

Made an account to ask this guestion. This is probably unrelated to SSIMDownscaler but the comments above got me asking, when using catmull_rom only (yes, without ssimdownscaler), is it adviseable to use with linear-downscaling=yes?

@igv
Copy link
Author

igv commented Nov 29, 2021

It is advisable to use linear-downscaling=yes only with soft scalers (it was in comments above), and catmull_rom isn't a soft scaler.

@cybergade
Copy link

Ah, i was under the impression that catmull_rom was a softscaler. Thanks for clearing it up.

@yeezylife
Copy link

yeezylife commented Nov 30, 2021

Been testing vo=gpu-next gpu-api=vlukan lately and I accidentlly found out that SSimDownscaler results are very different than it's on vo=gpu gpu-api=d3d11
The dark line in the anime become thicker(also blurer) and you can see "gliches" around the edge

@igv
Copy link
Author

igv commented Nov 30, 2021

Can't reproduce.

@Rafee-M
Copy link

Rafee-M commented Jan 25, 2022

Hi, @igv You had mentioned here that "lanczos with linear-downscaling=no" would give a sharper result.

But you also mentioned here that this is tuned for mitchell.

When downscaling from 3840x2160 to 2560x1440, which one would yield better results?

@igv
Copy link
Author

igv commented Jan 25, 2022

lanczos

@Rafee-M
Copy link

Rafee-M commented Jan 25, 2022

Thank you for your response

@laichiaheng
Copy link

The image in HDR mode becomes oil painting with this one.

@igv
Copy link
Author

igv commented Oct 6, 2022

Can't confirm.

@laichiaheng
Copy link

It doesn't happen anymore, I don't know what happened.

@Zabooby
Copy link

Zabooby commented Dec 28, 2022

Question from #tomasklaen/uosc#405

My mpv config.

My mpv.conf uses profile=gpu-hq which has linear-downscaling=yes by default. I just tried adding ssimds without switching to linear-downscaling=no and it still seems to work, how come?

image

@kasper93
Copy link

kasper93 commented Apr 24, 2023

@igv: Exactly the same pattern/issue in this shader, explained here https://gist.github.com/igv/a015fc885d5c22e6891820ad89555637?permalink_comment_id=4546672#gistcomment-4546672

@@ -12,8 +12,8 @@
 // License along with this library.

 //!HOOK POSTKERNEL
-//!BIND HOOKED
 //!BIND PREKERNEL
+//!BIND HOOKED
 //!SAVE L2
 //!WIDTH NATIVE_CROPPED.w
 //!WHEN NATIVE_CROPPED.h POSTKERNEL.h >
@@ -53,8 +53,8 @@ vec4 hook() {
 }

 //!HOOK POSTKERNEL
-//!BIND HOOKED
 //!BIND L2
+//!BIND HOOKED
 //!SAVE L2
 //!WHEN NATIVE_CROPPED.w POSTKERNEL.w >
 //!COMPONENTS 3

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment