Skip to main content

NEON

Constant NEON 

Source
pub const NEON: &str = "\nstruct Post {\n    size: vec2<u32>,\n    frame: u32,\n    seed: u32,\n    p0: vec4<f32>,\n    p1: vec4<f32>,\n    p2: vec4<f32>,\n    p3: vec4<f32>,\n    region: vec4<u32>,\n    extent: vec4<u32>,\n}\n\n@group(0) @binding(0) var<uniform> post: Post;\n@group(0) @binding(1) var src_tex: texture_2d<f32>;\n@group(0) @binding(2) var dst_tex: texture_storage_2d<rgba16float, write>;\n\nfn src_dim() -> vec2<u32> {\n    return min(textureDimensions(src_tex), post.extent.xy);\n}\n\nfn load_src(p: vec2<i32>) -> vec4<f32> {\n    let dim = vec2<i32>(src_dim());\n    if (dim.x <= 0 || dim.y <= 0) { return vec4<f32>(0.0); }\n    let c = clamp(p, vec2<i32>(0), dim - vec2<i32>(1));\n    return textureLoad(src_tex, c, 0);\n}\n\nfn sample_src(x: f32, y: f32) -> vec4<f32> {\n    let dim = vec2<f32>(src_dim());\n    if (dim.x < 1.0 || dim.y < 1.0) { return vec4<f32>(0.0); }\n    let xc = clamp(x, 0.0, dim.x - 1.0);\n    let yc = clamp(y, 0.0, dim.y - 1.0);\n    let x0 = i32(floor(xc));\n    let y0 = i32(floor(yc));\n    let tx = xc - floor(xc);\n    let ty = yc - floor(yc);\n    let a = load_src(vec2<i32>(x0, y0));\n    let b = load_src(vec2<i32>(x0 + 1, y0));\n    let c = load_src(vec2<i32>(x0, y0 + 1));\n    let d = load_src(vec2<i32>(x0 + 1, y0 + 1));\n    return mix(mix(a, b, tx), mix(c, d, tx), ty);\n}\n\nfn store(p: vec2<u32>, c: vec4<f32>) {\n    textureStore(dst_tex, p, c);\n}\n\nfn luma(c: vec3<f32>) -> f32 {\n    return dot(c, vec3<f32>(0.2126, 0.7152, 0.0722));\n}\n\nfn luma_at(x: i32, y: i32) -> f32 {\n    return luma(load_src(vec2<i32>(x, y)).rgb);\n}\n\nfn sobel(x: i32, y: i32) -> f32 {\n    let gx = -luma_at(x - 1, y - 1) + luma_at(x + 1, y - 1) - 2.0 * luma_at(x - 1, y) + 2.0 * luma_at(x + 1, y) - luma_at(x - 1, y + 1) + luma_at(x + 1, y + 1);\n    let gy = -luma_at(x - 1, y - 1) - 2.0 * luma_at(x, y - 1) - luma_at(x + 1, y - 1) + luma_at(x - 1, y + 1) + 2.0 * luma_at(x, y + 1) + luma_at(x + 1, y + 1);\n    return sqrt(gx * gx + gy * gy);\n}\n\nfn normalize3(v: vec3<f32>) -> vec3<f32> {\n    let len = length(v);\n    if (len < 1e-8) { return vec3<f32>(0.0, 0.0, 1.0); }\n    return v / len;\n}\n\nfn safe_pow(a: f32, b: f32) -> f32 {\n    if (a <= 0.0) { return 0.0; }\n    return pow(a, b);\n}\n\nfn edge_step(edge0: f32, edge1: f32, x: f32) -> f32 {\n    let span = edge1 - edge0;\n    if (abs(span) < 1e-8) {\n        if (x < edge0) { return 0.0; }\n        return 1.0;\n    }\n    let t = clamp((x - edge0) / span, 0.0, 1.0);\n    return t * t * (3.0 - 2.0 * t);\n}\n\nfn grain_hash(x: u32, y: u32, seed: u32) -> f32 {\n    var h = x * 0x8da6b343u ^ y * 0xd8163841u ^ seed * 0xcb1ab31fu;\n    h = h ^ (h >> 15u);\n    h = h * 0x2c1b3c6du;\n    h = h ^ (h >> 12u);\n    return f32(h >> 8u) / 16777216.0;\n}\n\nfn mixed_seed() -> u32 {\n    return post.seed ^ (post.frame * 0x9e3779b9u);\n}\n\nfn hash21(x: f32, y: f32) -> f32 {\n    var qx = fract(x * 123.34);\n    var qy = fract(y * 456.21);\n    let d = qx * (qx + 45.32) + qy * (qy + 45.32);\n    qx = qx + d;\n    qy = qy + d;\n    return fract(qx * qy);\n}\n\nfn grain_hash_i(x: i32, y: i32, seed: u32) -> f32 {\n    return grain_hash(u32(x), u32(y), seed);\n}\n\nfn value_noise(x: f32, y: f32, seed: u32) -> f32 {\n    let x0 = floor(x);\n    let y0 = floor(y);\n    let tx = x - x0;\n    let ty = y - y0;\n    let sx = tx * tx * (3.0 - 2.0 * tx);\n    let sy = ty * ty * (3.0 - 2.0 * ty);\n    let xi = i32(x0);\n    let yi = i32(y0);\n    let a = grain_hash_i(xi, yi, seed);\n    let b = grain_hash_i(xi + 1, yi, seed);\n    let c = grain_hash_i(xi, yi + 1, seed);\n    let d = grain_hash_i(xi + 1, yi + 1, seed);\n    let ab = a + (b - a) * sx;\n    let cd = c + (d - c) * sx;\n    return ab + (cd - ab) * sy;\n}\n\nfn bayer(x: u32, y: u32) -> f32 {\n    var v = 0u;\n    var xx = x & 7u;\n    var yy = y & 7u;\n    var half = 4u;\n    var mul = 1u;\n    for (var i = 0u; i < 3u; i = i + 1u) {\n        let cx = xx >= half;\n        let cy = yy >= half;\n        if (xx >= half) { xx = xx - half; }\n        if (yy >= half) { yy = yy - half; }\n        var add = 0u;\n        if (cx && !cy) { add = 2u; }\n        else if (!cx && cy) { add = 3u; }\n        else if (cx && cy) { add = 1u; }\n        v = v + add * mul;\n        mul = mul * 4u;\n        half = half / 2u;\n    }\n    return (f32(v) + 0.5) / 64.0;\n}\n\nfn saturate3(c: vec3<f32>, amount: f32) -> vec3<f32> {\n    let l = luma(c);\n    return max(vec3<f32>(l) + (c - vec3<f32>(l)) * amount, vec3<f32>(0.0));\n}\n\nfn quantize(v: f32, levels: f32) -> f32 {\n    let t = clamp(v, 0.0, 1.0);\n    let q = min(floor(t * levels), levels - 1.0);\n    return q / (levels - 1.0);\n}\n\nfn keep_rgb(rgb: vec3<f32>, threshold: f32, knee: f32, knee_width: f32, soft: f32) -> vec3<f32> {\n    let l = max(rgb.r, max(rgb.g, rgb.b));\n    var hard = 0.0;\n    if (l > threshold) { hard = max(l - threshold, 0.0) / max(l, 1e-4); }\n    var knee_t = 0.0;\n    if (knee_width > 1e-6) { knee_t = clamp((l - knee) / knee_width, 0.0, 1.0); }\n    return rgb * (hard + knee_t * knee_t * soft);\n}\n\nfn aces_channel(x: f32) -> f32 {\n    let a = x * (x * 2.51 + 0.03);\n    let b = x * (x * 2.43 + 0.59) + 0.14;\n    if (abs(b) < 1e-8) { return 0.0; }\n    return clamp(a / b, 0.0, 1.0);\n}\n\nfn agx_contrast(x: f32) -> f32 {\n    let x2 = x * x;\n    let x4 = x2 * x2;\n    return 15.5 * x4 * x2 - 40.14 * x4 * x + 31.96 * x4 - 6.868 * x2 * x + 0.4298 * x2 + 0.1191 * x - 0.00232;\n}\n\nfn agx(c: vec3<f32>) -> vec3<f32> {\n    let r0 = vec3<f32>(0.842479062253094, 0.0784335999999992, 0.0792237451477643);\n    let r1 = vec3<f32>(0.0423282422610123, 0.878468636469772, 0.0791661274605434);\n    let r2 = vec3<f32>(0.0423756549057051, 0.0784336, 0.879142973793104);\n    let v = vec3<f32>(dot(r0, c), dot(r1, c), dot(r2, c));\n    let min_ev = -12.47393;\n    let max_ev = 4.026069;\n    let span = max_ev - min_ev;\n    let t0 = clamp((log2(max(v.r, 1e-10)) - min_ev) / span, 0.0, 1.0);\n    let t1 = clamp((log2(max(v.g, 1e-10)) - min_ev) / span, 0.0, 1.0);\n    let t2 = clamp((log2(max(v.b, 1e-10)) - min_ev) / span, 0.0, 1.0);\n    return clamp(vec3<f32>(agx_contrast(t0), agx_contrast(t1), agx_contrast(t2)), vec3<f32>(0.0), vec3<f32>(1.0));\n}\n\nfn neutral_map(c: vec3<f32>, start: f32, toe: f32, desat: f32, clamp_hi: bool) -> vec3<f32> {\n    let low = min(c.r, min(c.g, c.b));\n    var offset = toe;\n    if (low < 0.08) { offset = low - 6.25 * low * low; }\n    var v = c - vec3<f32>(offset);\n    let peak = max(v.r, max(v.g, v.b));\n    if (peak >= start && peak > 1e-8) {\n        let d = 1.0 - start;\n        let denom = peak + d - start;\n        var mapped = start;\n        if (abs(denom) >= 1e-8) { mapped = 1.0 - d * d / denom; }\n        v = v * (mapped / peak);\n        let g = 1.0 - 1.0 / (desat * (peak - mapped) + 1.0);\n        v = mix(v, vec3<f32>(mapped), g);\n    }\n    if (clamp_hi) { v = clamp(v, vec3<f32>(0.0), vec3<f32>(1.0)); }\n    return v;\n}\n\nfn band_shade(light: f32, bands: f32, softness: f32, threshold: f32, shadow: f32) -> f32 {\n    let bands_f = max(bands, 1.0);\n    let light_c = clamp(light, 0.0, 1.0);\n    let x = min(light_c * bands_f, bands_f - 1e-4);\n    var w = 0.0;\n    if (softness > 0.0) { w = edge_step(0.5 - softness * 0.5, 0.5 + softness * 0.5, fract(x)); }\n    let idx = floor(x) + w;\n    var q = light_c;\n    if (bands_f > 1.0) { q = clamp(idx / (bands_f - 1.0), 0.0, 1.0); }\n    var gate = 1.0;\n    if (softness <= 1e-5) {\n        if (light_c < threshold) { gate = 0.0; }\n    } else {\n        gate = edge_step(threshold - softness, threshold + softness, light_c);\n    }\n    return q * (shadow + (1.0 - shadow) * gate);\n}\n\nfn palette(i: u32) -> vec3<f32> {\n    if (i == 0u) { return vec3<f32>(0.0, 0.0, 0.0); }\n    if (i == 1u) { return vec3<f32>(0.0122865, 0.0241576, 0.0865005); }\n    if (i == 2u) { return vec3<f32>(0.208637, 0.0185002, 0.0865005); }\n    if (i == 3u) { return vec3<f32>(0.0, 0.242281, 0.0822827); }\n    if (i == 4u) { return vec3<f32>(0.40724, 0.0843762, 0.0368895); }\n    if (i == 5u) { return vec3<f32>(0.114435, 0.0953075, 0.0781874); }\n    if (i == 6u) { return vec3<f32>(0.539479, 0.545724, 0.571125); }\n    if (i == 7u) { return vec3<f32>(1.0, 0.879622, 0.806952); }\n    if (i == 8u) { return vec3<f32>(1.0, 0.0, 0.0742136); }\n    if (i == 9u) { return vec3<f32>(1.0, 0.366253, 0.0); }\n    if (i == 10u) { return vec3<f32>(1.0, 0.838799, 0.0202886); }\n    if (i == 11u) { return vec3<f32>(0.0, 0.775822, 0.0368895); }\n    if (i == 12u) { return vec3<f32>(0.0221739, 0.417885, 1.0); }\n    if (i == 13u) { return vec3<f32>(0.226966, 0.181164, 0.332452); }\n    if (i == 14u) { return vec3<f32>(1.0, 0.184475, 0.391572); }\n    return vec3<f32>(1.0, 0.603827, 0.401978);\n}\n\nfn nearest_palette(c: vec3<f32>) -> vec3<f32> {\n    var best = palette(0u);\n    var best_d = 1e30;\n    for (var i = 0u; i < 16u; i = i + 1u) {\n        let swatch = palette(i);\n        let d = dot(c - swatch, c - swatch);\n        if (d < best_d) { best_d = d; best = swatch; }\n    }\n    return best;\n}\n\nfn encode_channel(c: f32) -> f32 {\n    if (c <= 0.0031308) { return c * 12.92; }\n    return 1.055 * safe_pow(max(c, 0.0), 1.0 / 2.4) - 0.055;\n}\n\nfn gaussian(p: vec2<u32>, dirx: i32, diry: i32, radius: u32, spread: f32) -> vec4<f32> {\n    var acc = vec4<f32>(0.0);\n    var total = 0.0;\n    var s = spread;\n    if (s <= 1e-4) { s = 1.0; }\n    let r = i32(min(radius, 64u));\n    for (var k = -r; k <= r; k = k + 1) {\n        let w = exp(-f32(k * k) / s);\n        acc = acc + load_src(vec2<i32>(i32(p.x) + k * dirx, i32(p.y) + k * diry)) * w;\n        total = total + w;\n    }\n    return acc / max(total, 1e-8);\n}\n\nfn ring_radius(ring: u32) -> f32 {\n    if (ring == 0u) { return post.p1.x; }\n    if (ring == 1u) { return post.p1.y; }\n    if (ring == 2u) { return post.p1.z; }\n    return post.p1.w;\n}\n\nfn ring_gain(ring: u32) -> f32 {\n    if (ring == 0u) { return post.p2.x; }\n    if (ring == 1u) { return post.p2.y; }\n    if (ring == 2u) { return post.p2.z; }\n    return post.p2.w;\n}\n\nfn ring_channel(c: f32, threshold: f32, clamp_hi: f32) -> f32 {\n    var v = max(c - threshold, 0.0);\n    if (clamp_hi > 0.0) { v = min(v, clamp_hi); }\n    return v;\n}\n\n@compute @workgroup_size(8, 8)\nfn main(@builtin(global_invocation_id) id: vec3<u32>) {\n    let dst_dim = textureDimensions(dst_tex);\n    let scissor = post.region.z != 0u;\n    let p = select(id.xy, id.xy + post.region.xy, scissor);\n    if (scissor && (p.x >= post.region.z || p.y >= post.region.w)) { return; }\n    if (p.x >= dst_dim.x || p.y >= dst_dim.y) { return; }\n    if (post.size.x != 0u && (p.x >= post.size.x || p.y >= post.size.y)) { return; }\n    let src = load_src(vec2<i32>(p));\n\n    let center = saturate3(src.rgb, post.p0.x);\n    let radius_full = u32(max(post.p0.z, 0.0));\n    let radius = min(radius_full, 8u);\n    if (radius == 0u || abs(post.p0.y) < 1e-8) { store(p, vec4<f32>(center, src.a)); return; }\n    let spread = f32(max(radius_full, 1u)) * 6.0;\n    var acc = vec3<f32>(0.0);\n    var weight = 0.0;\n    for (var dy = -8; dy <= 8; dy = dy + 1) {\n        for (var dx = -8; dx <= 8; dx = dx + 1) {\n            if (u32(abs(dx)) > radius || u32(abs(dy)) > radius) { continue; }\n            let e = clamp(sobel(i32(p.x) + dx, i32(p.y) + dy), 0.0, 4.0);\n            let s = saturate3(load_src(vec2<i32>(i32(p.x) + dx, i32(p.y) + dy)).rgb, post.p0.x);\n            let w = exp(-f32(dx * dx + dy * dy) / spread);\n            acc = acc + s * e * w;\n            weight = weight + w;\n        }\n    }\n    var glow = vec3<f32>(0.0);\n    if (weight > 1e-8) { glow = acc / weight; }\n    store(p, vec4<f32>(center + glow * post.p0.y, src.a));\n\n}\n";