diff options
Diffstat (limited to 'src/qcam/assets/shader/YUV_packed.frag')
-rw-r--r-- | src/qcam/assets/shader/YUV_packed.frag | 82 |
1 files changed, 82 insertions, 0 deletions
diff --git a/src/qcam/assets/shader/YUV_packed.frag b/src/qcam/assets/shader/YUV_packed.frag new file mode 100644 index 00000000..224dfafe --- /dev/null +++ b/src/qcam/assets/shader/YUV_packed.frag @@ -0,0 +1,82 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2020, Laurent Pinchart <laurent.pinchart@ideasonboard.com> + * + * YUV_packed.frag - Fragment shader code for YUYV packed formats + */ + +#ifdef GL_ES +precision mediump float; +#endif + +varying vec2 textureOut; + +uniform sampler2D tex_y; +uniform float tex_stepx; + +void main(void) +{ + mat3 yuv2rgb_bt601_mat = mat3( + vec3(1.164, 1.164, 1.164), + vec3(0.000, -0.392, 2.017), + vec3(1.596, -0.813, 0.000) + ); + vec3 yuv2rgb_bt601_offset = vec3(0.063, 0.500, 0.500); + + /* + * The sampler won't interpolate the texture correctly along the X axis, + * as each RGBA pixel effectively stores two pixels. We thus need to + * interpolate manually. + * + * In integer texture coordinates, the Y values are layed out in the + * texture memory as follows: + * + * ...| Y U Y V | Y U Y V | Y U Y V |... + * ...| R G B A | R G B A | R G B A |... + * ^ ^ ^ ^ ^ ^ + * | | | | | | + * n-1 n-0.5 n n+0.5 n+1 n+1.5 + * + * For a texture location x in the interval [n, n+1[, sample the left + * and right pixels at n and n+1, and interpolate them with + * + * left.r * (1 - a) + left.b * a if fract(x) < 0.5 + * left.b * (1 - a) + right.r * a if fract(x) >= 0.5 + * + * with a = fract(x * 2) which can also be written + * + * a = fract(x) * 2 if fract(x) < 0.5 + * a = fract(x) * 2 - 1 if fract(x) >= 0.5 + */ + vec2 pos = textureOut; + float f_x = fract(pos.x / tex_stepx); + + vec4 left = texture2D(tex_y, vec2(pos.x - f_x * tex_stepx, pos.y)); + vec4 right = texture2D(tex_y, vec2(pos.x + (1.0 - f_x) * tex_stepx , pos.y)); + +#if defined(YUV_PATTERN_UYVY) + float y_left = mix(left.g, left.a, f_x * 2.0); + float y_right = mix(left.a, right.g, f_x * 2.0 - 1.0); + vec2 uv = mix(left.rb, right.rb, f_x); +#elif defined(YUV_PATTERN_VYUY) + float y_left = mix(left.g, left.a, f_x * 2.0); + float y_right = mix(left.a, right.g, f_x * 2.0 - 1.0); + vec2 uv = mix(left.br, right.br, f_x); +#elif defined(YUV_PATTERN_YUYV) + float y_left = mix(left.r, left.b, f_x * 2.0); + float y_right = mix(left.b, right.r, f_x * 2.0 - 1.0); + vec2 uv = mix(left.ga, right.ga, f_x); +#elif defined(YUV_PATTERN_YVYU) + float y_left = mix(left.r, left.b, f_x * 2.0); + float y_right = mix(left.b, right.r, f_x * 2.0 - 1.0); + vec2 uv = mix(left.ag, right.ag, f_x); +#else +#error Invalid pattern +#endif + + float y = mix(y_left, y_right, step(0.5, f_x)); + + vec3 rgb = yuv2rgb_bt601_mat * (vec3(y, uv) - yuv2rgb_bt601_offset); + + gl_FragColor = vec4(rgb, 1.0); +} |