pub(crate) const PLANAR_RGB_F16_PACKED_FRAGMENT: &str = r#"#version 300 es
precision highp float;
precision highp int;
uniform sampler2D src;
uniform vec2 dst_image_size; // (W, H) — destination plane size
uniform vec4 src_rect_uv; // (origin_u, origin_v, size_u, size_v)
uniform vec4 src_extent; // (u_min, v_min, u_max, v_max) a sample may reach
uniform vec4 dst_rect_px; // (origin_x, origin_y, w, h) within one plane
uniform vec4 pad_color; // per-channel pad value as written (RGBA)
uniform vec4 norm_scale; // output = sample * norm_scale + norm_offset
uniform vec4 norm_offset;
out vec4 frag;
// Sample one planar element. Returns the per-channel value at
// (in_plane_x, in_plane_y) for the given plane (0=R, 1=G, 2=B, 3=A).
// Pad value is returned when (in_plane_x, in_plane_y) is outside
// `dst_rect_px`.
float sample_planar_element(float in_plane_x, float in_plane_y, float plane) {
bool inside_dst = (in_plane_x >= dst_rect_px.x) &&
(in_plane_x < dst_rect_px.x + dst_rect_px.z) &&
(in_plane_y >= dst_rect_px.y) &&
(in_plane_y < dst_rect_px.y + dst_rect_px.w);
if (inside_dst) {
float u = (in_plane_x - dst_rect_px.x) / dst_rect_px.z;
float v = (in_plane_y - dst_rect_px.y) / dst_rect_px.w;
vec2 src_uv = clamp(src_rect_uv.xy + vec2(u, v) * src_rect_uv.zw,
src_extent.xy, src_extent.zw);
vec4 rgba = texture(src, src_uv) * norm_scale + norm_offset;
if (plane < 0.5) {
return rgba.r;
} else if (plane < 1.5) {
return rgba.g;
} else if (plane < 2.5) {
return rgba.b;
} else {
return rgba.a;
}
} else {
if (plane < 0.5) {
return pad_color.r;
} else if (plane < 1.5) {
return pad_color.g;
} else if (plane < 2.5) {
return pad_color.b;
} else {
return pad_color.a;
}
}
}
void main() {
// gl_FragCoord is at pixel center (n+0.5). Floor for the integer
// index of the output pixel on the (W/4 × 3H) surface.
int ox = int(floor(gl_FragCoord.x));
int oy = int(floor(gl_FragCoord.y));
float plane = floor(float(oy) / dst_image_size.y);
float in_plane_y = float(oy) - plane * dst_image_size.y + 0.5;
// Sample 4 consecutive in-plane x positions. Pixel center is
// (x+0.5) so the first element of pixel `ox` starts at logical
// tensor column `ox*4` — add 0.5 for the texel center sampled
// by the bilinear filter.
float base_x = float(ox * 4) + 0.5;
float e0 = sample_planar_element(base_x + 0.0, in_plane_y, plane);
float e1 = sample_planar_element(base_x + 1.0, in_plane_y, plane);
float e2 = sample_planar_element(base_x + 2.0, in_plane_y, plane);
float e3 = sample_planar_element(base_x + 3.0, in_plane_y, plane);
// An RGBA16F attachment narrows each f32 to f16 on write; an RGBA32F
// one keeps it. Either way the resulting byte layout in the surface is
// exactly the [C, H, W] planar order the consumer expects.
frag = vec4(e0, e1, e2, e3);
}
"#;
pub(crate) const FLOAT_NHWC_PACKED_FRAGMENT: &str = r#"#version 300 es
precision highp float;
precision highp int;
uniform sampler2D src;
uniform vec4 src_rect_uv; // (origin_u, origin_v, size_u, size_v)
uniform vec4 src_extent; // (u_min, v_min, u_max, v_max) a sample may reach
uniform vec4 dst_rect_px; // (origin_x, origin_y, w, h) in pixel space
uniform vec4 pad_color; // per-channel pad value as written (RGBA)
uniform vec4 norm_scale; // output = sample * norm_scale + norm_offset
uniform vec4 norm_offset;
out vec4 frag;
// Sample one element of the interleaved [H, W, 3] stream. `element` is the
// element's index within its row, `oy` the destination row; the pad value is
// returned when the element's pixel lies outside `dst_rect_px`.
float sample_interleaved_element(int element, int oy) {
int px = element / 3;
int channel = element - px * 3;
float fx = float(px);
float fy = float(oy);
bool inside_dst = (fx >= dst_rect_px.x) &&
(fx < dst_rect_px.x + dst_rect_px.z) &&
(fy >= dst_rect_px.y) &&
(fy < dst_rect_px.y + dst_rect_px.w);
if (!inside_dst) {
return (channel == 0) ? pad_color.r
: (channel == 1) ? pad_color.g : pad_color.b;
}
// Pixel center (+0.5) so LINEAR filtering resamples about the right
// point, matching the F32 NHWC PBO shader.
float u = (fx + 0.5 - dst_rect_px.x) / dst_rect_px.z;
float v = (fy + 0.5 - dst_rect_px.y) / dst_rect_px.w;
vec2 src_uv = clamp(src_rect_uv.xy + vec2(u, v) * src_rect_uv.zw,
src_extent.xy, src_extent.zw);
vec4 rgba = texture(src, src_uv) * norm_scale + norm_offset;
return (channel == 0) ? rgba.r
: (channel == 1) ? rgba.g : rgba.b;
}
void main() {
// gl_FragCoord is at pixel center (n+0.5). Floor for the integer index
// of the output texel on the (W*3/4 x H) surface.
int ox = int(floor(gl_FragCoord.x));
int oy = int(floor(gl_FragCoord.y));
int base = ox * 4;
frag = vec4(sample_interleaved_element(base + 0, oy),
sample_interleaved_element(base + 1, oy),
sample_interleaved_element(base + 2, oy),
sample_interleaved_element(base + 3, oy));
}
"#;
pub(crate) const FLOAT_RGBA_FRAGMENT: &str = r#"#version 300 es
precision highp float;
precision highp int;
uniform sampler2D src;
uniform vec4 src_rect_uv; // (origin_u, origin_v, size_u, size_v)
uniform vec4 src_extent; // (u_min, v_min, u_max, v_max) a sample may reach
uniform vec4 dst_rect_px; // (origin_x, origin_y, w, h) in pixel space
uniform vec4 pad_color; // per-channel pad value as written (RGBA)
uniform vec4 norm_scale; // output = sample * norm_scale + norm_offset
uniform vec4 norm_offset;
out vec4 color;
void main() {
float px = float(int(floor(gl_FragCoord.x)));
float py = float(int(floor(gl_FragCoord.y)));
bool inside_dst = (px >= dst_rect_px.x) &&
(px < dst_rect_px.x + dst_rect_px.z) &&
(py >= dst_rect_px.y) &&
(py < dst_rect_px.y + dst_rect_px.w);
if (!inside_dst) {
color = pad_color;
return;
}
// Pixel center (+0.5), as in the packed float shaders.
float u = (px + 0.5 - dst_rect_px.x) / dst_rect_px.z;
float v = (py + 0.5 - dst_rect_px.y) / dst_rect_px.w;
vec2 src_uv = clamp(src_rect_uv.xy + vec2(u, v) * src_rect_uv.zw,
src_extent.xy, src_extent.zw);
color = texture(src, src_uv) * norm_scale + norm_offset;
}
"#;
pub(crate) const VERTEX_SHADER: &str = "\
#version 300 es
precision mediump float;
layout(location = 0) in vec3 pos;
layout(location = 1) in vec2 texCoord;
out vec3 fragPos;
out vec2 tc;
void main() {
fragPos = pos;
tc = texCoord;
gl_Position = vec4(pos, 1.0);
}
";
macro_rules! nv_colorimetry {
() => {
"// Per-tensor colorimetry (YUV→RGB matrix + range), set by draw_nv_texture_2d
// from the source tensor's resolved colorimetry. Path B applies the matrix in
// the shader, so it is correct regardless of driver EGL color-hint support.
uniform float y_offset;
uniform float y_scale;
uniform float c_vr;
uniform float c_ug;
uniform float c_vg;
uniform float c_ub;
"
};
}
macro_rules! nv_yuv_to_rgb_fn {
() => {
"// Floor expanded luma at 0 to match the CPU `yuv` crate's saturating (Y-16)
// term (limited footroom Y<16 → 0). The top is left uncapped — the crate lets
// headroom exceed 1.0 and relies on the final RGB clamp, so the GL path must
// too. No-op for full range (y_offset=0, y_scale=1).
vec3 nv_yuv_to_rgb(float yv, float u, float v) {
float yp = max((yv - y_offset) * y_scale, 0.0);
float up = u - 128.0 / 255.0;
float vp = v - 128.0 / 255.0;
return clamp(vec3(yp + c_vr * vp, yp - c_ug * up - c_vg * vp, yp + c_ub * up), 0.0, 1.0);
}
"
};
}
macro_rules! nv_rgba_header {
() => {
concat!(
"#version 300 es
precision highp float;
precision highp int;
uniform highp sampler2D src;
uniform ivec2 img_size;
uniform int tex_width;
uniform ivec2 chroma_shift;
uniform int chroma_lines;
// Inclusive texel bounds (x0, y0, x1, y1) of the source crop: every tap is
// clamped to them, so a crop never reads pixels from outside itself.
uniform ivec4 src_rect;
// Hardware-filtered program only: the chroma plane as (U, V) texels on unit 1,
// the image's share of each texture (`*_scale`), and the crop's half-texel-
// inset rectangle on each (`*_clamp`), which keeps the LINEAR kernel inside
// the crop and the luma rows.
uniform highp sampler2D uv_tex;
uniform vec2 luma_scale;
uniform vec4 luma_clamp;
uniform vec2 chroma_scale;
uniform vec4 chroma_clamp;
",
nv_colorimetry!(),
"in vec3 fragPos;
in vec2 tc;
out vec4 color;
",
nv_yuv_to_rgb_fn!(),
"vec3 nv_rgb(int x, int y) {
// Luma: direct 2D texel — no per-pixel integer divide/modulo (very slow on
// some embedded GPUs, e.g. Vivante GC7000UL).
float yv = texelFetch(src, ivec2(x, y), 0).r;
// Interleaved CbCr plane begins at buffer row `h`. Each image-chroma-row
// spans `chroma_lines` R8 rows: NV24's 2W-byte row wraps once at tex_width
// (carry); NV12/NV16 fit one row. `cx` is even so `cx+1` stays in-row.
int ccol = x >> chroma_shift.x;
int crow = y >> chroma_shift.y;
int ccol2 = ccol * 2;
int carry = ccol2 >= tex_width ? 1 : 0;
int cy = img_size.y + crow * chroma_lines + carry;
int cx = ccol2 - carry * tex_width;
float u = texelFetch(src, ivec2(cx, cy), 0).r;
float v = texelFetch(src, ivec2(cx + 1, cy), 0).r;
return nv_yuv_to_rgb(yv, u, v);
}
"
)
};
}
macro_rules! nv_rgb_nearest_body {
() => {
" ivec2 i = clamp(ivec2(tc * vec2(img_size)), src_rect.xy, src_rect.zw);
vec3 rgb = nv_rgb(i.x, i.y);
"
};
}
macro_rules! nv_rgb_bilinear_body {
() => {
" vec2 p = tc * vec2(img_size) - 0.5;
vec2 p0 = floor(p);
vec2 f = p - p0;
ivec2 i0 = clamp(ivec2(p0), src_rect.xy, src_rect.zw);
ivec2 i1 = clamp(ivec2(p0) + 1, src_rect.xy, src_rect.zw);
vec3 rgb = mix(mix(nv_rgb(i0.x, i0.y), nv_rgb(i1.x, i0.y), f.x),
mix(nv_rgb(i0.x, i1.y), nv_rgb(i1.x, i1.y), f.x), f.y);
"
};
}
macro_rules! nv_rgb_hw_bilinear_body {
() => {
" vec2 luv = clamp(tc * luma_scale, luma_clamp.xy, luma_clamp.zw);
vec2 cuv = clamp(tc * chroma_scale, chroma_clamp.xy, chroma_clamp.zw);
vec2 c = texture(uv_tex, cuv).rg;
vec3 rgb = nv_yuv_to_rgb(texture(src, luv).r, c.r, c.g);
"
};
}
macro_rules! int_quantize {
() => {
"#ifdef QUANT_MAPPED
uniform highp vec3 q_scale; // q = clamp(floor(v * q_scale + q_offset), q_lo, q_hi)
uniform highp vec3 q_offset;
uniform highp vec3 q_lo;
uniform highp vec3 q_hi;
uniform highp vec3 q_zero; // zero point / 255; q_wrap marks a negative stored value
uniform highp vec3 q_wrap;
highp vec3 quantize(highp vec3 v) {
highp vec3 q = clamp(floor(v * q_scale + q_offset), q_lo, q_hi);
return q * (1.0 / 255.0) + q_zero + step(q, q_wrap) * (256.0 / 255.0);
}
#else
// The plain XOR 0x80 bias, `(q + 128) mod 256`, as the CPU `byte ^ 0x80`.
highp vec3 quantize(highp vec3 v) {
highp vec3 q = floor(v * 255.0 + 0.5);
return mod(q + 128.0, 256.0) / 255.0;
}
#endif
"
};
}
macro_rules! yuyv_rgba_2d_header {
() => {
r#"#version 300 es
precision highp float;
uniform highp sampler2D tex;
uniform vec2 src_size;
uniform vec4 src_extent;
uniform float y_offset;
uniform float y_scale;
uniform float c_vr;
uniform float c_ug;
uniform float c_vg;
uniform float c_ub;
in vec3 fragPos;
in vec2 tc;
out vec4 color;
"#
};
}
macro_rules! yuyv_rgb_body {
() => {
r#" vec2 texel = vec2(1.0) / src_size;
// `src_extent` keeps the texel index inside the logical image when the
// texture is larger than it; `src_size` is the texture's own grid.
vec2 col = floor(clamp(tc, src_extent.xy, src_extent.zw) * src_size);
bool even = mod(col.x, 2.0) < 0.5;
vec2 self_uv = (col + vec2(0.5)) * texel;
// The clamp bounds `col`, not the partner. On an odd logical width the
// last column is even, so its partner is one texel past the logical
// image: stale pool content on a narrowed import, and the column itself
// under CLAMP_TO_EDGE otherwise. Out of scope, and unchanged by the
// clamp: a YUYV chroma pair spans two columns, so an odd width has no
// partner to read in any layout (the allocation is `width` texels wide,
// not rounded up), and the engine's YUYV coverage is even widths only.
vec2 pair_uv = (col + vec2(even ? 1.5 : -0.5, 0.5)) * texel;
vec4 self_rg = texture(tex, self_uv);
vec4 pair_rg = texture(tex, pair_uv);
float y = self_rg.r;
float u, v;
if (even) { u = self_rg.g; v = pair_rg.g; }
else { v = self_rg.g; u = pair_rg.g; }
// Identical matrix/range math to the NV program: floor the expanded
// luma at 0 (limited-range footroom folds to 0; full range is a no-op
// with y_offset=0/y_scale=1), top end left to the per-channel clamp.
float yp = max((y - y_offset) * y_scale, 0.0);
float up = u - 128.0 / 255.0;
float vp = v - 128.0 / 255.0;
float r = clamp(yp + c_vr * vp, 0.0, 1.0);
float g = clamp(yp - c_ug * up - c_vg * vp, 0.0, 1.0);
float b = clamp(yp + c_ub * up, 0.0, 1.0);
"#
};
}
pub(crate) const YUYV_RGBA_2D_FRAGMENT: &str = concat!(
yuyv_rgba_2d_header!(),
"void main() {\n",
yuyv_rgb_body!(),
" color = vec4(r, g, b, 1.0);\n}\n"
);
pub(crate) const YUYV_RGBA_2D_INT8_FRAGMENT: &str = concat!(
yuyv_rgba_2d_header!(),
int_quantize!(),
"void main() {\n",
yuyv_rgb_body!(),
" color = vec4(quantize(vec3(r, g, b)), 1.0);\n}\n"
);
pub(crate) const NV_RGBA_FRAGMENT: &str = concat!(
nv_rgba_header!(),
"void main() {\n",
nv_rgb_nearest_body!(),
" color = vec4(rgb, 1.0);\n}\n"
);
pub(crate) const NV_RGBA_INT8_FRAGMENT: &str = concat!(
nv_rgba_header!(),
int_quantize!(),
"void main() {\n",
nv_rgb_nearest_body!(),
" color = vec4(quantize(rgb), 1.0);\n}\n"
);
pub(crate) const NV_RGBA_BILINEAR_FRAGMENT: &str = concat!(
nv_rgba_header!(),
"void main() {\n",
nv_rgb_bilinear_body!(),
" color = vec4(rgb, 1.0);\n}\n"
);
pub(crate) const NV_RGBA_HW_BILINEAR_FRAGMENT: &str = concat!(
nv_rgba_header!(),
"void main() {\n",
nv_rgb_hw_bilinear_body!(),
" color = vec4(rgb, 1.0);\n}\n"
);
pub(crate) const NV_RGBA_HW_BILINEAR_INT8_FRAGMENT: &str = concat!(
nv_rgba_header!(),
int_quantize!(),
"void main() {\n",
nv_rgb_hw_bilinear_body!(),
" color = vec4(quantize(rgb), 1.0);\n}\n"
);
macro_rules! nv_y2y_header {
() => {
concat!(
"#version 300 es
#extension GL_EXT_YUV_target : require
precision highp float;
uniform __samplerExternal2DY2YEXT src;
uniform highp vec4 src_extent;
",
nv_colorimetry!(),
"in vec3 fragPos;
in highp vec2 tc;
out vec4 color;
",
nv_yuv_to_rgb_fn!()
)
};
}
macro_rules! nv_rgb_y2y_body {
() => {
" vec3 yuv = texture(src, clamp(tc, src_extent.xy, src_extent.zw)).rgb;
vec3 rgb = nv_yuv_to_rgb(yuv.r, yuv.g, yuv.b);
"
};
}
pub(crate) const NV_RGBA_Y2Y_FRAGMENT: &str = concat!(
nv_y2y_header!(),
"void main() {\n",
nv_rgb_y2y_body!(),
" color = vec4(rgb, 1.0);\n}\n"
);
pub(crate) const NV_RGBA_Y2Y_INT8_FRAGMENT: &str = concat!(
nv_y2y_header!(),
int_quantize!(),
"void main() {\n",
nv_rgb_y2y_body!(),
" color = vec4(quantize(rgb), 1.0);\n}\n"
);
pub(crate) const NV_RGBA_BILINEAR_INT8_FRAGMENT: &str = concat!(
nv_rgba_header!(),
int_quantize!(),
"void main() {\n",
nv_rgb_bilinear_body!(),
" color = vec4(quantize(rgb), 1.0);\n}\n"
);
#[cfg(test)]
mod nv_shader_golden {
fn golden(src: &str) -> String {
src.replace("\r\n", "\n")
}
#[test]
fn nv_fragment_byte_identical() {
assert_eq!(
super::NV_RGBA_FRAGMENT,
golden(include_str!("golden/nv_rgba_linux.glsl")).as_str(),
"NV->RGBA shader bytes drifted from the on-target-validated golden"
);
assert_eq!(
super::NV_RGBA_BILINEAR_FRAGMENT,
golden(include_str!("golden/nv_rgba_bilinear_linux.glsl")).as_str(),
"bilinear NV->RGBA shader bytes drifted from the on-target-validated golden"
);
assert_eq!(
super::NV_RGBA_Y2Y_FRAGMENT,
golden(include_str!("golden/nv_rgba_y2y_linux.glsl")).as_str(),
"Y2Y NV->RGBA shader bytes drifted from the on-target-validated golden"
);
assert_eq!(
super::NV_RGBA_HW_BILINEAR_FRAGMENT,
golden(include_str!("golden/nv_rgba_hw_bilinear_linux.glsl")).as_str(),
"hardware-bilinear NV->RGBA shader bytes drifted from the on-target-validated golden"
);
}
#[test]
fn vertex_byte_identical() {
assert_eq!(
super::VERTEX_SHADER,
golden(include_str!("golden/vertex.glsl")).as_str(),
"vertex shader bytes drifted from the on-target-validated golden"
);
}
}