summaryrefslogtreecommitdiff
path: root/src/qcam/assets/shader/bayer_1x_packed.frag
diff options
context:
space:
mode:
Diffstat (limited to 'src/qcam/assets/shader/bayer_1x_packed.frag')
-rw-r--r--src/qcam/assets/shader/bayer_1x_packed.frag185
1 files changed, 185 insertions, 0 deletions
diff --git a/src/qcam/assets/shader/bayer_1x_packed.frag b/src/qcam/assets/shader/bayer_1x_packed.frag
new file mode 100644
index 00000000..d36db8a2
--- /dev/null
+++ b/src/qcam/assets/shader/bayer_1x_packed.frag
@@ -0,0 +1,185 @@
+/* SPDX-License-Identifier: BSD-2-Clause */
+/*
+ * Based on the code from http://jgt.akpeters.com/papers/McGuire08/
+ *
+ * Efficient, High-Quality Bayer Demosaic Filtering on GPUs
+ *
+ * Morgan McGuire
+ *
+ * This paper appears in issue Volume 13, Number 4.
+ * ---------------------------------------------------------
+ * Copyright (c) 2008, Morgan McGuire. All rights reserved.
+ *
+ *
+ * Modified by Linaro Ltd for 10/12-bit packed vs 8-bit raw Bayer format,
+ * and for simpler demosaic algorithm.
+ * Copyright (C) 2020, Linaro
+ *
+ * bayer_1x_packed.frag - Fragment shader code for raw Bayer 10-bit and 12-bit
+ * packed formats
+ */
+
+#ifdef GL_ES
+precision mediump float;
+#endif
+
+varying vec2 textureOut;
+
+/* the texture size in pixels */
+uniform vec2 tex_size;
+uniform vec2 tex_step;
+uniform vec2 tex_bayer_first_red;
+
+uniform sampler2D tex_y;
+
+void main(void)
+{
+ vec3 rgb;
+
+ /*
+ * center_bytes holds the coordinates of the MS byte of the pixel
+ * being sampled on the [0, stride-1/height-1] range.
+ * center_pixel holds the coordinates of the pixel being sampled
+ * on the [0, width/height-1] range.
+ */
+ vec2 center_bytes;
+ vec2 center_pixel;
+
+ /*
+ * x- and y-positions of the adjacent pixels on the [0, 1] range.
+ */
+ vec2 xcoords;
+ vec2 ycoords;
+
+ /*
+ * The coordinates passed to the shader in textureOut may point
+ * to a place in between the pixels if the texture format doesn't
+ * match the image format. In particular, MIPI packed raw Bayer
+ * formats don't have a matching texture format.
+ * In this case align the coordinates to the left nearest pixel
+ * by hand.
+ */
+ center_pixel = floor(textureOut * tex_size);
+ center_bytes.y = center_pixel.y;
+
+ /*
+ * Add a small number (a few mantissa's LSBs) to avoid float
+ * representation issues. Maybe paranoic.
+ */
+ center_bytes.x = BPP_X * center_pixel.x + 0.02;
+
+ const float threshold_l = 0.127 /* fract(BPP_X) * 0.5 + 0.02 */;
+ const float threshold_h = 0.625 /* 1.0 - fract(BPP_X) * 1.5 */;
+
+ float fract_x = fract(center_bytes.x);
+
+ /*
+ * The below floor() call ensures that center_bytes.x points
+ * at one of the bytes representing the 8 higher bits of
+ * the pixel value, not at the byte containing the LS bits
+ * of the group of the pixels.
+ */
+ center_bytes.x = floor(center_bytes.x);
+ center_bytes *= tex_step;
+
+ xcoords = center_bytes.x + vec2(-tex_step.x, tex_step.x);
+ ycoords = center_bytes.y + vec2(-tex_step.y, tex_step.y);
+
+ /*
+ * If xcoords[0] points at the byte containing the LS bits
+ * of the previous group of the pixels, move xcoords[0] one
+ * byte back.
+ */
+ xcoords[0] += (fract_x < threshold_l) ? -tex_step.x : 0.0;
+
+ /*
+ * If xcoords[1] points at the byte containing the LS bits
+ * of the current group of the pixels, move xcoords[1] one
+ * byte forward.
+ */
+ xcoords[1] += (fract_x > threshold_h) ? tex_step.x : 0.0;
+
+ vec2 alternate = mod(center_pixel.xy + tex_bayer_first_red, 2.0);
+ bool even_col = alternate.x < 1.0;
+ bool even_row = alternate.y < 1.0;
+
+ /*
+ * We need to sample the central pixel and the ones with offset
+ * of -1 to +1 pixel in both X and Y directions. Let's name these
+ * pixels as below, where C is the central pixel:
+ *
+ * +----+----+----+----+
+ * | \ x| | | |
+ * |y \ | -1 | 0 | +1 |
+ * +----+----+----+----+
+ * | +1 | D2 | A1 | D3 |
+ * +----+----+----+----+
+ * | 0 | B0 | C | B1 |
+ * +----+----+----+----+
+ * | -1 | D0 | A0 | D1 |
+ * +----+----+----+----+
+ *
+ * In the below equations (0,-1).r means "r component of the texel
+ * shifted by -tex_step.y from the center_bytes one" etc.
+ *
+ * In the even row / even column (EE) case the colour values are:
+ * R = C = (0,0).r,
+ * G = (A0 + A1 + B0 + B1) / 4.0 =
+ * ( (0,-1).r + (0,1).r + (-1,0).r + (1,0).r ) / 4.0,
+ * B = (D0 + D1 + D2 + D3) / 4.0 =
+ * ( (-1,-1).r + (1,-1).r + (-1,1).r + (1,1).r ) / 4.0
+ *
+ * For even row / odd column (EO):
+ * R = (B0 + B1) / 2.0 = ( (-1,0).r + (1,0).r ) / 2.0,
+ * G = C = (0,0).r,
+ * B = (A0 + A1) / 2.0 = ( (0,-1).r + (0,1).r ) / 2.0
+ *
+ * For odd row / even column (OE):
+ * R = (A0 + A1) / 2.0 = ( (0,-1).r + (0,1).r ) / 2.0,
+ * G = C = (0,0).r,
+ * B = (B0 + B1) / 2.0 = ( (-1,0).r + (1,0).r ) / 2.0
+ *
+ * For odd row / odd column (OO):
+ * R = (D0 + D1 + D2 + D3) / 4.0 =
+ * ( (-1,-1).r + (1,-1).r + (-1,1).r + (1,1).r ) / 4.0,
+ * G = (A0 + A1 + B0 + B1) / 4.0 =
+ * ( (0,-1).r + (0,1).r + (-1,0).r + (1,0).r ) / 4.0,
+ * B = C = (0,0).r
+ */
+
+ /*
+ * Fetch the values and precalculate the terms:
+ * patterns.x = (A0 + A1) / 2.0
+ * patterns.y = (B0 + B1) / 2.0
+ * patterns.z = (A0 + A1 + B0 + B1) / 4.0
+ * patterns.w = (D0 + D1 + D2 + D3) / 4.0
+ */
+ #define fetch(x, y) texture2D(tex_y, vec2(x, y)).r
+
+ float C = texture2D(tex_y, center_bytes).r;
+ vec4 patterns = vec4(
+ fetch(center_bytes.x, ycoords[0]), /* A0: (0,-1) */
+ fetch(xcoords[0], center_bytes.y), /* B0: (-1,0) */
+ fetch(xcoords[0], ycoords[0]), /* D0: (-1,-1) */
+ fetch(xcoords[1], ycoords[0])); /* D1: (1,-1) */
+ vec4 temp = vec4(
+ fetch(center_bytes.x, ycoords[1]), /* A1: (0,1) */
+ fetch(xcoords[1], center_bytes.y), /* B1: (1,0) */
+ fetch(xcoords[1], ycoords[1]), /* D3: (1,1) */
+ fetch(xcoords[0], ycoords[1])); /* D2: (-1,1) */
+ patterns = (patterns + temp) * 0.5;
+ /* .x = (A0 + A1) / 2.0, .y = (B0 + B1) / 2.0 */
+ /* .z = (D0 + D3) / 2.0, .w = (D1 + D2) / 2.0 */
+ patterns.w = (patterns.z + patterns.w) * 0.5;
+ patterns.z = (patterns.x + patterns.y) * 0.5;
+
+ rgb = even_col ?
+ (even_row ?
+ vec3(C, patterns.zw) :
+ vec3(patterns.x, C, patterns.y)) :
+ (even_row ?
+ vec3(patterns.y, C, patterns.x) :
+ vec3(patterns.wz, C));
+
+ gl_FragColor = vec4(rgb, 1.0);
+}