cvkg-render-gpu 0.3.2

Cyber Viking Kvasir Graph (CVKG) - High-fidelity agentic UI framework
Documentation
//! Tone mapping shader.
//! Converts HDR (Rgba16Float) scene to LDR (Rgba8UnormSrgb) for display.
//! Implements ACES filmic tone mapping with optional P3 color space output.

struct ToneMapUniforms {
    exposure: f32,
    gamma: f32,
    _pad0: f32,
    _pad1: f32,
};

@group(0) @binding(0) var<uniform> uniforms: ToneMapUniforms;
@group(0) @binding(1) var hdr_scene: texture_2d<f32>;
@group(0) @binding(2) var hdr_sampler: sampler;

struct VertexOutput {
    @builtin(position) position: vec4<f32>,
    @location(0) uv: vec2<f32>,
};

@vertex
fn vs_fullscreen(@builtin(vertex_index) vid: u32) -> VertexOutput {
    let pos = vec4<f32>(
        select(vec2<f32>(-1.0, -1.0), vec2<f32>(3.0, -1.0), vid == 1u),
        0.0,
        1.0
    );
    let uv = vec2<f32>(
        select(0.0, 2.0, vid == 1u),
        select(0.0, 2.0, vid > 0u),
    );
    return VertexOutput(pos, uv);
}

// AgX Tonemapping constants and functions.
// Maps high dynamic range scene colors to standard display bounds
// in a perceptually calibrated logarithmic space, preventing highlight shifts.

// Input transform matrix from sRGB to the AgX internal color space
const AGX_IN_MATRIX = mat3x3<f32>(
    vec3<f32>(0.84247906229, 0.07843358840, 0.07922374822),
    vec3<f32>(0.09784776100, 0.84803738020, 0.05413186259),
    vec3<f32>(0.06050045173, 0.07369234857, 0.86617576595)
);

// Output transform matrix back to sRGB display linear space
const AGX_OUT_MATRIX = mat3x3<f32>(
    vec3<f32>(1.19682190398, -0.09702284903, -0.09979925827),
    vec3<f32>(-0.13843969460, 1.20249767228, -0.06405828459),
    vec3<f32>(-0.05838220938, -0.10547482325, 1.16385754286)
);

/// Linear to AgX Logarithmic space conversion
fn linear_to_agx_log(x: vec3<f32>) -> vec3<f32> {
    let min_ev = -10.0;
    let max_ev = 6.5;
    let log_color = log2(clamp(x, vec3<f32>(1e-5), vec3<f32>(65536.0)));
    return clamp((log_color - min_ev) / (max_ev - min_ev), vec3<f32>(0.0), vec3<f32>(1.0));
}

/// Hermite cubic polynomial approximation of the AgX contrast curve
fn agx_contrast_curve(x: vec3<f32>) -> vec3<f32> {
    let x2 = x * x;
    let x3 = x2 * x;
    let x4 = x3 * x;
    let x5 = x4 * x;
    return clamp(
        15.5 * x5 - 40.14 * x4 + 37.96 * x3 - 14.285 * x2 + 1.92 * x + 0.005,
        vec3<f32>(0.0),
        vec3<f32>(1.0)
    );
}

/// Core AgX tonemapping transformation pipeline
fn agx_tonemap(color: vec3<f32>) -> vec3<f32> {
    // 1. Transform to AgX input color space
    let agx_in = transpose(AGX_IN_MATRIX) * color;
    
    // 2. Convert to logarithmic scale
    let log_scale = linear_to_agx_log(agx_in);
    
    // 3. Apply contrast curve
    let curve = agx_contrast_curve(log_scale);
    
    // 4. Transform back to display linear space
    return clamp(transpose(AGX_OUT_MATRIX) * curve, vec3<f32>(0.0), vec3<f32>(1.0));
}

@fragment
fn fs_main(in: VertexOutput) -> @location(0) vec4<f32> {
    let hdr_color = textureSample(hdr_scene, hdr_sampler, in.uv).rgb;

    // Apply exposure
    let exposed = hdr_color * uniforms.exposure;

    // AgX tone mapping
    let mapped = agx_tonemap(exposed);

    // Gamma correction
    let gamma_corrected = pow(mapped, vec3<f32>(1.0 / uniforms.gamma));

    return vec4<f32>(gamma_corrected, 1.0);
}