// Full-screen blit of the guest frontbuffer texture, with aspect-ratio
// letterboxing. A three-vertex fullscreen triangle covers the viewport; the
// fragment shader samples the frontbuffer and emits sRGB colors directly,
// letting the swapchain handle the final gamma step.

struct Uniforms {
    // aspect_correction.xy = scaling factors applied to the clip-space
    // position to letterbox the frontbuffer into the swapchain window.
    aspect_correction: vec2<f32>,
    // tint for when the frontbuffer is missing / unknown format. When the
    // guest has not yet swapped a frame, CPU side uploads a 1x1 texture and
    // we just want the background color.
    fallback_rgb: vec3<f32>,
    _pad: f32,
};

@group(0) @binding(0) var<uniform> u: Uniforms;
@group(0) @binding(1) var frontbuffer: texture_2d<f32>;
@group(0) @binding(2) var samp: sampler;

struct VsOut {
    @builtin(position) clip: vec4<f32>,
    @location(0) uv: vec2<f32>,
    @location(1) in_bounds: f32,
};

@vertex
fn vs_main(@builtin(vertex_index) vid: u32) -> VsOut {
    // Fullscreen triangle: (-1,-1), (3,-1), (-1,3).
    var pos = array<vec2<f32>, 3>(
        vec2<f32>(-1.0, -1.0),
        vec2<f32>( 3.0, -1.0),
        vec2<f32>(-1.0,  3.0),
    );
    let p = pos[vid];
    // Scale by the aspect-correction factor so the frontbuffer stays at its
    // native aspect inside the window.
    let corrected = p * u.aspect_correction;
    var out: VsOut;
    out.clip = vec4<f32>(corrected, 0.0, 1.0);
    // UV runs [0,1] across the unscaled fullscreen triangle's extent
    // [(-1,-1), (3,-1), (-1,3)] → UV = (p+1)*0.5 mapped with Y flipped.
    let uv_raw = (p + vec2<f32>(1.0, 1.0)) * 0.5;
    out.uv = vec2<f32>(uv_raw.x, 1.0 - uv_raw.y);
    // Also pass a flag telling the FS whether the original position (before
    // aspect correction) was inside [-1,1]; outside = letterbox region.
    let in_bounds = f32(all(abs(corrected) <= vec2<f32>(1.0, 1.0)));
    out.in_bounds = in_bounds;
    return out;
}

@fragment
fn fs_main(in: VsOut) -> @location(0) vec4<f32> {
    if (in.uv.x < 0.0 || in.uv.x > 1.0 || in.uv.y < 0.0 || in.uv.y > 1.0) {
        return vec4<f32>(u.fallback_rgb, 1.0);
    }
    let sample = textureSample(frontbuffer, samp, in.uv);
    return vec4<f32>(sample.rgb, 1.0);
}
