1// Texture IDs
2#if PIXFMT == V4L2_PIX_FMT_SBGGR8 || PIXFMT == V4L2_PIX_FMT_SGBRG8 || \
3    PIXFMT == V4L2_PIX_FMT_SGRBG8 || PIXFMT == V4L2_PIX_FMT_SRGGB8 || \
4    PIXFMT == V4L2_PIX_FMT_SBGGR10 || PIXFMT == V4L2_PIX_FMT_SGBRG10 || \
5    PIXFMT == V4L2_PIX_FMT_SGRBG10 || PIXFMT == V4L2_PIX_FMT_SRGGB10 || \
6    PIXFMT == V4L2_PIX_FMT_SBGGR12 || PIXFMT == V4L2_PIX_FMT_SGBRG12 || \
7    PIXFMT == V4L2_PIX_FMT_SGRBG12 || PIXFMT == V4L2_PIX_FMT_SRGGB12 || \
8    PIXFMT == V4L2_PIX_FMT_SBGGR16 || PIXFMT == V4L2_PIX_FMT_SGBRG16 || \
9    PIXFMT == V4L2_PIX_FMT_SGRBG16 || PIXFMT == V4L2_PIX_FMT_SRGGB16 || \
10    PIXFMT == V4L2_PIX_FMT_GREY || PIXFMT == V4L2_PIX_FMT_Y16 || \
11    PIXFMT == V4L2_PIX_FMT_Y16_BE || PIXFMT == V4L2_PIX_FMT_Z16 || \
12    PIXFMT == V4L2_PIX_FMT_Y10 || PIXFMT == V4L2_PIX_FMT_Y12
13uniform highp usampler2D tex;
14#else
15uniform sampler2D tex;
16#endif
17uniform sampler2D ytex;
18uniform sampler2D uvtex;
19uniform sampler2D utex;
20uniform sampler2D vtex;
21
22in vec2 vs_TexCoord;
23
24out vec4 fs_FragColor;
25
26// YUV (aka Y'CbCr) to R'G'B' matrices
27
28const mat3 yuv2rgb = mat3(
29#if YCBCRENC == V4L2_YCBCR_ENC_SMPTE240M
30	// Old obsolete HDTV standard. Replaced by REC 709.
31	// SMPTE 240M has its own luma coefficients
32	1.0,     1.0,     1.0,
33	0.0,    -0.2253,  1.8270,
34	1.5756, -0.4768,  0.0
35#elif YCBCRENC == V4L2_YCBCR_ENC_BT2020
36	// BT.2020 luma coefficients
37	1.0,     1.0,     1.0,
38	0.0,    -0.1646,  1.8814,
39	1.4719, -0.5703,  0.0
40#elif YCBCRENC == V4L2_YCBCR_ENC_601 || YCBCRENC == V4L2_YCBCR_ENC_XV601
41	// These colorspaces all use the BT.601 luma coefficients
42	1.0,    1.0,    1.0,
43	0.0,   -0.344,  1.773,
44	1.403, -0.714,  0.0
45#else
46	// The HDTV colorspaces all use REC 709 luma coefficients
47	1.0,     1.0,     1.0,
48	0.0,    -0.1870,  1.8556,
49	1.5701, -0.4664,  0.0
50#endif
51);
52
53// Various colorspace conversion matrices that transfer the source chromaticities
54// to the sRGB/Rec.709 chromaticities
55
56const mat3 colconv = mat3(
57#if COLSP == V4L2_COLORSPACE_SMPTE170M || COLSP == V4L2_COLORSPACE_SMPTE240M
58	// Current SDTV standard, although slowly being replaced by REC 709.
59	// Uses the SMPTE 170M aka SMPTE-C aka SMPTE RP 145 conversion matrix.
60	0.939536,  0.017743, -0.001591,
61	0.050215,  0.965758, -0.004356,
62	0.001789,  0.016243,  1.005951
63#elif COLSP == V4L2_COLORSPACE_470_SYSTEM_M
64	// Old obsolete NTSC standard. Replaced by REC 709.
65	// Uses the NTSC 1953 conversion matrix and the Bradford method to
66	// compensate for the different whitepoints.
67	 1.4858417, -0.0251179, -0.0272254,
68	-0.4033361,  0.9541568, -0.0440815,
69	-0.0825056,  0.0709611,  1.0713068
70#elif COLSP == V4L2_COLORSPACE_470_SYSTEM_BG
71	// Old obsolete PAL/SECAM standard. Replaced by REC 709.
72	// Uses the EBU Tech. 3213 conversion matrix.
73	 1.0440, 0,  0,
74	-0.0440, 1, -0.0119,
75	 0,      0,  1.0119
76#elif COLSP == V4L2_COLORSPACE_OPRGB
77	 1.3982832, 0,  0,
78	-0.3982831, 1, -0.0429383,
79	 0,         0,  1.0429383
80#elif COLSP == V4L2_COLORSPACE_DCI_P3
81	// Uses the Bradford method to compensate for the different whitepoints.
82	 1.1574000, -0.0415052, -0.0180562,
83	-0.1548597,  1.0455684, -0.0785993,
84	-0.0025403, -0.0040633,  1.0966555
85#elif COLSP == V4L2_COLORSPACE_BT2020
86	 1.6603627, -0.1245635, -0.0181566,
87	-0.5875400,  1.1329114, -0.1006017,
88	-0.0728227, -0.0083478,  1.1187583
89#else
90	// Identity matrix
91	1.0
92#endif
93);
94
95void main()
96{
97	const float texl_w = 1.0 / tex_w;
98	const float texl_h = 1.0 / tex_h;
99	float alpha = 0.0;
100	vec2 xy = vs_TexCoord;
101	float xcoord = floor(xy.x * tex_w);
102	float ycoord = floor(xy.y * tex_h);
103	bool xeven = mod(xcoord, 2.0) == 0.0;
104	bool yeven = mod(ycoord, 2.0) == 0.0;
105	vec3 yuv;
106	vec3 rgb;
107
108#if FIELD == V4L2_FIELD_SEQ_TB
109	xy.y = (mod(ycoord, 2.0) == 0.0) ? xy.y / 2.0 : xy.y / 2.0 + 0.5;
110#elif FIELD == V4L2_FIELD_SEQ_BT
111	xy.y = (mod(ycoord, 2.0) == 0.0) ? xy.y / 2.0 + 0.5 : xy.y / 2.0;
112#endif
113
114#if IS_RGB
115
116// Bayer pixel formats
117#if PIXFMT == V4L2_PIX_FMT_SBGGR8 || PIXFMT == V4L2_PIX_FMT_SBGGR10 || PIXFMT == V4L2_PIX_FMT_SBGGR12 || PIXFMT == V4L2_PIX_FMT_SBGGR16
118	uvec4 urgb;
119	vec2 cell = vec2(xeven ? xy.x : xy.x - texl_w, yeven ? xy.y : xy.y - texl_h);
120	urgb.r = texture(tex, vec2(cell.x + texl_w, cell.y + texl_h)).r;
121	urgb.g = texture(tex, vec2((cell.y == xy.y) ? cell.x + texl_w : cell.x, xy.y)).r;
122	urgb.b = texture(tex, cell).r;
123#elif PIXFMT == V4L2_PIX_FMT_SGBRG8 || PIXFMT == V4L2_PIX_FMT_SGBRG10 || PIXFMT == V4L2_PIX_FMT_SGBRG12 || PIXFMT == V4L2_PIX_FMT_SGBRG16
124	uvec4 urgb;
125	vec2 cell = vec2(xeven ? xy.x : xy.x - texl_w, yeven ? xy.y : xy.y - texl_h);
126	urgb.r = texture(tex, vec2(cell.x, cell.y + texl_h)).r;
127	urgb.g = texture(tex, vec2((cell.y == xy.y) ? cell.x : cell.x + texl_w, xy.y)).r;
128	urgb.b = texture(tex, vec2(cell.x + texl_w, cell.y)).r;
129#elif PIXFMT == V4L2_PIX_FMT_SGRBG8 || PIXFMT == V4L2_PIX_FMT_SGRBG10 || PIXFMT == V4L2_PIX_FMT_SGRBG12 || PIXFMT == V4L2_PIX_FMT_SGRBG16
130	uvec4 urgb;
131	vec2 cell = vec2(xeven ? xy.x : xy.x - texl_w, yeven ? xy.y : xy.y - texl_h);
132	urgb.r = texture(tex, vec2(cell.x + texl_w, cell.y)).r;
133	urgb.g = texture(tex, vec2((cell.y == xy.y) ? cell.x : cell.x + texl_w, xy.y)).r;
134	urgb.b = texture(tex, vec2(cell.x, cell.y + texl_h)).r;
135#elif PIXFMT == V4L2_PIX_FMT_SRGGB8 || PIXFMT == V4L2_PIX_FMT_SRGGB10 || PIXFMT == V4L2_PIX_FMT_SRGGB12 || PIXFMT == V4L2_PIX_FMT_SRGGB16
136	uvec4 urgb;
137	vec2 cell = vec2(xeven ? xy.x : xy.x - texl_w, yeven ? xy.y : xy.y - texl_h);
138	urgb.b = texture(tex, vec2(cell.x + texl_w, cell.y + texl_h)).r;
139	urgb.g = texture(tex, vec2((cell.y == xy.y) ? cell.x + texl_w : cell.x, xy.y)).r;
140	urgb.r = texture(tex, cell).r;
141#elif PIXFMT == V4L2_PIX_FMT_RGB32 || PIXFMT == V4L2_PIX_FMT_XRGB32 || PIXFMT == V4L2_PIX_FMT_ARGB32 || \
142      PIXFMT == V4L2_PIX_FMT_RGB444 || PIXFMT == V4L2_PIX_FMT_XRGB444 || PIXFMT == V4L2_PIX_FMT_ARGB444
143	vec4 cell = texture(tex, xy);
144#if V4L2_PIX_FMT_ARGB444 || PIXFMT == V4L2_PIX_FMT_ARGB32
145	alpha = cell.r;
146#endif
147	rgb.rgb = cell.gba;
148#elif PIXFMT == V4L2_PIX_FMT_BGR32 || PIXFMT == V4L2_PIX_FMT_XBGR32 || PIXFMT == V4L2_PIX_FMT_ABGR32 || \
149      PIXFMT == V4L2_PIX_FMT_BGRX444 || PIXFMT == V4L2_PIX_FMT_BGRA444 || \
150      PIXFMT == V4L2_PIX_FMT_XBGR555 || PIXFMT == V4L2_PIX_FMT_ABGR555 || \
151      PIXFMT == V4L2_PIX_FMT_RGBX555 || PIXFMT == V4L2_PIX_FMT_RGBA555
152	vec4 cell = texture(tex, xy);
153#if PIXFMT == V4L2_PIX_FMT_ABGR32 || PIXFMT == V4L2_PIX_FMT_BGRA444 || PIXFMT == V4L2_PIX_FMT_RGBA555 || PIXFMT == V4L2_PIX_FMT_ABGR555
154	alpha = cell.a;
155#endif
156	rgb.rgb = cell.bgr;
157#elif PIXFMT == V4L2_PIX_FMT_RGBX32 || PIXFMT == V4L2_PIX_FMT_RGBA32 || \
158      PIXFMT == V4L2_PIX_FMT_RGBX444 || PIXFMT == V4L2_PIX_FMT_RGBA444 || \
159      PIXFMT == V4L2_PIX_FMT_RGB555 || PIXFMT == V4L2_PIX_FMT_XRGB555 || PIXFMT == V4L2_PIX_FMT_ARGB555 || \
160      PIXFMT == V4L2_PIX_FMT_BGRX555 || PIXFMT == V4L2_PIX_FMT_BGRA555
161	vec4 cell = texture(tex, xy);
162#if PIXFMT == V4L2_PIX_FMT_RGBA32 || PIXFMT == V4L2_PIX_FMT_RGBA444 || PIXFMT == V4L2_PIX_FMT_ARGB555 || PIXFMT == V4L2_PIX_FMT_BGRA555
163	alpha = cell.a;
164#endif
165	rgb.rgb = cell.rgb;
166#elif PIXFMT == V4L2_PIX_FMT_BGRX32 || PIXFMT == V4L2_PIX_FMT_BGRA32 || \
167      PIXFMT == V4L2_PIX_FMT_XBGR444 || PIXFMT == V4L2_PIX_FMT_ABGR444
168	vec4 cell = texture(tex, xy);
169#if PIXFMT == V4L2_PIX_FMT_BGRA32 || PIXFMT == V4L2_PIX_FMT_ABGR444
170	alpha = cell.r;
171#endif
172	rgb.rgb = cell.abg;
173#elif PIXFMT == V4L2_PIX_FMT_GREY
174	rgb.rgb = vec3(float(texture(tex, xy).r) / 255.0);
175#elif PIXFMT == V4L2_PIX_FMT_Y10
176	rgb.rgb = vec3(float(texture(tex, xy).r) / 1023.0);
177#elif PIXFMT == V4L2_PIX_FMT_Y12
178	rgb.rgb = vec3(float(texture(tex, xy).r) / 4095.0);
179#elif PIXFMT == V4L2_PIX_FMT_Y16 || PIXFMT == V4L2_PIX_FMT_Z16
180	rgb.rgb = vec3(float(texture(tex, xy).r) / 65535.0);
181#elif PIXFMT == V4L2_PIX_FMT_Y16_BE
182	uint low = texture(tex, xy).r >> 8;
183	uint high = (texture(tex, xy).r & 0xFFu) << 8;
184	rgb.rgb = vec3(float(high | low) / 65535.0);
185#else
186	vec4 color = texture(tex, xy);
187
188// RGB pixel formats with an alpha component
189#if PIXFMT == V4L2_PIX_FMT_ARGB555 || PIXFMT == V4L2_PIX_FMT_ARGB555X || \
190    PIXFMT == V4L2_PIX_FMT_RGBA555 || PIXFMT == V4L2_PIX_FMT_ABGR555 || \
191    PIXFMT == V4L2_PIX_FMT_BGRA555
192	alpha = color.a;
193#endif
194
195#if PIXFMT == V4L2_PIX_FMT_BGR666
196	vec3 frgb = floor(color.rgb * 255.0);
197	frgb.r = floor(frgb.r / 64.0) + mod(frgb.g, 16.0) * 4.0;
198	frgb.g = floor(frgb.g / 16.0) + mod(frgb.b, 4.0) * 16.0;
199	frgb.b = floor(frgb.b / 4.0);
200	rgb = frgb / 63.0;
201#elif PIXFMT == V4L2_PIX_FMT_BGR24
202	rgb = color.bgr;
203#else
204	rgb = color.rgb;
205#endif
206
207#endif
208
209#if PIXFMT == V4L2_PIX_FMT_SBGGR8 || PIXFMT == V4L2_PIX_FMT_SGBRG8 || \
210    PIXFMT == V4L2_PIX_FMT_SGRBG8 || PIXFMT == V4L2_PIX_FMT_SRGGB8
211	rgb = vec3(urgb) / 255.0;
212#elif PIXFMT == V4L2_PIX_FMT_SBGGR10 || PIXFMT == V4L2_PIX_FMT_SGBRG10 || \
213      PIXFMT == V4L2_PIX_FMT_SGRBG10 || PIXFMT == V4L2_PIX_FMT_SRGGB10
214	rgb = vec3(urgb) / 1023.0;
215#elif PIXFMT == V4L2_PIX_FMT_SBGGR12 || PIXFMT == V4L2_PIX_FMT_SGBRG12 || \
216      PIXFMT == V4L2_PIX_FMT_SGRBG12 || PIXFMT == V4L2_PIX_FMT_SRGGB12
217	rgb = vec3(urgb) / 4095.0;
218#elif PIXFMT == V4L2_PIX_FMT_SBGGR16 || PIXFMT == V4L2_PIX_FMT_SGBRG16 || \
219      PIXFMT == V4L2_PIX_FMT_SGRBG16 || PIXFMT == V4L2_PIX_FMT_SRGGB16
220	rgb = vec3(urgb) / 65535.0;
221#endif
222
223#if QUANT == V4L2_QUANTIZATION_LIM_RANGE
224	rgb -= 16.0 / 255.0;
225	rgb *= 255.0 / 219.0;
226#endif
227
228#else // IS_RGB
229
230#if PIXFMT == V4L2_PIX_FMT_YUYV
231	vec4 luma_chroma = texture(tex, xeven ? xy : vec2(xy.x - texl_w, xy.y));
232	yuv.r = xeven ? luma_chroma.r : luma_chroma.b;
233	yuv.gb = luma_chroma.ga;
234#elif PIXFMT == V4L2_PIX_FMT_YVYU
235	vec4 luma_chroma = texture(tex, xeven ? xy : vec2(xy.x - texl_w, xy.y));
236	yuv.r = xeven ? luma_chroma.r : luma_chroma.b;
237	yuv.gb = luma_chroma.ag;
238#elif PIXFMT == V4L2_PIX_FMT_UYVY
239	vec4 luma_chroma = texture(tex, xeven ? xy : vec2(xy.x - texl_w, xy.y));
240	yuv.r = xeven ? luma_chroma.g : luma_chroma.a;
241	yuv.gb = luma_chroma.rb;
242#elif PIXFMT == V4L2_PIX_FMT_VYUY
243	vec4 luma_chroma = texture(tex, xeven ? xy : vec2(xy.x - texl_w, xy.y));
244	yuv.r = xeven ? luma_chroma.g : luma_chroma.a;
245	yuv.gb = luma_chroma.br;
246#elif PIXFMT == V4L2_PIX_FMT_NV16 || PIXFMT == V4L2_PIX_FMT_NV16M || \
247      PIXFMT == V4L2_PIX_FMT_NV12 || PIXFMT == V4L2_PIX_FMT_NV12M
248	yuv.r = texture(ytex, xy).r;
249	if (xeven) {
250		yuv.g = texture(uvtex, xy).r;
251		yuv.b = texture(uvtex, vec2(xy.x + texl_w, xy.y)).r;
252	} else {
253		yuv.g = texture(uvtex, vec2(xy.x - texl_w, xy.y)).r;
254		yuv.b = texture(uvtex, xy).r;
255	}
256#elif PIXFMT == V4L2_PIX_FMT_NV61 || PIXFMT == V4L2_PIX_FMT_NV61M || \
257      PIXFMT == V4L2_PIX_FMT_NV21 || PIXFMT == V4L2_PIX_FMT_NV21M
258	yuv.r = texture(ytex, xy).r;
259	if (xeven) {
260		yuv.g = texture(uvtex, vec2(xy.x + texl_w, xy.y)).r;
261		yuv.b = texture(uvtex, xy).r;
262	} else {
263		yuv.g = texture(uvtex, xy).r;
264		yuv.b = texture(uvtex, vec2(xy.x - texl_w, xy.y)).r;
265	}
266#elif PIXFMT == V4L2_PIX_FMT_NV24
267	yuv.r = texture(ytex, xy).r;
268	yuv.g = texture(uvtex, xy).r;
269	yuv.b = texture(uvtex, xy).g;
270#elif PIXFMT == V4L2_PIX_FMT_NV42
271	yuv.r = texture(ytex, xy).r;
272	yuv.g = texture(uvtex, xy).g;
273	yuv.b = texture(uvtex, xy).r;
274#elif PIXFMT == V4L2_PIX_FMT_YUV555
275	vec4 color = texture(tex, xy);
276	alpha = color.a;
277	yuv = color.rgb;
278#elif PIXFMT == V4L2_PIX_FMT_YUV444 || PIXFMT == V4L2_PIX_FMT_YUV32 || \
279      PIXFMT == V4L2_PIX_FMT_XYUV32 || PIXFMT == V4L2_PIX_FMT_AYUV32
280	vec4 color = texture(tex, xy);
281#if PIXFMT == V4L2_PIX_FMT_AYUV32
282	alpha = color.r;
283#endif
284	yuv.r = color.g;
285	yuv.g = color.b;
286	yuv.b = color.a;
287#elif PIXFMT == V4L2_PIX_FMT_VUYA32 || PIXFMT == V4L2_PIX_FMT_VUYX32
288	vec4 color = texture(tex, xy);
289#if PIXFMT == V4L2_PIX_FMT_VUYA32
290	alpha = color.a;
291#endif
292	yuv.r = color.b;
293	yuv.g = color.g;
294	yuv.b = color.r;
295#elif PIXFMT == V4L2_PIX_FMT_YUV565
296	yuv = texture(tex, xy).rgb;
297#elif PIXFMT == V4L2_PIX_FMT_YUV422P || PIXFMT == V4L2_PIX_FMT_YUV420 || PIXFMT == V4L2_PIX_FMT_YVU420 || \
298      PIXFMT == V4L2_PIX_FMT_YUV420M || PIXFMT == V4L2_PIX_FMT_YVU420M || \
299      PIXFMT == V4L2_PIX_FMT_YUV422M || PIXFMT == V4L2_PIX_FMT_YVU422M || \
300      PIXFMT == V4L2_PIX_FMT_YUV444M || PIXFMT == V4L2_PIX_FMT_YVU444M
301	yuv = vec3(texture(ytex, xy).r, texture(utex, xy).r, texture(vtex, xy).r);
302#endif
303
304#if IS_HSV
305	vec4 color = texture(tex, xy);
306
307#if PIXFMT == V4L2_PIX_FMT_HSV32
308	color = color.gbar;
309#endif
310	// From http://lolengine.net/blog/2013/07/27/rgb-to-hsv-in-glsl
311	float hue = color.r;
312
313#if HSVENC == V4L2_HSV_ENC_180
314	hue = (hue * 256.0) / 180.0;
315#endif
316	vec3 c = vec3(hue, color.g, color.b);
317	vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
318	vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);
319	rgb = c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);
320#else // IS_HSV
321	yuv.gb -= 0.5;
322#endif
323
324#if QUANT != V4L2_QUANTIZATION_FULL_RANGE || YCBCRENC == V4L2_YCBCR_ENC_XV601 || YCBCRENC == V4L2_YCBCR_ENC_XV709
325	/*
326	 * xv709 and xv601 have full range quantization, but they still
327	 * need to be normalized as if they were limited range. But the
328	 * result are values outside the normal 0-1 range, which is the
329	 * point of these extended gamut encodings.
330	 */
331	const vec3 scale = vec3(255.0 / 219.0, 255.0 / 224.0, 255.0 / 224.0);
332	const vec3 offset = vec3(16.0 / 255.0, 0.0, 0.0);
333
334	yuv -= offset;
335	yuv *= scale;
336#endif
337
338#if YCBCRENC == V4L2_YCBCR_ENC_BT2020_CONST_LUM
339	// BT.2020_CONST_LUM luma coefficients
340	float y = yuv.r;
341	float u = yuv.g;
342	float v = yuv.b;
343	float b = u <= 0.0 ? y + 1.9404 * u : y + 1.5816 * u;
344	float r = v <= 0.0 ? y + 1.7184 * v : y + 0.9936 * v;
345	float lin_r = (r < 0.081) ? r / 4.5 : pow((r + 0.099) / 1.099, 1.0 / 0.45);
346	float lin_b = (b < 0.081) ? b / 4.5 : pow((b + 0.099) / 1.099, 1.0 / 0.45);
347	float lin_y = (y < 0.081) ? y / 4.5 : pow((y + 0.099) / 1.099, 1.0 / 0.45);
348	float lin_g = lin_y / 0.6780 - lin_r * 0.2627 / 0.6780 - lin_b * 0.0593 / 0.6780;
349	float g = (lin_g < 0.018) ? lin_g * 4.5 : 1.099 * pow(lin_g, 0.45) - 0.099;
350	rgb = vec3(r, g, b);
351#elif !IS_HSV
352	rgb = yuv2rgb * yuv;
353#endif
354#endif // !IS_RGB
355
356// Convert non-linear R'G'B' to linear RGB, taking into account the
357// colorspace.
358#if XFERFUNC == V4L2_XFER_FUNC_SMPTE240M
359
360// Old obsolete HDTV standard. Replaced by REC 709.
361// This is the transfer function for SMPTE 240M
362#define XFER(c) (((c) < 0.0913) ? (c) / 4.0 : pow(((c) + 0.1115) / 1.1115, 1.0 / 0.45))
363
364	rgb = vec3(XFER(rgb.r), XFER(rgb.g), XFER(rgb.b));
365
366#elif XFERFUNC == V4L2_XFER_FUNC_SRGB
367
368// This is used for sRGB as specified by the IEC FDIS 61966-2-1 standard
369#define XFER(c) (((c) < -0.04045) ? -pow((-(c) + 0.055) / 1.055, 2.4) : \
370		(((c) <= 0.04045) ? (c) / 12.92 : pow(((c) + 0.055) / 1.055, 2.4)))
371
372	rgb = vec3(XFER(rgb.r), XFER(rgb.g), XFER(rgb.b));
373
374#elif XFERFUNC == V4L2_XFER_FUNC_OPRGB
375
376	// Avoid powers of negative numbers
377	rgb = max(rgb, vec3(0.0));
378	rgb = pow(rgb, vec3(2.19921875));
379
380#elif XFERFUNC == V4L2_XFER_FUNC_DCI_P3
381
382	// Avoid powers of negative numbers
383	rgb = max(rgb, vec3(0.0));
384	rgb = pow(rgb, vec3(2.6));
385
386#elif XFERFUNC == V4L2_XFER_FUNC_SMPTE2084
387	const vec3 m1 = vec3(1.0 / ((2610.0 / 4096.0) / 4.0));
388	const vec3 m2 = vec3(1.0 / (128.0 * 2523.0 / 4096.0));
389	const vec3 c1 = vec3(3424.0 / 4096.0);
390	const vec3 c2 = vec3(32.0 * 2413.0 / 4096.0);
391	const vec3 c3 = vec3(32.0 * 2392.0 / 4096.0);
392
393	// Avoid powers of negative numbers
394	rgb = max(rgb, vec3(0.0));
395	rgb = pow(rgb, m2);
396	// The factor 100 is because SMPTE-2084 maps to 0-10000 cd/m^2
397	// whereas other transfer functions map to 0-100 cd/m^2.
398	rgb = pow(max(rgb - c1, vec3(0.0)) / (c2 - rgb * c3), m1) * 100.0;
399
400#elif XFERFUNC != V4L2_XFER_FUNC_NONE
401
402// All others use the transfer function specified by REC 709
403#define XFER(c) (((c) <= -0.081) ? -pow(((c) - 0.099) / -1.099, 1.0 / 0.45) : \
404		 (((c) < 0.081) ? (c) / 4.5 : pow(((c) + 0.099) / 1.099, 1.0 / 0.45)))
405
406	rgb = vec3(XFER(rgb.r), XFER(rgb.g), XFER(rgb.b));
407
408#endif
409
410// Convert the given colorspace to the REC 709/sRGB colorspace. All colors are
411// specified as linear RGB.
412#if COLSP == V4L2_COLORSPACE_SMPTE170M || COLSP == V4L2_COLORSPACE_SMPTE240M || \
413    COLSP == V4L2_COLORSPACE_470_SYSTEM_M || COLSP == V4L2_COLORSPACE_470_SYSTEM_BG || \
414    COLSP == V4L2_COLORSPACE_OPRGB || COLSP == V4L2_COLORSPACE_DCI_P3 || \
415    COLSP == V4L2_COLORSPACE_BT2020
416	rgb = colconv * rgb;
417#endif
418
419// Convert linear RGB to non-linear R'G'B', assuming an sRGB display colorspace.
420
421#define XFER_SRGB(c) (((c) < -0.0031308) ? -1.055 * pow(-(c), 1.0 / 2.4) + 0.055 : \
422	(((c) <= 0.0031308) ? (c) * 12.92 : 1.055 * pow(c, 1.0 / 2.4) - 0.055))
423
424	rgb = vec3(XFER_SRGB(rgb.r), XFER_SRGB(rgb.g), XFER_SRGB(rgb.b));
425
426	fs_FragColor = vec4(rgb, alpha);
427}
428