1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
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);
}
|