Skip to content

Instantly share code, notes, and snippets.

@igv
Last active September 5, 2024 11:51
Show Gist options
  • Save igv/36508af3ffc84410fe39761d6969be10 to your computer and use it in GitHub Desktop.
Save igv/36508af3ffc84410fe39761d6969be10 to your computer and use it in GitHub Desktop.
Tuned for 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 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.), float(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);
}
@CrHasher
Copy link

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
Copy link
Author

igv commented Sep 27, 2023

Idk, works for me.

@dyphire
Copy link

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
Copy link

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

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
Copy link

yeezylife commented Nov 23, 2023

test
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
Copy link
Author

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.

@ianhattendorf
Copy link

I'm running mpv via the render API (vo=libmpv) in an OpenGL ES 3.2 context, and getting the following error with this shader:

[   2.754][e][libmpv_render] 0:118(22): error: no matching function for call to `mix(float, float, int)'; candidates are:
[   2.754][e][libmpv_render] 0:118(22): error:    float mix(float, float, float)
[   2.754][e][libmpv_render] 0:118(22): error:    vec2 mix(vec2, vec2, float)
...

The following patch gets the shader compiling, and appears to work fine, however I'm no GLSL expert. Are there any downsides to this change? Does it change the shader output/perform worse/etc.? I'm assuming there's a reason int was used over float, but maybe not.

From d048e7c2f052731cbdb0f175e90db01255702729 Mon Sep 17 00:00:00 2001
From: Ian Hattendorf <ian@ianhattendorf.com>
Date: Wed, 4 Sep 2024 10:19:56 -0700
Subject: [PATCH] mix(float, float, int) -> mix(float, float, float) for GLSL
 ES support

---
 SSimDownscaler.glsl | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/SSimDownscaler.glsl b/SSimDownscaler.glsl
index e2ec778..e969b6a 100644
--- a/SSimDownscaler.glsl
+++ b/SSimDownscaler.glsl
@@ -151,7 +151,7 @@ vec4 hook() {
 
     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)));
+    return vec4(avg[0], mix(sqrt((Sh + sigma_nsq) / (Sl + sigma_nsq)) * (1. + oversharp), clamp(Sh / Sl, 0., 1.), float(Sl > Sh)));
 }
 
 //!HOOK POSTKERNEL
-- 
2.46.0

KrigBilateral and SSimSuperRes are working perfectly with OpenGL ES.

Ref:
https://registry.khronos.org/OpenGL-Refpages/es3.0/html/mix.xhtml
https://registry.khronos.org/OpenGL-Refpages/gl4/html/mix.xhtml

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