Skip to main content

WGSL

Constant WGSL 

Source
pub const WGSL: &str = r#"
struct Upscale {
    content: vec4f,
    source: vec2f,
    mode: u32,
    transfer: u32,
    bars: vec4f,
    backdrop: u32,
    pad0: u32,
    pad1: u32,
    pad2: u32,
}

@group(0) @binding(0) var upscale_source: texture_2d<f32>;
@group(0) @binding(1) var<uniform> upscale: Upscale;

@vertex
fn upscale_vertex(@builtin(vertex_index) index: u32) -> @builtin(position) vec4f {
    let xy = array<vec2f, 3>(vec2f(-1.0, -1.0), vec2f(3.0, -1.0), vec2f(-1.0, 3.0));
    return vec4f(xy[index], 0.0, 1.0);
}

fn upscale_texel(p: vec2i) -> vec4f {
    let last = vec2i(upscale.source) - vec2i(1);
    return textureLoad(upscale_source, clamp(p, vec2i(0), last), 0);
}

fn upscale_weights(t: f32) -> vec4f {
    let t2 = t * t;
    let t3 = t2 * t;
    return vec4f(
        0.5 * (-t3 + 2.0 * t2 - t),
        0.5 * (3.0 * t3 - 5.0 * t2 + 2.0),
        0.5 * (-3.0 * t3 + 4.0 * t2 + t),
        0.5 * (t3 - t2),
    );
}

fn upscale_decode(c: vec3f) -> vec3f {
    return select(pow((c + vec3f(0.055)) / 1.055, vec3f(2.4)), c / 12.92, c <= vec3f(0.04045));
}

fn upscale_encode(c: vec3f) -> vec3f {
    let v = max(c, vec3f(0.0));
    return select(1.055 * pow(v, vec3f(1.0 / 2.4)) - vec3f(0.055), v * 12.92, v <= vec3f(0.0031308));
}

fn upscale_transfer(c: vec4f) -> vec4f {
    if (upscale.transfer == 1u) {
        return vec4f(upscale_decode(c.rgb), c.a);
    }
    if (upscale.transfer == 2u) {
        return vec4f(upscale_encode(c.rgb), c.a);
    }
    return c;
}

@fragment
fn upscale_fragment(@builtin(position) position: vec4f) -> @location(0) vec4f {
    let c = upscale.content;
    let p = position.xy;
    if (p.x < c.x || p.y < c.y || p.x >= c.x + c.z || p.y >= c.y + c.w) {
        if (upscale.backdrop == 1u) {
            discard;
        }
        return upscale.bars;
    }
    return upscale_transfer(upscale_filtered(p));
}

fn upscale_filtered(p: vec2f) -> vec4f {
    let c = upscale.content;
    let uv = (p - c.xy) / c.zw * upscale.source - vec2f(0.5);
    if (upscale.mode == 1u) {
        return upscale_texel(vec2i(floor(uv + vec2f(0.5))));
    }
    let base = floor(uv);
    let f = uv - base;
    let wx = upscale_weights(f.x);
    let wy = upscale_weights(f.y);
    let b = vec2i(base);
    var sum = vec4f(0.0);
    for (var j = 0; j < 4; j++) {
        var row = vec4f(0.0);
        for (var i = 0; i < 4; i++) {
            row += upscale_texel(b + vec2i(i - 1, j - 1)) * wx[i];
        }
        sum += row * wy[j];
    }
    let t00 = upscale_texel(b);
    let t10 = upscale_texel(b + vec2i(1, 0));
    let t01 = upscale_texel(b + vec2i(0, 1));
    let t11 = upscale_texel(b + vec2i(1, 1));
    let lo = min(min(t00, t10), min(t01, t11));
    let hi = max(max(t00, t10), max(t01, t11));
    return clamp(sum, lo, hi);
}
"#;