aboutsummaryrefslogtreecommitdiff
path: root/src/video_core/host_shaders/present_lanczos.frag
blob: ed51ae6d088ffffca38b0eef191dcb327a4de42a (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later

// https://en.wikipedia.org/wiki/Lanczos_resampling

#version 460 core

layout (location = 0) in vec2 frag_tex_coord;
layout (location = 0) out vec4 color;
layout (binding = 0) uniform sampler2D color_texture;

#define PI 3.1415926535897932384626433
float sinc(float x) {
    return x == 0.0f ? 1.0f : sin(PI * x) / (PI * x);
}
float lanczos(vec2 v, float a) {
    float d = length(v);
    return sinc(d) / sinc(d / a);
}
vec4 textureLanczos(sampler2D textureSampler, vec2 p) {
    vec3 c_sum = vec3(0.0f);
    float w_sum = 0.0f;
    vec2 res = vec2(textureSize(textureSampler, 0));
    vec2 cc = floor(p * res) / res;
    // kernel size = (2r + 1)^2
    const int r = 3; //radius (1 = 3 steps)
#define LANCZOS_LOOP_STEP(x, y) \
    { \
        vec2 kp = 0.5f * (vec2(x, y) / res); /* 0.5 = half-pixel level resampling */ \
        vec2 uv = cc + kp; \
        float w = lanczos(kp, float(r)); \
        c_sum += w * texture(textureSampler, p + kp).rgb; \
        w_sum += w; \
    }

    for (int y = -r; y <= r; ++y) {
        LANCZOS_LOOP_STEP(-3, y);
        LANCZOS_LOOP_STEP(-2, y);
        LANCZOS_LOOP_STEP(-1, y);
        LANCZOS_LOOP_STEP(-0, y);
        LANCZOS_LOOP_STEP(+1, y);
        LANCZOS_LOOP_STEP(+2, y);
        LANCZOS_LOOP_STEP(+3, y);
    }
    return vec4(c_sum / w_sum, 1.0f);
}

void main() {
    color = textureLanczos(color_texture, frag_tex_coord);
}