SHADER_SOURCE

Constant SHADER_SOURCE 

Source
pub const SHADER_SOURCE: &str = r"
#include <metal_stdlib>
using namespace metal;

struct Uniforms {
    float2 viewport_size;
    float2 texture_size;
    float time;
    uint pixel_format;
    float padding[2];
};

struct TexturedVertexOut {
    float4 position [[position]];
    float2 texcoord;
};

// Fullscreen quad vertex shader with aspect ratio correction
vertex TexturedVertexOut vertex_fullscreen(uint vid [[vertex_id]], constant Uniforms& uniforms [[buffer(0)]]) {
    TexturedVertexOut out;
    float va = uniforms.viewport_size.x / uniforms.viewport_size.y;
    float ta = uniforms.texture_size.x / uniforms.texture_size.y;
    float sx = ta > va ? 1.0 : ta / va;
    float sy = ta > va ? va / ta : 1.0;
    float2 positions[4] = { float2(-sx, -sy), float2(sx, -sy), float2(-sx, sy), float2(sx, sy) };
    float2 texcoords[4] = { float2(0.0, 1.0), float2(1.0, 1.0), float2(0.0, 0.0), float2(1.0, 0.0) };
    out.position = float4(positions[vid], 0.0, 1.0);
    out.texcoord = texcoords[vid];
    return out;
}

// BGRA/RGB texture fragment shader
fragment float4 fragment_textured(TexturedVertexOut in [[stage_in]], texture2d<float> tex [[texture(0)]]) {
    constexpr sampler s(mag_filter::linear, min_filter::linear);
    return tex.sample(s, in.texcoord);
}

// YCbCr to RGB conversion (BT.709 matrix for HD video)
float4 ycbcr_to_rgb(float y, float2 cbcr, bool full_range) {
    float y_adj = full_range ? y : (y - 16.0/255.0) * (255.0/219.0);
    float cb = cbcr.x - 0.5;
    float cr = cbcr.y - 0.5;
    // BT.709 conversion matrix
    float r = y_adj + 1.5748 * cr;
    float g = y_adj - 0.1873 * cb - 0.4681 * cr;
    float b = y_adj + 1.8556 * cb;
    return float4(saturate(float3(r, g, b)), 1.0);
}

// YCbCr biplanar (420v/420f) fragment shader
fragment float4 fragment_ycbcr(TexturedVertexOut in [[stage_in]], 
    texture2d<float> y_tex [[texture(0)]], 
    texture2d<float> cbcr_tex [[texture(1)]],
    constant Uniforms& uniforms [[buffer(0)]]) {
    constexpr sampler s(mag_filter::linear, min_filter::linear);
    float y = y_tex.sample(s, in.texcoord).r;
    float2 cbcr = cbcr_tex.sample(s, in.texcoord).rg;
    bool full_range = (uniforms.pixel_format == 0x34323066); // '420f'
    return ycbcr_to_rgb(y, cbcr, full_range);
}

// Colored vertex input/output for UI overlays
struct ColoredVertex {
    float2 position [[attribute(0)]];
    float4 color [[attribute(1)]];
};

struct ColoredVertexOut {
    float4 position [[position]];
    float4 color;
};

// Colored vertex shader for UI elements (position in pixels, converted to NDC)
vertex ColoredVertexOut vertex_colored(ColoredVertex in [[stage_in]], constant Uniforms& uniforms [[buffer(1)]]) {
    ColoredVertexOut out;
    float2 ndc = (in.position / uniforms.viewport_size) * 2.0 - 1.0;
    ndc.y = -ndc.y;
    out.position = float4(ndc, 0.0, 1.0);
    out.color = in.color;
    return out;
}

// Colored fragment shader for UI elements
fragment float4 fragment_colored(ColoredVertexOut in [[stage_in]]) {
    return in.color;
}
";
Expand description

Metal shader source for rendering captured frames

This shader supports:

  • BGRA and BGR10A2 single-plane formats
  • YCbCr 4:2:0 biplanar formats (420v and 420f)
  • Aspect-ratio-preserving fullscreen quad

§Uniforms

The shader expects a Uniforms buffer:

  • viewport_size: float2 - Current viewport dimensions
  • texture_size: float2 - Source texture dimensions
  • time: float - Animation time (optional)
  • pixel_format: uint - FourCC pixel format code

§Usage

  1. Compile shader with device.new_library_with_source(SHADER_SOURCE, ...)
  2. Create pipeline with vertex_fullscreen + fragment_textured (for BGRA/L10R)
  3. Or use vertex_fullscreen + fragment_ycbcr (for 420v/420f)
  4. Bind plane0 to texture slot 0, plane1 to texture slot 1 (for YCbCr)