Skip to content

Instantly share code, notes, and snippets.

# igv/SSimDownscaler.glsl

Last active December 28, 2023 21:41
Star You must be signed in to star a gist
Tuned for linear-downscaling=no.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
 // 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 PREKERNEL //!BIND HOOKED //!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 L2 //!BIND HOOKED //!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); }

### yeezylife commented Oct 13, 2021 • edited

Noticed that you've updated several shaders these days.Cool!

Can be used with sharp scalers now (finally able to suppress ringing artifacts).

Any chance to tell us what's the recomonded dscale algos now(to use with SSimDownscaler)... spline36,lanczos,ewa_lanczossharp?

### igv commented Oct 13, 2021

As always - catmull_rom or mitchell.

### yeezylife commented Oct 13, 2021

Thanks for replying,I misunderstood the level of sharpness...

### igv commented Oct 13, 2021

lanczos is a good choice too - less aliased than catmull_rom / mitchell.

### yeezylife commented Oct 13, 2021

Can I use spline36 with SSimDownscaler now(Since "lanczos is a good choice too")?I thought it has less ringing than lanczos,and less aliasing than catmull_rom / mitchell(but sharper).

Sure.

### ghost commented Oct 25, 2021

My downscaling factor is <2x, should I use SSIMDownscaler or just something like lanczos or catrom? Which gives the "best" results?

### igv commented Oct 25, 2021

lanczos with `linear-downscaling=no`

Thanks

### ghost commented Oct 25, 2021

By the way if I may ask, what is the reason you chose lancos over mitchell, catrom and other sane dscale algos? Is it because it produces the most perceived sharpness and is the least aliased of the three? If so, what about artifacts?

### yeezylife commented Oct 25, 2021

I guess when your downscaling factor is <2x , the ringing artifacts that lanczos might cause wasn't that visible without zoom in.

### igv commented Oct 25, 2021

Is it because it produces the most perceived sharpness and is the least aliased of the three?

Yes.

what about artifacts?

Ringing artifacts not perceivable with gamma light. And, after the latest update, SSimDownscaler blurs them instead of over-sharpening.

### ghost commented Oct 25, 2021

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

### cybergade commented Nov 29, 2021

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 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 commented Nov 29, 2021

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

### yeezylife commented Nov 30, 2021 • edited by igv

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

Can't reproduce.

### Rafee-M commented Jan 25, 2022 • edited

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 commented Jan 25, 2022

`lanczos`

### Rafee-M commented Jan 25, 2022 • edited

Thank you for your response

### laichiaheng commented Oct 6, 2022

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

Can't confirm.

### laichiaheng commented Oct 6, 2022

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

### 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?

### kasper93 commented Apr 24, 2023 • edited

@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```

### CrHasher commented Sep 25, 2023

Not sure what happened to this shader but from my testing something is really off, I get a water effect on the walls in the image

ewa_lanczossharp:

SSimD:

This is the end result of something not working in this shader as expected:

I'm using `vo=gpu-next` and nothing else truly special in the config other than FSRCNNX + Krig

### igv commented Sep 25, 2023

Nothing has changed in this shader either. Have you tried with `vo=gpu`?

### CrHasher commented Sep 25, 2023

Will try to test tomorrow.

### CrHasher commented Sep 26, 2023

I tried vo=gpu does not apply any shaders like vo=gpu-next when using images for testing like I do. Tested both with master and stable. Dead end.

### igv commented Sep 27, 2023 • edited

Idk, works for me.

### dyphire commented Oct 14, 2023

I'm using `vo=gpu-next` and nothing else truly special in the config other than FSRCNNX + Krig

mpv is currently enabled `linear-downscaling` by default: mpv-player/mpv@8121d41. Have you tested it correctly with disabled `linear-downscaling`?

### CrHasher commented Oct 14, 2023 • edited

I'm using `vo=gpu-next` and nothing else truly special in the config other than FSRCNNX + Krig

mpv is currently enabled `linear-downscaling` by default: mpv-player/mpv@8121d41. Have you tested it correctly with disabled `linear-downscaling`?

Yes I have `linear-downscaling≠no` I truly think its not worth turning on linear downscaling and the ringing it results in even with EWA scalers. I will have to test more when I have time bc. right now SSimD gets worst score on any IQA test, and it should be way higher in those tests.

### yeezylife commented Nov 23, 2023 • edited

Will have 2 "unknown shader" process if I add SSIMDownscaler in the conf and it doesn't kick in. And it doesn't seems to happen with other shaders.

glsl-shaders="/shaders/CfL_Prediction.glsl;/shaders/SSimDownscaler.glsl"

### igv commented Nov 23, 2023

No idea what is going on. Only happens when no upscaling or downscaling, but it clearly shouldn't. Ask mpv devs.

### kasper93 commented Nov 24, 2023

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