Moving the GL shaders to src/libcamera/assets/shader to allow for reuse of these inside of the SoftISP. Signed-off-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org>
216 lines
6.7 KiB
GLSL
216 lines
6.7 KiB
GLSL
/* 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
|
|
|
|
/*
|
|
* These constants are used to select the bytes containing the HS part of
|
|
* the pixel value:
|
|
* BPP - bytes per pixel,
|
|
* THRESHOLD_L = fract(BPP) * 0.5 + 0.02
|
|
* THRESHOLD_H = 1.0 - fract(BPP) * 1.5 + 0.02
|
|
* Let X is the x coordinate in the texture measured in bytes (so that the
|
|
* range is from 0 to (stride_-1)) aligned on the nearest pixel.
|
|
* E.g. for RAW10P:
|
|
* -------------+-------------------+-------------------+--
|
|
* pixel No | 0 1 2 3 | 4 5 6 7 | ...
|
|
* -------------+-------------------+-------------------+--
|
|
* byte offset | 0 1 2 3 4 | 5 6 7 8 9 | ...
|
|
* -------------+-------------------+-------------------+--
|
|
* X | 0.0 1.25 2.5 3.75 | 5.0 6.25 7.5 8.75 | ...
|
|
* -------------+-------------------+-------------------+--
|
|
* If fract(X) < THRESHOLD_L then the previous byte contains the LS
|
|
* bits of the pixel values and needs to be skipped.
|
|
* If fract(X) > THRESHOLD_H then the next byte contains the LS bits
|
|
* of the pixel values and needs to be skipped.
|
|
*/
|
|
#if defined(RAW10P)
|
|
#define BPP 1.25
|
|
#define THRESHOLD_L 0.14
|
|
#define THRESHOLD_H 0.64
|
|
#elif defined(RAW12P)
|
|
#define BPP 1.5
|
|
#define THRESHOLD_L 0.27
|
|
#define THRESHOLD_H 0.27
|
|
#else
|
|
#error Invalid raw format
|
|
#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 * center_pixel.x + 0.02;
|
|
|
|
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);
|
|
}
|