cvkg-render-gpu 0.1.22

Cyber Viking Kvasir Graph (CVKG) - High-fidelity agentic UI framework
Documentation
// =============================================================================
// Dual Kawase Blur Pyramid — Backdrop Capture Architecture
// =============================================================================
//
// This shader implements a Dual Kawase Blur for generating a mip-chain
// backdrop pyramid used by glass/frosted-ui elements.
//
// Modes:
//   0 = Downsample (read from mip N, write to mip N+1, offset = iteration)
//   1 = Upsample   (read from mip N+1, accumulate into mip N, offset = iteration)
//   2 = Composite  (sample blurred backdrop by blur_radius, blend over glass quad)
//
// The Kawase offset pattern uses a diagonal cross kernel:
//   offsets = [(+o,+o), (-o,+o), (-o,-o), (+o,-o)]
// where o = iteration_index, producing increasingly wide sampling.
//
// =============================================================================

// Re-use the shared uniforms and fullscreen vertex from common.wgsl.
// This shader must be #included by the pipeline shader or compiled standalone.
// For standalone pipeline compilation, we define our own bindings.

struct BlurUniforms {
    // xy = src_texture_size (for computing texel UV step)
    // z = mip_level being written
    // w = kernel_width (Kawase offset = iteration index)
    params:       vec4<f32>,
    mode:         u32,      // 0=down, 1=up, 2=composite
    _pad0:        u32,
    _pad1:        u32,
    _pad2:        u32,
};

@Override
group(0) @binding(0) var<uniform> blur: BlurUniforms;

// Source texture (the mip level to read from)
@group(0) @binding(1) var t_src: texture_2d<f32>;
@group(0) @binding(2) var s_src: sampler;

// --- Fullscreen triangle vertex ---
struct BlurVertexOutput {
    @builtin(position) position: vec4<f32>,
    @location(0)             texcoord: vec2<f32>,
};

@vertex
fn vs_blur(@builtin(vertex_index) idx: u32) -> BlurVertexOutput {
    var out: BlurVertexOutput;
    let x = f32(i32(idx) / 2) * 4.0 - 1.0;
    let y = f32(i32(idx) % 2) * 4.0 - 1.0;
    out.position = vec4<f32>(x, y, 0.0, 1.0);
    out.texcoord = vec2<f32>((x + 1.0) * 0.5, (1.0 - y) * 0.5);
    return out;
}

// --- Kawase Downsample Fragment ---
// Reads 4 diagonal taps from current mip, writes to next mip (half res).
// Each invocation covers one output pixel; offset = blur_params.w
@fragment
fn fs_kawase_down(in: BlurVertexOutput) -> @location(0) vec4<f32> {
    let texel = 1.0 / blur.params.xy;
    let offset = blur.params.w;

    // Kawase diagonal offsets: 4-tap sparse kernel
    let o = offset * texel;
    var c = vec4<f32>(0.0);
    c += textureSample(t_src, s_src, in.texcoord + vec2<f32>( o.x,  o.y));
    c += textureSample(t_src, s_src, in.texcoord + vec2<f32>(-o.x,  o.y));
    c += textureSample(t_src, s_src, in.texcoord + vec2<f32>(-o.x, -o.y));
    c += textureSample(t_src, s_src, in.texcoord + vec2<f32>( o.x, -o.y));

    return c * 0.25;
}

// --- Kawase Upsample Fragment ---
// Reads 4 diagonal taps from higher mip (N+1), accumulates into current mip (N).
@fragment
fn fs_kawase_up(in: BlurVertexOutput) -> @location(0) vec4<f32> {
    let texel = 1.0 / blur.params.xy;
    let offset = blur.params.w;

    // Same diagonal pattern but we may use a wider offset for upsample
    let o = offset * texel;
    var c = vec4<f32>(0.0);
    c += textureSample(t_src, s_src, in.texcoord + vec2<f32>( o.x,  o.y));
    c += textureSample(t_src, s_src, in.texcoord + vec2<f32>(-o.x,  o.y));
    c += textureSample(t_src, s_src, in.texcoord + vec2<f32>(-o.x, -o.y));
    c += textureSample(t_src, s_src, in.texcoord + vec2<f32>( o.x, -o.y));

    return c * 0.25;
}