treewide: remove redundant IS_ERR() before error code check
[linux/fpc-iii.git] / drivers / media / common / v4l2-tpg / v4l2-tpg-core.c
blob50f1e0b28b250d8f20a1c689da5c7263b32117d8
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3 * v4l2-tpg-core.c - Test Pattern Generator
5 * Note: gen_twopix and tpg_gen_text are based on code from vivi.c. See the
6 * vivi.c source for the copyright information of those functions.
8 * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
9 */
11 #include <linux/module.h>
12 #include <media/tpg/v4l2-tpg.h>
14 /* Must remain in sync with enum tpg_pattern */
15 const char * const tpg_pattern_strings[] = {
16 "75% Colorbar",
17 "100% Colorbar",
18 "CSC Colorbar",
19 "Horizontal 100% Colorbar",
20 "100% Color Squares",
21 "100% Black",
22 "100% White",
23 "100% Red",
24 "100% Green",
25 "100% Blue",
26 "16x16 Checkers",
27 "2x2 Checkers",
28 "1x1 Checkers",
29 "2x2 Red/Green Checkers",
30 "1x1 Red/Green Checkers",
31 "Alternating Hor Lines",
32 "Alternating Vert Lines",
33 "One Pixel Wide Cross",
34 "Two Pixels Wide Cross",
35 "Ten Pixels Wide Cross",
36 "Gray Ramp",
37 "Noise",
38 NULL
40 EXPORT_SYMBOL_GPL(tpg_pattern_strings);
42 /* Must remain in sync with enum tpg_aspect */
43 const char * const tpg_aspect_strings[] = {
44 "Source Width x Height",
45 "4x3",
46 "14x9",
47 "16x9",
48 "16x9 Anamorphic",
49 NULL
51 EXPORT_SYMBOL_GPL(tpg_aspect_strings);
54 * Sine table: sin[0] = 127 * sin(-180 degrees)
55 * sin[128] = 127 * sin(0 degrees)
56 * sin[256] = 127 * sin(180 degrees)
58 static const s8 sin[257] = {
59 0, -4, -7, -11, -13, -18, -20, -22, -26, -29, -33, -35, -37, -41, -43, -48,
60 -50, -52, -56, -58, -62, -63, -65, -69, -71, -75, -76, -78, -82, -83, -87, -88,
61 -90, -93, -94, -97, -99, -101, -103, -104, -107, -108, -110, -111, -112, -114, -115, -117,
62 -118, -119, -120, -121, -122, -123, -123, -124, -125, -125, -126, -126, -127, -127, -127, -127,
63 -127, -127, -127, -127, -126, -126, -125, -125, -124, -124, -123, -122, -121, -120, -119, -118,
64 -117, -116, -114, -113, -111, -110, -109, -107, -105, -103, -101, -100, -97, -96, -93, -91,
65 -90, -87, -85, -82, -80, -76, -75, -73, -69, -67, -63, -62, -60, -56, -54, -50,
66 -48, -46, -41, -39, -35, -33, -31, -26, -24, -20, -18, -15, -11, -9, -4, -2,
67 0, 2, 4, 9, 11, 15, 18, 20, 24, 26, 31, 33, 35, 39, 41, 46,
68 48, 50, 54, 56, 60, 62, 64, 67, 69, 73, 75, 76, 80, 82, 85, 87,
69 90, 91, 93, 96, 97, 100, 101, 103, 105, 107, 109, 110, 111, 113, 114, 116,
70 117, 118, 119, 120, 121, 122, 123, 124, 124, 125, 125, 126, 126, 127, 127, 127,
71 127, 127, 127, 127, 127, 126, 126, 125, 125, 124, 123, 123, 122, 121, 120, 119,
72 118, 117, 115, 114, 112, 111, 110, 108, 107, 104, 103, 101, 99, 97, 94, 93,
73 90, 88, 87, 83, 82, 78, 76, 75, 71, 69, 65, 64, 62, 58, 56, 52,
74 50, 48, 43, 41, 37, 35, 33, 29, 26, 22, 20, 18, 13, 11, 7, 4,
78 #define cos(idx) sin[((idx) + 64) % sizeof(sin)]
80 /* Global font descriptor */
81 static const u8 *font8x16;
83 void tpg_set_font(const u8 *f)
85 font8x16 = f;
87 EXPORT_SYMBOL_GPL(tpg_set_font);
89 void tpg_init(struct tpg_data *tpg, unsigned w, unsigned h)
91 memset(tpg, 0, sizeof(*tpg));
92 tpg->scaled_width = tpg->src_width = w;
93 tpg->src_height = tpg->buf_height = h;
94 tpg->crop.width = tpg->compose.width = w;
95 tpg->crop.height = tpg->compose.height = h;
96 tpg->recalc_colors = true;
97 tpg->recalc_square_border = true;
98 tpg->brightness = 128;
99 tpg->contrast = 128;
100 tpg->saturation = 128;
101 tpg->hue = 0;
102 tpg->mv_hor_mode = TPG_MOVE_NONE;
103 tpg->mv_vert_mode = TPG_MOVE_NONE;
104 tpg->field = V4L2_FIELD_NONE;
105 tpg_s_fourcc(tpg, V4L2_PIX_FMT_RGB24);
106 tpg->colorspace = V4L2_COLORSPACE_SRGB;
107 tpg->perc_fill = 100;
108 tpg->hsv_enc = V4L2_HSV_ENC_180;
110 EXPORT_SYMBOL_GPL(tpg_init);
112 int tpg_alloc(struct tpg_data *tpg, unsigned max_w)
114 unsigned pat;
115 unsigned plane;
117 tpg->max_line_width = max_w;
118 for (pat = 0; pat < TPG_MAX_PAT_LINES; pat++) {
119 for (plane = 0; plane < TPG_MAX_PLANES; plane++) {
120 unsigned pixelsz = plane ? 2 : 4;
122 tpg->lines[pat][plane] =
123 vzalloc(array3_size(max_w, 2, pixelsz));
124 if (!tpg->lines[pat][plane])
125 return -ENOMEM;
126 if (plane == 0)
127 continue;
128 tpg->downsampled_lines[pat][plane] =
129 vzalloc(array3_size(max_w, 2, pixelsz));
130 if (!tpg->downsampled_lines[pat][plane])
131 return -ENOMEM;
134 for (plane = 0; plane < TPG_MAX_PLANES; plane++) {
135 unsigned pixelsz = plane ? 2 : 4;
137 tpg->contrast_line[plane] =
138 vzalloc(array_size(pixelsz, max_w));
139 if (!tpg->contrast_line[plane])
140 return -ENOMEM;
141 tpg->black_line[plane] =
142 vzalloc(array_size(pixelsz, max_w));
143 if (!tpg->black_line[plane])
144 return -ENOMEM;
145 tpg->random_line[plane] =
146 vzalloc(array3_size(max_w, 2, pixelsz));
147 if (!tpg->random_line[plane])
148 return -ENOMEM;
150 return 0;
152 EXPORT_SYMBOL_GPL(tpg_alloc);
154 void tpg_free(struct tpg_data *tpg)
156 unsigned pat;
157 unsigned plane;
159 for (pat = 0; pat < TPG_MAX_PAT_LINES; pat++)
160 for (plane = 0; plane < TPG_MAX_PLANES; plane++) {
161 vfree(tpg->lines[pat][plane]);
162 tpg->lines[pat][plane] = NULL;
163 if (plane == 0)
164 continue;
165 vfree(tpg->downsampled_lines[pat][plane]);
166 tpg->downsampled_lines[pat][plane] = NULL;
168 for (plane = 0; plane < TPG_MAX_PLANES; plane++) {
169 vfree(tpg->contrast_line[plane]);
170 vfree(tpg->black_line[plane]);
171 vfree(tpg->random_line[plane]);
172 tpg->contrast_line[plane] = NULL;
173 tpg->black_line[plane] = NULL;
174 tpg->random_line[plane] = NULL;
177 EXPORT_SYMBOL_GPL(tpg_free);
179 bool tpg_s_fourcc(struct tpg_data *tpg, u32 fourcc)
181 tpg->fourcc = fourcc;
182 tpg->planes = 1;
183 tpg->buffers = 1;
184 tpg->recalc_colors = true;
185 tpg->interleaved = false;
186 tpg->vdownsampling[0] = 1;
187 tpg->hdownsampling[0] = 1;
188 tpg->hmask[0] = ~0;
189 tpg->hmask[1] = ~0;
190 tpg->hmask[2] = ~0;
192 switch (fourcc) {
193 case V4L2_PIX_FMT_SBGGR8:
194 case V4L2_PIX_FMT_SGBRG8:
195 case V4L2_PIX_FMT_SGRBG8:
196 case V4L2_PIX_FMT_SRGGB8:
197 case V4L2_PIX_FMT_SBGGR10:
198 case V4L2_PIX_FMT_SGBRG10:
199 case V4L2_PIX_FMT_SGRBG10:
200 case V4L2_PIX_FMT_SRGGB10:
201 case V4L2_PIX_FMT_SBGGR12:
202 case V4L2_PIX_FMT_SGBRG12:
203 case V4L2_PIX_FMT_SGRBG12:
204 case V4L2_PIX_FMT_SRGGB12:
205 case V4L2_PIX_FMT_SBGGR16:
206 case V4L2_PIX_FMT_SGBRG16:
207 case V4L2_PIX_FMT_SGRBG16:
208 case V4L2_PIX_FMT_SRGGB16:
209 tpg->interleaved = true;
210 tpg->vdownsampling[1] = 1;
211 tpg->hdownsampling[1] = 1;
212 tpg->planes = 2;
213 /* fall through */
214 case V4L2_PIX_FMT_RGB332:
215 case V4L2_PIX_FMT_RGB565:
216 case V4L2_PIX_FMT_RGB565X:
217 case V4L2_PIX_FMT_RGB444:
218 case V4L2_PIX_FMT_XRGB444:
219 case V4L2_PIX_FMT_ARGB444:
220 case V4L2_PIX_FMT_RGBX444:
221 case V4L2_PIX_FMT_RGBA444:
222 case V4L2_PIX_FMT_XBGR444:
223 case V4L2_PIX_FMT_ABGR444:
224 case V4L2_PIX_FMT_BGRX444:
225 case V4L2_PIX_FMT_BGRA444:
226 case V4L2_PIX_FMT_RGB555:
227 case V4L2_PIX_FMT_XRGB555:
228 case V4L2_PIX_FMT_ARGB555:
229 case V4L2_PIX_FMT_RGBX555:
230 case V4L2_PIX_FMT_RGBA555:
231 case V4L2_PIX_FMT_XBGR555:
232 case V4L2_PIX_FMT_ABGR555:
233 case V4L2_PIX_FMT_BGRX555:
234 case V4L2_PIX_FMT_BGRA555:
235 case V4L2_PIX_FMT_RGB555X:
236 case V4L2_PIX_FMT_XRGB555X:
237 case V4L2_PIX_FMT_ARGB555X:
238 case V4L2_PIX_FMT_BGR666:
239 case V4L2_PIX_FMT_RGB24:
240 case V4L2_PIX_FMT_BGR24:
241 case V4L2_PIX_FMT_RGB32:
242 case V4L2_PIX_FMT_BGR32:
243 case V4L2_PIX_FMT_XRGB32:
244 case V4L2_PIX_FMT_XBGR32:
245 case V4L2_PIX_FMT_ARGB32:
246 case V4L2_PIX_FMT_ABGR32:
247 case V4L2_PIX_FMT_RGBX32:
248 case V4L2_PIX_FMT_BGRX32:
249 case V4L2_PIX_FMT_RGBA32:
250 case V4L2_PIX_FMT_BGRA32:
251 tpg->color_enc = TGP_COLOR_ENC_RGB;
252 break;
253 case V4L2_PIX_FMT_GREY:
254 case V4L2_PIX_FMT_Y10:
255 case V4L2_PIX_FMT_Y12:
256 case V4L2_PIX_FMT_Y16:
257 case V4L2_PIX_FMT_Y16_BE:
258 case V4L2_PIX_FMT_Z16:
259 tpg->color_enc = TGP_COLOR_ENC_LUMA;
260 break;
261 case V4L2_PIX_FMT_YUV444:
262 case V4L2_PIX_FMT_YUV555:
263 case V4L2_PIX_FMT_YUV565:
264 case V4L2_PIX_FMT_YUV32:
265 case V4L2_PIX_FMT_AYUV32:
266 case V4L2_PIX_FMT_XYUV32:
267 case V4L2_PIX_FMT_VUYA32:
268 case V4L2_PIX_FMT_VUYX32:
269 tpg->color_enc = TGP_COLOR_ENC_YCBCR;
270 break;
271 case V4L2_PIX_FMT_YUV420M:
272 case V4L2_PIX_FMT_YVU420M:
273 tpg->buffers = 3;
274 /* fall through */
275 case V4L2_PIX_FMT_YUV420:
276 case V4L2_PIX_FMT_YVU420:
277 tpg->vdownsampling[1] = 2;
278 tpg->vdownsampling[2] = 2;
279 tpg->hdownsampling[1] = 2;
280 tpg->hdownsampling[2] = 2;
281 tpg->planes = 3;
282 tpg->color_enc = TGP_COLOR_ENC_YCBCR;
283 break;
284 case V4L2_PIX_FMT_YUV422M:
285 case V4L2_PIX_FMT_YVU422M:
286 tpg->buffers = 3;
287 /* fall through */
288 case V4L2_PIX_FMT_YUV422P:
289 tpg->vdownsampling[1] = 1;
290 tpg->vdownsampling[2] = 1;
291 tpg->hdownsampling[1] = 2;
292 tpg->hdownsampling[2] = 2;
293 tpg->planes = 3;
294 tpg->color_enc = TGP_COLOR_ENC_YCBCR;
295 break;
296 case V4L2_PIX_FMT_NV16M:
297 case V4L2_PIX_FMT_NV61M:
298 tpg->buffers = 2;
299 /* fall through */
300 case V4L2_PIX_FMT_NV16:
301 case V4L2_PIX_FMT_NV61:
302 tpg->vdownsampling[1] = 1;
303 tpg->hdownsampling[1] = 1;
304 tpg->hmask[1] = ~1;
305 tpg->planes = 2;
306 tpg->color_enc = TGP_COLOR_ENC_YCBCR;
307 break;
308 case V4L2_PIX_FMT_NV12M:
309 case V4L2_PIX_FMT_NV21M:
310 tpg->buffers = 2;
311 /* fall through */
312 case V4L2_PIX_FMT_NV12:
313 case V4L2_PIX_FMT_NV21:
314 tpg->vdownsampling[1] = 2;
315 tpg->hdownsampling[1] = 1;
316 tpg->hmask[1] = ~1;
317 tpg->planes = 2;
318 tpg->color_enc = TGP_COLOR_ENC_YCBCR;
319 break;
320 case V4L2_PIX_FMT_YUV444M:
321 case V4L2_PIX_FMT_YVU444M:
322 tpg->buffers = 3;
323 tpg->planes = 3;
324 tpg->vdownsampling[1] = 1;
325 tpg->vdownsampling[2] = 1;
326 tpg->hdownsampling[1] = 1;
327 tpg->hdownsampling[2] = 1;
328 tpg->color_enc = TGP_COLOR_ENC_YCBCR;
329 break;
330 case V4L2_PIX_FMT_NV24:
331 case V4L2_PIX_FMT_NV42:
332 tpg->vdownsampling[1] = 1;
333 tpg->hdownsampling[1] = 1;
334 tpg->planes = 2;
335 tpg->color_enc = TGP_COLOR_ENC_YCBCR;
336 break;
337 case V4L2_PIX_FMT_YUYV:
338 case V4L2_PIX_FMT_UYVY:
339 case V4L2_PIX_FMT_YVYU:
340 case V4L2_PIX_FMT_VYUY:
341 tpg->hmask[0] = ~1;
342 tpg->color_enc = TGP_COLOR_ENC_YCBCR;
343 break;
344 case V4L2_PIX_FMT_HSV24:
345 case V4L2_PIX_FMT_HSV32:
346 tpg->color_enc = TGP_COLOR_ENC_HSV;
347 break;
348 default:
349 return false;
352 switch (fourcc) {
353 case V4L2_PIX_FMT_GREY:
354 case V4L2_PIX_FMT_RGB332:
355 tpg->twopixelsize[0] = 2;
356 break;
357 case V4L2_PIX_FMT_RGB565:
358 case V4L2_PIX_FMT_RGB565X:
359 case V4L2_PIX_FMT_RGB444:
360 case V4L2_PIX_FMT_XRGB444:
361 case V4L2_PIX_FMT_ARGB444:
362 case V4L2_PIX_FMT_RGBX444:
363 case V4L2_PIX_FMT_RGBA444:
364 case V4L2_PIX_FMT_XBGR444:
365 case V4L2_PIX_FMT_ABGR444:
366 case V4L2_PIX_FMT_BGRX444:
367 case V4L2_PIX_FMT_BGRA444:
368 case V4L2_PIX_FMT_RGB555:
369 case V4L2_PIX_FMT_XRGB555:
370 case V4L2_PIX_FMT_ARGB555:
371 case V4L2_PIX_FMT_RGBX555:
372 case V4L2_PIX_FMT_RGBA555:
373 case V4L2_PIX_FMT_XBGR555:
374 case V4L2_PIX_FMT_ABGR555:
375 case V4L2_PIX_FMT_BGRX555:
376 case V4L2_PIX_FMT_BGRA555:
377 case V4L2_PIX_FMT_RGB555X:
378 case V4L2_PIX_FMT_XRGB555X:
379 case V4L2_PIX_FMT_ARGB555X:
380 case V4L2_PIX_FMT_YUYV:
381 case V4L2_PIX_FMT_UYVY:
382 case V4L2_PIX_FMT_YVYU:
383 case V4L2_PIX_FMT_VYUY:
384 case V4L2_PIX_FMT_YUV444:
385 case V4L2_PIX_FMT_YUV555:
386 case V4L2_PIX_FMT_YUV565:
387 case V4L2_PIX_FMT_Y10:
388 case V4L2_PIX_FMT_Y12:
389 case V4L2_PIX_FMT_Y16:
390 case V4L2_PIX_FMT_Y16_BE:
391 case V4L2_PIX_FMT_Z16:
392 tpg->twopixelsize[0] = 2 * 2;
393 break;
394 case V4L2_PIX_FMT_RGB24:
395 case V4L2_PIX_FMT_BGR24:
396 case V4L2_PIX_FMT_HSV24:
397 tpg->twopixelsize[0] = 2 * 3;
398 break;
399 case V4L2_PIX_FMT_BGR666:
400 case V4L2_PIX_FMT_RGB32:
401 case V4L2_PIX_FMT_BGR32:
402 case V4L2_PIX_FMT_XRGB32:
403 case V4L2_PIX_FMT_XBGR32:
404 case V4L2_PIX_FMT_ARGB32:
405 case V4L2_PIX_FMT_ABGR32:
406 case V4L2_PIX_FMT_RGBX32:
407 case V4L2_PIX_FMT_BGRX32:
408 case V4L2_PIX_FMT_RGBA32:
409 case V4L2_PIX_FMT_BGRA32:
410 case V4L2_PIX_FMT_YUV32:
411 case V4L2_PIX_FMT_AYUV32:
412 case V4L2_PIX_FMT_XYUV32:
413 case V4L2_PIX_FMT_VUYA32:
414 case V4L2_PIX_FMT_VUYX32:
415 case V4L2_PIX_FMT_HSV32:
416 tpg->twopixelsize[0] = 2 * 4;
417 break;
418 case V4L2_PIX_FMT_NV12:
419 case V4L2_PIX_FMT_NV21:
420 case V4L2_PIX_FMT_NV12M:
421 case V4L2_PIX_FMT_NV21M:
422 case V4L2_PIX_FMT_NV16:
423 case V4L2_PIX_FMT_NV61:
424 case V4L2_PIX_FMT_NV16M:
425 case V4L2_PIX_FMT_NV61M:
426 case V4L2_PIX_FMT_SBGGR8:
427 case V4L2_PIX_FMT_SGBRG8:
428 case V4L2_PIX_FMT_SGRBG8:
429 case V4L2_PIX_FMT_SRGGB8:
430 tpg->twopixelsize[0] = 2;
431 tpg->twopixelsize[1] = 2;
432 break;
433 case V4L2_PIX_FMT_SRGGB10:
434 case V4L2_PIX_FMT_SGRBG10:
435 case V4L2_PIX_FMT_SGBRG10:
436 case V4L2_PIX_FMT_SBGGR10:
437 case V4L2_PIX_FMT_SRGGB12:
438 case V4L2_PIX_FMT_SGRBG12:
439 case V4L2_PIX_FMT_SGBRG12:
440 case V4L2_PIX_FMT_SBGGR12:
441 case V4L2_PIX_FMT_SRGGB16:
442 case V4L2_PIX_FMT_SGRBG16:
443 case V4L2_PIX_FMT_SGBRG16:
444 case V4L2_PIX_FMT_SBGGR16:
445 tpg->twopixelsize[0] = 4;
446 tpg->twopixelsize[1] = 4;
447 break;
448 case V4L2_PIX_FMT_YUV444M:
449 case V4L2_PIX_FMT_YVU444M:
450 case V4L2_PIX_FMT_YUV422M:
451 case V4L2_PIX_FMT_YVU422M:
452 case V4L2_PIX_FMT_YUV422P:
453 case V4L2_PIX_FMT_YUV420:
454 case V4L2_PIX_FMT_YVU420:
455 case V4L2_PIX_FMT_YUV420M:
456 case V4L2_PIX_FMT_YVU420M:
457 tpg->twopixelsize[0] = 2;
458 tpg->twopixelsize[1] = 2;
459 tpg->twopixelsize[2] = 2;
460 break;
461 case V4L2_PIX_FMT_NV24:
462 case V4L2_PIX_FMT_NV42:
463 tpg->twopixelsize[0] = 2;
464 tpg->twopixelsize[1] = 4;
465 break;
467 return true;
469 EXPORT_SYMBOL_GPL(tpg_s_fourcc);
471 void tpg_s_crop_compose(struct tpg_data *tpg, const struct v4l2_rect *crop,
472 const struct v4l2_rect *compose)
474 tpg->crop = *crop;
475 tpg->compose = *compose;
476 tpg->scaled_width = (tpg->src_width * tpg->compose.width +
477 tpg->crop.width - 1) / tpg->crop.width;
478 tpg->scaled_width &= ~1;
479 if (tpg->scaled_width > tpg->max_line_width)
480 tpg->scaled_width = tpg->max_line_width;
481 if (tpg->scaled_width < 2)
482 tpg->scaled_width = 2;
483 tpg->recalc_lines = true;
485 EXPORT_SYMBOL_GPL(tpg_s_crop_compose);
487 void tpg_reset_source(struct tpg_data *tpg, unsigned width, unsigned height,
488 u32 field)
490 unsigned p;
492 tpg->src_width = width;
493 tpg->src_height = height;
494 tpg->field = field;
495 tpg->buf_height = height;
496 if (V4L2_FIELD_HAS_T_OR_B(field))
497 tpg->buf_height /= 2;
498 tpg->scaled_width = width;
499 tpg->crop.top = tpg->crop.left = 0;
500 tpg->crop.width = width;
501 tpg->crop.height = height;
502 tpg->compose.top = tpg->compose.left = 0;
503 tpg->compose.width = width;
504 tpg->compose.height = tpg->buf_height;
505 for (p = 0; p < tpg->planes; p++)
506 tpg->bytesperline[p] = (width * tpg->twopixelsize[p]) /
507 (2 * tpg->hdownsampling[p]);
508 tpg->recalc_square_border = true;
510 EXPORT_SYMBOL_GPL(tpg_reset_source);
512 static enum tpg_color tpg_get_textbg_color(struct tpg_data *tpg)
514 switch (tpg->pattern) {
515 case TPG_PAT_BLACK:
516 return TPG_COLOR_100_WHITE;
517 case TPG_PAT_CSC_COLORBAR:
518 return TPG_COLOR_CSC_BLACK;
519 default:
520 return TPG_COLOR_100_BLACK;
524 static enum tpg_color tpg_get_textfg_color(struct tpg_data *tpg)
526 switch (tpg->pattern) {
527 case TPG_PAT_75_COLORBAR:
528 case TPG_PAT_CSC_COLORBAR:
529 return TPG_COLOR_CSC_WHITE;
530 case TPG_PAT_BLACK:
531 return TPG_COLOR_100_BLACK;
532 default:
533 return TPG_COLOR_100_WHITE;
537 static inline int rec709_to_linear(int v)
539 v = clamp(v, 0, 0xff0);
540 return tpg_rec709_to_linear[v];
543 static inline int linear_to_rec709(int v)
545 v = clamp(v, 0, 0xff0);
546 return tpg_linear_to_rec709[v];
549 static void color_to_hsv(struct tpg_data *tpg, int r, int g, int b,
550 int *h, int *s, int *v)
552 int max_rgb, min_rgb, diff_rgb;
553 int aux;
554 int third;
555 int third_size;
557 r >>= 4;
558 g >>= 4;
559 b >>= 4;
561 /* Value */
562 max_rgb = max3(r, g, b);
563 *v = max_rgb;
564 if (!max_rgb) {
565 *h = 0;
566 *s = 0;
567 return;
570 /* Saturation */
571 min_rgb = min3(r, g, b);
572 diff_rgb = max_rgb - min_rgb;
573 aux = 255 * diff_rgb;
574 aux += max_rgb / 2;
575 aux /= max_rgb;
576 *s = aux;
577 if (!aux) {
578 *h = 0;
579 return;
582 third_size = (tpg->real_hsv_enc == V4L2_HSV_ENC_180) ? 60 : 85;
584 /* Hue */
585 if (max_rgb == r) {
586 aux = g - b;
587 third = 0;
588 } else if (max_rgb == g) {
589 aux = b - r;
590 third = third_size;
591 } else {
592 aux = r - g;
593 third = third_size * 2;
596 aux *= third_size / 2;
597 aux += diff_rgb / 2;
598 aux /= diff_rgb;
599 aux += third;
601 /* Clamp Hue */
602 if (tpg->real_hsv_enc == V4L2_HSV_ENC_180) {
603 if (aux < 0)
604 aux += 180;
605 else if (aux > 180)
606 aux -= 180;
607 } else {
608 aux = aux & 0xff;
611 *h = aux;
614 static void rgb2ycbcr(const int m[3][3], int r, int g, int b,
615 int y_offset, int *y, int *cb, int *cr)
617 *y = ((m[0][0] * r + m[0][1] * g + m[0][2] * b) >> 16) + (y_offset << 4);
618 *cb = ((m[1][0] * r + m[1][1] * g + m[1][2] * b) >> 16) + (128 << 4);
619 *cr = ((m[2][0] * r + m[2][1] * g + m[2][2] * b) >> 16) + (128 << 4);
622 static void color_to_ycbcr(struct tpg_data *tpg, int r, int g, int b,
623 int *y, int *cb, int *cr)
625 #define COEFF(v, r) ((int)(0.5 + (v) * (r) * 256.0))
627 static const int bt601[3][3] = {
628 { COEFF(0.299, 219), COEFF(0.587, 219), COEFF(0.114, 219) },
629 { COEFF(-0.1687, 224), COEFF(-0.3313, 224), COEFF(0.5, 224) },
630 { COEFF(0.5, 224), COEFF(-0.4187, 224), COEFF(-0.0813, 224) },
632 static const int bt601_full[3][3] = {
633 { COEFF(0.299, 255), COEFF(0.587, 255), COEFF(0.114, 255) },
634 { COEFF(-0.1687, 255), COEFF(-0.3313, 255), COEFF(0.5, 255) },
635 { COEFF(0.5, 255), COEFF(-0.4187, 255), COEFF(-0.0813, 255) },
637 static const int rec709[3][3] = {
638 { COEFF(0.2126, 219), COEFF(0.7152, 219), COEFF(0.0722, 219) },
639 { COEFF(-0.1146, 224), COEFF(-0.3854, 224), COEFF(0.5, 224) },
640 { COEFF(0.5, 224), COEFF(-0.4542, 224), COEFF(-0.0458, 224) },
642 static const int rec709_full[3][3] = {
643 { COEFF(0.2126, 255), COEFF(0.7152, 255), COEFF(0.0722, 255) },
644 { COEFF(-0.1146, 255), COEFF(-0.3854, 255), COEFF(0.5, 255) },
645 { COEFF(0.5, 255), COEFF(-0.4542, 255), COEFF(-0.0458, 255) },
647 static const int smpte240m[3][3] = {
648 { COEFF(0.212, 219), COEFF(0.701, 219), COEFF(0.087, 219) },
649 { COEFF(-0.116, 224), COEFF(-0.384, 224), COEFF(0.5, 224) },
650 { COEFF(0.5, 224), COEFF(-0.445, 224), COEFF(-0.055, 224) },
652 static const int smpte240m_full[3][3] = {
653 { COEFF(0.212, 255), COEFF(0.701, 255), COEFF(0.087, 255) },
654 { COEFF(-0.116, 255), COEFF(-0.384, 255), COEFF(0.5, 255) },
655 { COEFF(0.5, 255), COEFF(-0.445, 255), COEFF(-0.055, 255) },
657 static const int bt2020[3][3] = {
658 { COEFF(0.2627, 219), COEFF(0.6780, 219), COEFF(0.0593, 219) },
659 { COEFF(-0.1396, 224), COEFF(-0.3604, 224), COEFF(0.5, 224) },
660 { COEFF(0.5, 224), COEFF(-0.4598, 224), COEFF(-0.0402, 224) },
662 static const int bt2020_full[3][3] = {
663 { COEFF(0.2627, 255), COEFF(0.6780, 255), COEFF(0.0593, 255) },
664 { COEFF(-0.1396, 255), COEFF(-0.3604, 255), COEFF(0.5, 255) },
665 { COEFF(0.5, 255), COEFF(-0.4598, 255), COEFF(-0.0402, 255) },
667 static const int bt2020c[4] = {
668 COEFF(1.0 / 1.9404, 224), COEFF(1.0 / 1.5816, 224),
669 COEFF(1.0 / 1.7184, 224), COEFF(1.0 / 0.9936, 224),
671 static const int bt2020c_full[4] = {
672 COEFF(1.0 / 1.9404, 255), COEFF(1.0 / 1.5816, 255),
673 COEFF(1.0 / 1.7184, 255), COEFF(1.0 / 0.9936, 255),
676 bool full = tpg->real_quantization == V4L2_QUANTIZATION_FULL_RANGE;
677 unsigned y_offset = full ? 0 : 16;
678 int lin_y, yc;
680 switch (tpg->real_ycbcr_enc) {
681 case V4L2_YCBCR_ENC_601:
682 rgb2ycbcr(full ? bt601_full : bt601, r, g, b, y_offset, y, cb, cr);
683 break;
684 case V4L2_YCBCR_ENC_XV601:
685 /* Ignore quantization range, there is only one possible
686 * Y'CbCr encoding. */
687 rgb2ycbcr(bt601, r, g, b, 16, y, cb, cr);
688 break;
689 case V4L2_YCBCR_ENC_XV709:
690 /* Ignore quantization range, there is only one possible
691 * Y'CbCr encoding. */
692 rgb2ycbcr(rec709, r, g, b, 16, y, cb, cr);
693 break;
694 case V4L2_YCBCR_ENC_BT2020:
695 rgb2ycbcr(full ? bt2020_full : bt2020, r, g, b, y_offset, y, cb, cr);
696 break;
697 case V4L2_YCBCR_ENC_BT2020_CONST_LUM:
698 lin_y = (COEFF(0.2627, 255) * rec709_to_linear(r) +
699 COEFF(0.6780, 255) * rec709_to_linear(g) +
700 COEFF(0.0593, 255) * rec709_to_linear(b)) >> 16;
701 yc = linear_to_rec709(lin_y);
702 *y = full ? yc : (yc * 219) / 255 + (16 << 4);
703 if (b <= yc)
704 *cb = (((b - yc) * (full ? bt2020c_full[0] : bt2020c[0])) >> 16) + (128 << 4);
705 else
706 *cb = (((b - yc) * (full ? bt2020c_full[1] : bt2020c[1])) >> 16) + (128 << 4);
707 if (r <= yc)
708 *cr = (((r - yc) * (full ? bt2020c_full[2] : bt2020c[2])) >> 16) + (128 << 4);
709 else
710 *cr = (((r - yc) * (full ? bt2020c_full[3] : bt2020c[3])) >> 16) + (128 << 4);
711 break;
712 case V4L2_YCBCR_ENC_SMPTE240M:
713 rgb2ycbcr(full ? smpte240m_full : smpte240m, r, g, b, y_offset, y, cb, cr);
714 break;
715 case V4L2_YCBCR_ENC_709:
716 default:
717 rgb2ycbcr(full ? rec709_full : rec709, r, g, b, y_offset, y, cb, cr);
718 break;
722 static void ycbcr2rgb(const int m[3][3], int y, int cb, int cr,
723 int y_offset, int *r, int *g, int *b)
725 y -= y_offset << 4;
726 cb -= 128 << 4;
727 cr -= 128 << 4;
728 *r = m[0][0] * y + m[0][1] * cb + m[0][2] * cr;
729 *g = m[1][0] * y + m[1][1] * cb + m[1][2] * cr;
730 *b = m[2][0] * y + m[2][1] * cb + m[2][2] * cr;
731 *r = clamp(*r >> 12, 0, 0xff0);
732 *g = clamp(*g >> 12, 0, 0xff0);
733 *b = clamp(*b >> 12, 0, 0xff0);
736 static void ycbcr_to_color(struct tpg_data *tpg, int y, int cb, int cr,
737 int *r, int *g, int *b)
739 #undef COEFF
740 #define COEFF(v, r) ((int)(0.5 + (v) * ((255.0 * 255.0 * 16.0) / (r))))
741 static const int bt601[3][3] = {
742 { COEFF(1, 219), COEFF(0, 224), COEFF(1.4020, 224) },
743 { COEFF(1, 219), COEFF(-0.3441, 224), COEFF(-0.7141, 224) },
744 { COEFF(1, 219), COEFF(1.7720, 224), COEFF(0, 224) },
746 static const int bt601_full[3][3] = {
747 { COEFF(1, 255), COEFF(0, 255), COEFF(1.4020, 255) },
748 { COEFF(1, 255), COEFF(-0.3441, 255), COEFF(-0.7141, 255) },
749 { COEFF(1, 255), COEFF(1.7720, 255), COEFF(0, 255) },
751 static const int rec709[3][3] = {
752 { COEFF(1, 219), COEFF(0, 224), COEFF(1.5748, 224) },
753 { COEFF(1, 219), COEFF(-0.1873, 224), COEFF(-0.4681, 224) },
754 { COEFF(1, 219), COEFF(1.8556, 224), COEFF(0, 224) },
756 static const int rec709_full[3][3] = {
757 { COEFF(1, 255), COEFF(0, 255), COEFF(1.5748, 255) },
758 { COEFF(1, 255), COEFF(-0.1873, 255), COEFF(-0.4681, 255) },
759 { COEFF(1, 255), COEFF(1.8556, 255), COEFF(0, 255) },
761 static const int smpte240m[3][3] = {
762 { COEFF(1, 219), COEFF(0, 224), COEFF(1.5756, 224) },
763 { COEFF(1, 219), COEFF(-0.2253, 224), COEFF(-0.4767, 224) },
764 { COEFF(1, 219), COEFF(1.8270, 224), COEFF(0, 224) },
766 static const int smpte240m_full[3][3] = {
767 { COEFF(1, 255), COEFF(0, 255), COEFF(1.5756, 255) },
768 { COEFF(1, 255), COEFF(-0.2253, 255), COEFF(-0.4767, 255) },
769 { COEFF(1, 255), COEFF(1.8270, 255), COEFF(0, 255) },
771 static const int bt2020[3][3] = {
772 { COEFF(1, 219), COEFF(0, 224), COEFF(1.4746, 224) },
773 { COEFF(1, 219), COEFF(-0.1646, 224), COEFF(-0.5714, 224) },
774 { COEFF(1, 219), COEFF(1.8814, 224), COEFF(0, 224) },
776 static const int bt2020_full[3][3] = {
777 { COEFF(1, 255), COEFF(0, 255), COEFF(1.4746, 255) },
778 { COEFF(1, 255), COEFF(-0.1646, 255), COEFF(-0.5714, 255) },
779 { COEFF(1, 255), COEFF(1.8814, 255), COEFF(0, 255) },
781 static const int bt2020c[4] = {
782 COEFF(1.9404, 224), COEFF(1.5816, 224),
783 COEFF(1.7184, 224), COEFF(0.9936, 224),
785 static const int bt2020c_full[4] = {
786 COEFF(1.9404, 255), COEFF(1.5816, 255),
787 COEFF(1.7184, 255), COEFF(0.9936, 255),
790 bool full = tpg->real_quantization == V4L2_QUANTIZATION_FULL_RANGE;
791 unsigned y_offset = full ? 0 : 16;
792 int y_fac = full ? COEFF(1.0, 255) : COEFF(1.0, 219);
793 int lin_r, lin_g, lin_b, lin_y;
795 switch (tpg->real_ycbcr_enc) {
796 case V4L2_YCBCR_ENC_601:
797 ycbcr2rgb(full ? bt601_full : bt601, y, cb, cr, y_offset, r, g, b);
798 break;
799 case V4L2_YCBCR_ENC_XV601:
800 /* Ignore quantization range, there is only one possible
801 * Y'CbCr encoding. */
802 ycbcr2rgb(bt601, y, cb, cr, 16, r, g, b);
803 break;
804 case V4L2_YCBCR_ENC_XV709:
805 /* Ignore quantization range, there is only one possible
806 * Y'CbCr encoding. */
807 ycbcr2rgb(rec709, y, cb, cr, 16, r, g, b);
808 break;
809 case V4L2_YCBCR_ENC_BT2020:
810 ycbcr2rgb(full ? bt2020_full : bt2020, y, cb, cr, y_offset, r, g, b);
811 break;
812 case V4L2_YCBCR_ENC_BT2020_CONST_LUM:
813 y -= full ? 0 : 16 << 4;
814 cb -= 128 << 4;
815 cr -= 128 << 4;
817 if (cb <= 0)
818 *b = y_fac * y + (full ? bt2020c_full[0] : bt2020c[0]) * cb;
819 else
820 *b = y_fac * y + (full ? bt2020c_full[1] : bt2020c[1]) * cb;
821 *b = *b >> 12;
822 if (cr <= 0)
823 *r = y_fac * y + (full ? bt2020c_full[2] : bt2020c[2]) * cr;
824 else
825 *r = y_fac * y + (full ? bt2020c_full[3] : bt2020c[3]) * cr;
826 *r = *r >> 12;
827 lin_r = rec709_to_linear(*r);
828 lin_b = rec709_to_linear(*b);
829 lin_y = rec709_to_linear((y * 255) / (full ? 255 : 219));
831 lin_g = COEFF(1.0 / 0.6780, 255) * lin_y -
832 COEFF(0.2627 / 0.6780, 255) * lin_r -
833 COEFF(0.0593 / 0.6780, 255) * lin_b;
834 *g = linear_to_rec709(lin_g >> 12);
835 break;
836 case V4L2_YCBCR_ENC_SMPTE240M:
837 ycbcr2rgb(full ? smpte240m_full : smpte240m, y, cb, cr, y_offset, r, g, b);
838 break;
839 case V4L2_YCBCR_ENC_709:
840 default:
841 ycbcr2rgb(full ? rec709_full : rec709, y, cb, cr, y_offset, r, g, b);
842 break;
846 /* precalculate color bar values to speed up rendering */
847 static void precalculate_color(struct tpg_data *tpg, int k)
849 int col = k;
850 int r = tpg_colors[col].r;
851 int g = tpg_colors[col].g;
852 int b = tpg_colors[col].b;
853 int y, cb, cr;
854 bool ycbcr_valid = false;
856 if (k == TPG_COLOR_TEXTBG) {
857 col = tpg_get_textbg_color(tpg);
859 r = tpg_colors[col].r;
860 g = tpg_colors[col].g;
861 b = tpg_colors[col].b;
862 } else if (k == TPG_COLOR_TEXTFG) {
863 col = tpg_get_textfg_color(tpg);
865 r = tpg_colors[col].r;
866 g = tpg_colors[col].g;
867 b = tpg_colors[col].b;
868 } else if (tpg->pattern == TPG_PAT_NOISE) {
869 r = g = b = prandom_u32_max(256);
870 } else if (k == TPG_COLOR_RANDOM) {
871 r = g = b = tpg->qual_offset + prandom_u32_max(196);
872 } else if (k >= TPG_COLOR_RAMP) {
873 r = g = b = k - TPG_COLOR_RAMP;
876 if (tpg->pattern == TPG_PAT_CSC_COLORBAR && col <= TPG_COLOR_CSC_BLACK) {
877 r = tpg_csc_colors[tpg->colorspace][tpg->real_xfer_func][col].r;
878 g = tpg_csc_colors[tpg->colorspace][tpg->real_xfer_func][col].g;
879 b = tpg_csc_colors[tpg->colorspace][tpg->real_xfer_func][col].b;
880 } else {
881 r <<= 4;
882 g <<= 4;
883 b <<= 4;
886 if (tpg->qual == TPG_QUAL_GRAY ||
887 tpg->color_enc == TGP_COLOR_ENC_LUMA) {
888 /* Rec. 709 Luma function */
889 /* (0.2126, 0.7152, 0.0722) * (255 * 256) */
890 r = g = b = (13879 * r + 46688 * g + 4713 * b) >> 16;
894 * The assumption is that the RGB output is always full range,
895 * so only if the rgb_range overrides the 'real' rgb range do
896 * we need to convert the RGB values.
898 * Remember that r, g and b are still in the 0 - 0xff0 range.
900 if (tpg->real_rgb_range == V4L2_DV_RGB_RANGE_LIMITED &&
901 tpg->rgb_range == V4L2_DV_RGB_RANGE_FULL &&
902 tpg->color_enc == TGP_COLOR_ENC_RGB) {
904 * Convert from full range (which is what r, g and b are)
905 * to limited range (which is the 'real' RGB range), which
906 * is then interpreted as full range.
908 r = (r * 219) / 255 + (16 << 4);
909 g = (g * 219) / 255 + (16 << 4);
910 b = (b * 219) / 255 + (16 << 4);
911 } else if (tpg->real_rgb_range != V4L2_DV_RGB_RANGE_LIMITED &&
912 tpg->rgb_range == V4L2_DV_RGB_RANGE_LIMITED &&
913 tpg->color_enc == TGP_COLOR_ENC_RGB) {
916 * Clamp r, g and b to the limited range and convert to full
917 * range since that's what we deliver.
919 r = clamp(r, 16 << 4, 235 << 4);
920 g = clamp(g, 16 << 4, 235 << 4);
921 b = clamp(b, 16 << 4, 235 << 4);
922 r = (r - (16 << 4)) * 255 / 219;
923 g = (g - (16 << 4)) * 255 / 219;
924 b = (b - (16 << 4)) * 255 / 219;
927 if ((tpg->brightness != 128 || tpg->contrast != 128 ||
928 tpg->saturation != 128 || tpg->hue) &&
929 tpg->color_enc != TGP_COLOR_ENC_LUMA) {
930 /* Implement these operations */
931 int tmp_cb, tmp_cr;
933 /* First convert to YCbCr */
935 color_to_ycbcr(tpg, r, g, b, &y, &cb, &cr);
937 y = (16 << 4) + ((y - (16 << 4)) * tpg->contrast) / 128;
938 y += (tpg->brightness << 4) - (128 << 4);
940 cb -= 128 << 4;
941 cr -= 128 << 4;
942 tmp_cb = (cb * cos(128 + tpg->hue)) / 127 + (cr * sin[128 + tpg->hue]) / 127;
943 tmp_cr = (cr * cos(128 + tpg->hue)) / 127 - (cb * sin[128 + tpg->hue]) / 127;
945 cb = (128 << 4) + (tmp_cb * tpg->contrast * tpg->saturation) / (128 * 128);
946 cr = (128 << 4) + (tmp_cr * tpg->contrast * tpg->saturation) / (128 * 128);
947 if (tpg->color_enc == TGP_COLOR_ENC_YCBCR)
948 ycbcr_valid = true;
949 else
950 ycbcr_to_color(tpg, y, cb, cr, &r, &g, &b);
951 } else if ((tpg->brightness != 128 || tpg->contrast != 128) &&
952 tpg->color_enc == TGP_COLOR_ENC_LUMA) {
953 r = (16 << 4) + ((r - (16 << 4)) * tpg->contrast) / 128;
954 r += (tpg->brightness << 4) - (128 << 4);
957 switch (tpg->color_enc) {
958 case TGP_COLOR_ENC_HSV:
960 int h, s, v;
962 color_to_hsv(tpg, r, g, b, &h, &s, &v);
963 tpg->colors[k][0] = h;
964 tpg->colors[k][1] = s;
965 tpg->colors[k][2] = v;
966 break;
968 case TGP_COLOR_ENC_YCBCR:
970 /* Convert to YCbCr */
971 if (!ycbcr_valid)
972 color_to_ycbcr(tpg, r, g, b, &y, &cb, &cr);
974 y >>= 4;
975 cb >>= 4;
976 cr >>= 4;
978 * XV601/709 use the header/footer margins to encode R', G'
979 * and B' values outside the range [0-1]. So do not clamp
980 * XV601/709 values.
982 if (tpg->real_quantization == V4L2_QUANTIZATION_LIM_RANGE &&
983 tpg->real_ycbcr_enc != V4L2_YCBCR_ENC_XV601 &&
984 tpg->real_ycbcr_enc != V4L2_YCBCR_ENC_XV709) {
985 y = clamp(y, 16, 235);
986 cb = clamp(cb, 16, 240);
987 cr = clamp(cr, 16, 240);
988 } else {
989 y = clamp(y, 1, 254);
990 cb = clamp(cb, 1, 254);
991 cr = clamp(cr, 1, 254);
993 switch (tpg->fourcc) {
994 case V4L2_PIX_FMT_YUV444:
995 y >>= 4;
996 cb >>= 4;
997 cr >>= 4;
998 break;
999 case V4L2_PIX_FMT_YUV555:
1000 y >>= 3;
1001 cb >>= 3;
1002 cr >>= 3;
1003 break;
1004 case V4L2_PIX_FMT_YUV565:
1005 y >>= 3;
1006 cb >>= 2;
1007 cr >>= 3;
1008 break;
1010 tpg->colors[k][0] = y;
1011 tpg->colors[k][1] = cb;
1012 tpg->colors[k][2] = cr;
1013 break;
1015 case TGP_COLOR_ENC_LUMA:
1017 tpg->colors[k][0] = r >> 4;
1018 break;
1020 case TGP_COLOR_ENC_RGB:
1022 if (tpg->real_quantization == V4L2_QUANTIZATION_LIM_RANGE) {
1023 r = (r * 219) / 255 + (16 << 4);
1024 g = (g * 219) / 255 + (16 << 4);
1025 b = (b * 219) / 255 + (16 << 4);
1027 switch (tpg->fourcc) {
1028 case V4L2_PIX_FMT_RGB332:
1029 r >>= 9;
1030 g >>= 9;
1031 b >>= 10;
1032 break;
1033 case V4L2_PIX_FMT_RGB565:
1034 case V4L2_PIX_FMT_RGB565X:
1035 r >>= 7;
1036 g >>= 6;
1037 b >>= 7;
1038 break;
1039 case V4L2_PIX_FMT_RGB444:
1040 case V4L2_PIX_FMT_XRGB444:
1041 case V4L2_PIX_FMT_ARGB444:
1042 case V4L2_PIX_FMT_RGBX444:
1043 case V4L2_PIX_FMT_RGBA444:
1044 case V4L2_PIX_FMT_XBGR444:
1045 case V4L2_PIX_FMT_ABGR444:
1046 case V4L2_PIX_FMT_BGRX444:
1047 case V4L2_PIX_FMT_BGRA444:
1048 r >>= 8;
1049 g >>= 8;
1050 b >>= 8;
1051 break;
1052 case V4L2_PIX_FMT_RGB555:
1053 case V4L2_PIX_FMT_XRGB555:
1054 case V4L2_PIX_FMT_ARGB555:
1055 case V4L2_PIX_FMT_RGBX555:
1056 case V4L2_PIX_FMT_RGBA555:
1057 case V4L2_PIX_FMT_XBGR555:
1058 case V4L2_PIX_FMT_ABGR555:
1059 case V4L2_PIX_FMT_BGRX555:
1060 case V4L2_PIX_FMT_BGRA555:
1061 case V4L2_PIX_FMT_RGB555X:
1062 case V4L2_PIX_FMT_XRGB555X:
1063 case V4L2_PIX_FMT_ARGB555X:
1064 r >>= 7;
1065 g >>= 7;
1066 b >>= 7;
1067 break;
1068 case V4L2_PIX_FMT_BGR666:
1069 r >>= 6;
1070 g >>= 6;
1071 b >>= 6;
1072 break;
1073 default:
1074 r >>= 4;
1075 g >>= 4;
1076 b >>= 4;
1077 break;
1080 tpg->colors[k][0] = r;
1081 tpg->colors[k][1] = g;
1082 tpg->colors[k][2] = b;
1083 break;
1088 static void tpg_precalculate_colors(struct tpg_data *tpg)
1090 int k;
1092 for (k = 0; k < TPG_COLOR_MAX; k++)
1093 precalculate_color(tpg, k);
1096 /* 'odd' is true for pixels 1, 3, 5, etc. and false for pixels 0, 2, 4, etc. */
1097 static void gen_twopix(struct tpg_data *tpg,
1098 u8 buf[TPG_MAX_PLANES][8], int color, bool odd)
1100 unsigned offset = odd * tpg->twopixelsize[0] / 2;
1101 u8 alpha = tpg->alpha_component;
1102 u8 r_y_h, g_u_s, b_v;
1104 if (tpg->alpha_red_only && color != TPG_COLOR_CSC_RED &&
1105 color != TPG_COLOR_100_RED &&
1106 color != TPG_COLOR_75_RED)
1107 alpha = 0;
1108 if (color == TPG_COLOR_RANDOM)
1109 precalculate_color(tpg, color);
1110 r_y_h = tpg->colors[color][0]; /* R or precalculated Y, H */
1111 g_u_s = tpg->colors[color][1]; /* G or precalculated U, V */
1112 b_v = tpg->colors[color][2]; /* B or precalculated V */
1114 switch (tpg->fourcc) {
1115 case V4L2_PIX_FMT_GREY:
1116 buf[0][offset] = r_y_h;
1117 break;
1118 case V4L2_PIX_FMT_Y10:
1119 buf[0][offset] = (r_y_h << 2) & 0xff;
1120 buf[0][offset+1] = r_y_h >> 6;
1121 break;
1122 case V4L2_PIX_FMT_Y12:
1123 buf[0][offset] = (r_y_h << 4) & 0xff;
1124 buf[0][offset+1] = r_y_h >> 4;
1125 break;
1126 case V4L2_PIX_FMT_Y16:
1127 case V4L2_PIX_FMT_Z16:
1129 * Ideally both bytes should be set to r_y_h, but then you won't
1130 * be able to detect endian problems. So keep it 0 except for
1131 * the corner case where r_y_h is 0xff so white really will be
1132 * white (0xffff).
1134 buf[0][offset] = r_y_h == 0xff ? r_y_h : 0;
1135 buf[0][offset+1] = r_y_h;
1136 break;
1137 case V4L2_PIX_FMT_Y16_BE:
1138 /* See comment for V4L2_PIX_FMT_Y16 above */
1139 buf[0][offset] = r_y_h;
1140 buf[0][offset+1] = r_y_h == 0xff ? r_y_h : 0;
1141 break;
1142 case V4L2_PIX_FMT_YUV422M:
1143 case V4L2_PIX_FMT_YUV422P:
1144 case V4L2_PIX_FMT_YUV420:
1145 case V4L2_PIX_FMT_YUV420M:
1146 buf[0][offset] = r_y_h;
1147 if (odd) {
1148 buf[1][0] = (buf[1][0] + g_u_s) / 2;
1149 buf[2][0] = (buf[2][0] + b_v) / 2;
1150 buf[1][1] = buf[1][0];
1151 buf[2][1] = buf[2][0];
1152 break;
1154 buf[1][0] = g_u_s;
1155 buf[2][0] = b_v;
1156 break;
1157 case V4L2_PIX_FMT_YVU422M:
1158 case V4L2_PIX_FMT_YVU420:
1159 case V4L2_PIX_FMT_YVU420M:
1160 buf[0][offset] = r_y_h;
1161 if (odd) {
1162 buf[1][0] = (buf[1][0] + b_v) / 2;
1163 buf[2][0] = (buf[2][0] + g_u_s) / 2;
1164 buf[1][1] = buf[1][0];
1165 buf[2][1] = buf[2][0];
1166 break;
1168 buf[1][0] = b_v;
1169 buf[2][0] = g_u_s;
1170 break;
1172 case V4L2_PIX_FMT_NV12:
1173 case V4L2_PIX_FMT_NV12M:
1174 case V4L2_PIX_FMT_NV16:
1175 case V4L2_PIX_FMT_NV16M:
1176 buf[0][offset] = r_y_h;
1177 if (odd) {
1178 buf[1][0] = (buf[1][0] + g_u_s) / 2;
1179 buf[1][1] = (buf[1][1] + b_v) / 2;
1180 break;
1182 buf[1][0] = g_u_s;
1183 buf[1][1] = b_v;
1184 break;
1185 case V4L2_PIX_FMT_NV21:
1186 case V4L2_PIX_FMT_NV21M:
1187 case V4L2_PIX_FMT_NV61:
1188 case V4L2_PIX_FMT_NV61M:
1189 buf[0][offset] = r_y_h;
1190 if (odd) {
1191 buf[1][0] = (buf[1][0] + b_v) / 2;
1192 buf[1][1] = (buf[1][1] + g_u_s) / 2;
1193 break;
1195 buf[1][0] = b_v;
1196 buf[1][1] = g_u_s;
1197 break;
1199 case V4L2_PIX_FMT_YUV444M:
1200 buf[0][offset] = r_y_h;
1201 buf[1][offset] = g_u_s;
1202 buf[2][offset] = b_v;
1203 break;
1205 case V4L2_PIX_FMT_YVU444M:
1206 buf[0][offset] = r_y_h;
1207 buf[1][offset] = b_v;
1208 buf[2][offset] = g_u_s;
1209 break;
1211 case V4L2_PIX_FMT_NV24:
1212 buf[0][offset] = r_y_h;
1213 buf[1][2 * offset] = g_u_s;
1214 buf[1][(2 * offset + 1) % 8] = b_v;
1215 break;
1217 case V4L2_PIX_FMT_NV42:
1218 buf[0][offset] = r_y_h;
1219 buf[1][2 * offset] = b_v;
1220 buf[1][(2 * offset + 1) % 8] = g_u_s;
1221 break;
1223 case V4L2_PIX_FMT_YUYV:
1224 buf[0][offset] = r_y_h;
1225 if (odd) {
1226 buf[0][1] = (buf[0][1] + g_u_s) / 2;
1227 buf[0][3] = (buf[0][3] + b_v) / 2;
1228 break;
1230 buf[0][1] = g_u_s;
1231 buf[0][3] = b_v;
1232 break;
1233 case V4L2_PIX_FMT_UYVY:
1234 buf[0][offset + 1] = r_y_h;
1235 if (odd) {
1236 buf[0][0] = (buf[0][0] + g_u_s) / 2;
1237 buf[0][2] = (buf[0][2] + b_v) / 2;
1238 break;
1240 buf[0][0] = g_u_s;
1241 buf[0][2] = b_v;
1242 break;
1243 case V4L2_PIX_FMT_YVYU:
1244 buf[0][offset] = r_y_h;
1245 if (odd) {
1246 buf[0][1] = (buf[0][1] + b_v) / 2;
1247 buf[0][3] = (buf[0][3] + g_u_s) / 2;
1248 break;
1250 buf[0][1] = b_v;
1251 buf[0][3] = g_u_s;
1252 break;
1253 case V4L2_PIX_FMT_VYUY:
1254 buf[0][offset + 1] = r_y_h;
1255 if (odd) {
1256 buf[0][0] = (buf[0][0] + b_v) / 2;
1257 buf[0][2] = (buf[0][2] + g_u_s) / 2;
1258 break;
1260 buf[0][0] = b_v;
1261 buf[0][2] = g_u_s;
1262 break;
1263 case V4L2_PIX_FMT_RGB332:
1264 buf[0][offset] = (r_y_h << 5) | (g_u_s << 2) | b_v;
1265 break;
1266 case V4L2_PIX_FMT_YUV565:
1267 case V4L2_PIX_FMT_RGB565:
1268 buf[0][offset] = (g_u_s << 5) | b_v;
1269 buf[0][offset + 1] = (r_y_h << 3) | (g_u_s >> 3);
1270 break;
1271 case V4L2_PIX_FMT_RGB565X:
1272 buf[0][offset] = (r_y_h << 3) | (g_u_s >> 3);
1273 buf[0][offset + 1] = (g_u_s << 5) | b_v;
1274 break;
1275 case V4L2_PIX_FMT_RGB444:
1276 case V4L2_PIX_FMT_XRGB444:
1277 alpha = 0;
1278 /* fall through */
1279 case V4L2_PIX_FMT_YUV444:
1280 case V4L2_PIX_FMT_ARGB444:
1281 buf[0][offset] = (g_u_s << 4) | b_v;
1282 buf[0][offset + 1] = (alpha & 0xf0) | r_y_h;
1283 break;
1284 case V4L2_PIX_FMT_RGBX444:
1285 alpha = 0;
1286 /* fall through */
1287 case V4L2_PIX_FMT_RGBA444:
1288 buf[0][offset] = (b_v << 4) | (alpha >> 4);
1289 buf[0][offset + 1] = (r_y_h << 4) | g_u_s;
1290 break;
1291 case V4L2_PIX_FMT_XBGR444:
1292 alpha = 0;
1293 /* fall through */
1294 case V4L2_PIX_FMT_ABGR444:
1295 buf[0][offset] = (g_u_s << 4) | r_y_h;
1296 buf[0][offset + 1] = (alpha & 0xf0) | b_v;
1297 break;
1298 case V4L2_PIX_FMT_BGRX444:
1299 alpha = 0;
1300 /* fall through */
1301 case V4L2_PIX_FMT_BGRA444:
1302 buf[0][offset] = (r_y_h << 4) | (alpha >> 4);
1303 buf[0][offset + 1] = (b_v << 4) | g_u_s;
1304 break;
1305 case V4L2_PIX_FMT_RGB555:
1306 case V4L2_PIX_FMT_XRGB555:
1307 alpha = 0;
1308 /* fall through */
1309 case V4L2_PIX_FMT_YUV555:
1310 case V4L2_PIX_FMT_ARGB555:
1311 buf[0][offset] = (g_u_s << 5) | b_v;
1312 buf[0][offset + 1] = (alpha & 0x80) | (r_y_h << 2)
1313 | (g_u_s >> 3);
1314 break;
1315 case V4L2_PIX_FMT_RGBX555:
1316 alpha = 0;
1317 /* fall through */
1318 case V4L2_PIX_FMT_RGBA555:
1319 buf[0][offset] = (g_u_s << 6) | (b_v << 1) |
1320 ((alpha & 0x80) >> 7);
1321 buf[0][offset + 1] = (r_y_h << 3) | (g_u_s >> 2);
1322 break;
1323 case V4L2_PIX_FMT_XBGR555:
1324 alpha = 0;
1325 /* fall through */
1326 case V4L2_PIX_FMT_ABGR555:
1327 buf[0][offset] = (g_u_s << 5) | r_y_h;
1328 buf[0][offset + 1] = (alpha & 0x80) | (b_v << 2)
1329 | (g_u_s >> 3);
1330 break;
1331 case V4L2_PIX_FMT_BGRX555:
1332 alpha = 0;
1333 /* fall through */
1334 case V4L2_PIX_FMT_BGRA555:
1335 buf[0][offset] = (g_u_s << 6) | (r_y_h << 1) |
1336 ((alpha & 0x80) >> 7);
1337 buf[0][offset + 1] = (b_v << 3) | (g_u_s >> 2);
1338 break;
1339 case V4L2_PIX_FMT_RGB555X:
1340 case V4L2_PIX_FMT_XRGB555X:
1341 alpha = 0;
1342 /* fall through */
1343 case V4L2_PIX_FMT_ARGB555X:
1344 buf[0][offset] = (alpha & 0x80) | (r_y_h << 2) | (g_u_s >> 3);
1345 buf[0][offset + 1] = (g_u_s << 5) | b_v;
1346 break;
1347 case V4L2_PIX_FMT_RGB24:
1348 case V4L2_PIX_FMT_HSV24:
1349 buf[0][offset] = r_y_h;
1350 buf[0][offset + 1] = g_u_s;
1351 buf[0][offset + 2] = b_v;
1352 break;
1353 case V4L2_PIX_FMT_BGR24:
1354 buf[0][offset] = b_v;
1355 buf[0][offset + 1] = g_u_s;
1356 buf[0][offset + 2] = r_y_h;
1357 break;
1358 case V4L2_PIX_FMT_BGR666:
1359 buf[0][offset] = (b_v << 2) | (g_u_s >> 4);
1360 buf[0][offset + 1] = (g_u_s << 4) | (r_y_h >> 2);
1361 buf[0][offset + 2] = r_y_h << 6;
1362 buf[0][offset + 3] = 0;
1363 break;
1364 case V4L2_PIX_FMT_RGB32:
1365 case V4L2_PIX_FMT_XRGB32:
1366 case V4L2_PIX_FMT_HSV32:
1367 case V4L2_PIX_FMT_XYUV32:
1368 alpha = 0;
1369 /* fall through */
1370 case V4L2_PIX_FMT_YUV32:
1371 case V4L2_PIX_FMT_ARGB32:
1372 case V4L2_PIX_FMT_AYUV32:
1373 buf[0][offset] = alpha;
1374 buf[0][offset + 1] = r_y_h;
1375 buf[0][offset + 2] = g_u_s;
1376 buf[0][offset + 3] = b_v;
1377 break;
1378 case V4L2_PIX_FMT_RGBX32:
1379 alpha = 0;
1380 /* fall through */
1381 case V4L2_PIX_FMT_RGBA32:
1382 buf[0][offset] = r_y_h;
1383 buf[0][offset + 1] = g_u_s;
1384 buf[0][offset + 2] = b_v;
1385 buf[0][offset + 3] = alpha;
1386 break;
1387 case V4L2_PIX_FMT_BGR32:
1388 case V4L2_PIX_FMT_XBGR32:
1389 case V4L2_PIX_FMT_VUYX32:
1390 alpha = 0;
1391 /* fall through */
1392 case V4L2_PIX_FMT_ABGR32:
1393 case V4L2_PIX_FMT_VUYA32:
1394 buf[0][offset] = b_v;
1395 buf[0][offset + 1] = g_u_s;
1396 buf[0][offset + 2] = r_y_h;
1397 buf[0][offset + 3] = alpha;
1398 break;
1399 case V4L2_PIX_FMT_BGRX32:
1400 alpha = 0;
1401 /* fall through */
1402 case V4L2_PIX_FMT_BGRA32:
1403 buf[0][offset] = alpha;
1404 buf[0][offset + 1] = b_v;
1405 buf[0][offset + 2] = g_u_s;
1406 buf[0][offset + 3] = r_y_h;
1407 break;
1408 case V4L2_PIX_FMT_SBGGR8:
1409 buf[0][offset] = odd ? g_u_s : b_v;
1410 buf[1][offset] = odd ? r_y_h : g_u_s;
1411 break;
1412 case V4L2_PIX_FMT_SGBRG8:
1413 buf[0][offset] = odd ? b_v : g_u_s;
1414 buf[1][offset] = odd ? g_u_s : r_y_h;
1415 break;
1416 case V4L2_PIX_FMT_SGRBG8:
1417 buf[0][offset] = odd ? r_y_h : g_u_s;
1418 buf[1][offset] = odd ? g_u_s : b_v;
1419 break;
1420 case V4L2_PIX_FMT_SRGGB8:
1421 buf[0][offset] = odd ? g_u_s : r_y_h;
1422 buf[1][offset] = odd ? b_v : g_u_s;
1423 break;
1424 case V4L2_PIX_FMT_SBGGR10:
1425 buf[0][offset] = odd ? g_u_s << 2 : b_v << 2;
1426 buf[0][offset + 1] = odd ? g_u_s >> 6 : b_v >> 6;
1427 buf[1][offset] = odd ? r_y_h << 2 : g_u_s << 2;
1428 buf[1][offset + 1] = odd ? r_y_h >> 6 : g_u_s >> 6;
1429 buf[0][offset] |= (buf[0][offset] >> 2) & 3;
1430 buf[1][offset] |= (buf[1][offset] >> 2) & 3;
1431 break;
1432 case V4L2_PIX_FMT_SGBRG10:
1433 buf[0][offset] = odd ? b_v << 2 : g_u_s << 2;
1434 buf[0][offset + 1] = odd ? b_v >> 6 : g_u_s >> 6;
1435 buf[1][offset] = odd ? g_u_s << 2 : r_y_h << 2;
1436 buf[1][offset + 1] = odd ? g_u_s >> 6 : r_y_h >> 6;
1437 buf[0][offset] |= (buf[0][offset] >> 2) & 3;
1438 buf[1][offset] |= (buf[1][offset] >> 2) & 3;
1439 break;
1440 case V4L2_PIX_FMT_SGRBG10:
1441 buf[0][offset] = odd ? r_y_h << 2 : g_u_s << 2;
1442 buf[0][offset + 1] = odd ? r_y_h >> 6 : g_u_s >> 6;
1443 buf[1][offset] = odd ? g_u_s << 2 : b_v << 2;
1444 buf[1][offset + 1] = odd ? g_u_s >> 6 : b_v >> 6;
1445 buf[0][offset] |= (buf[0][offset] >> 2) & 3;
1446 buf[1][offset] |= (buf[1][offset] >> 2) & 3;
1447 break;
1448 case V4L2_PIX_FMT_SRGGB10:
1449 buf[0][offset] = odd ? g_u_s << 2 : r_y_h << 2;
1450 buf[0][offset + 1] = odd ? g_u_s >> 6 : r_y_h >> 6;
1451 buf[1][offset] = odd ? b_v << 2 : g_u_s << 2;
1452 buf[1][offset + 1] = odd ? b_v >> 6 : g_u_s >> 6;
1453 buf[0][offset] |= (buf[0][offset] >> 2) & 3;
1454 buf[1][offset] |= (buf[1][offset] >> 2) & 3;
1455 break;
1456 case V4L2_PIX_FMT_SBGGR12:
1457 buf[0][offset] = odd ? g_u_s << 4 : b_v << 4;
1458 buf[0][offset + 1] = odd ? g_u_s >> 4 : b_v >> 4;
1459 buf[1][offset] = odd ? r_y_h << 4 : g_u_s << 4;
1460 buf[1][offset + 1] = odd ? r_y_h >> 4 : g_u_s >> 4;
1461 buf[0][offset] |= (buf[0][offset] >> 4) & 0xf;
1462 buf[1][offset] |= (buf[1][offset] >> 4) & 0xf;
1463 break;
1464 case V4L2_PIX_FMT_SGBRG12:
1465 buf[0][offset] = odd ? b_v << 4 : g_u_s << 4;
1466 buf[0][offset + 1] = odd ? b_v >> 4 : g_u_s >> 4;
1467 buf[1][offset] = odd ? g_u_s << 4 : r_y_h << 4;
1468 buf[1][offset + 1] = odd ? g_u_s >> 4 : r_y_h >> 4;
1469 buf[0][offset] |= (buf[0][offset] >> 4) & 0xf;
1470 buf[1][offset] |= (buf[1][offset] >> 4) & 0xf;
1471 break;
1472 case V4L2_PIX_FMT_SGRBG12:
1473 buf[0][offset] = odd ? r_y_h << 4 : g_u_s << 4;
1474 buf[0][offset + 1] = odd ? r_y_h >> 4 : g_u_s >> 4;
1475 buf[1][offset] = odd ? g_u_s << 4 : b_v << 4;
1476 buf[1][offset + 1] = odd ? g_u_s >> 4 : b_v >> 4;
1477 buf[0][offset] |= (buf[0][offset] >> 4) & 0xf;
1478 buf[1][offset] |= (buf[1][offset] >> 4) & 0xf;
1479 break;
1480 case V4L2_PIX_FMT_SRGGB12:
1481 buf[0][offset] = odd ? g_u_s << 4 : r_y_h << 4;
1482 buf[0][offset + 1] = odd ? g_u_s >> 4 : r_y_h >> 4;
1483 buf[1][offset] = odd ? b_v << 4 : g_u_s << 4;
1484 buf[1][offset + 1] = odd ? b_v >> 4 : g_u_s >> 4;
1485 buf[0][offset] |= (buf[0][offset] >> 4) & 0xf;
1486 buf[1][offset] |= (buf[1][offset] >> 4) & 0xf;
1487 break;
1488 case V4L2_PIX_FMT_SBGGR16:
1489 buf[0][offset] = buf[0][offset + 1] = odd ? g_u_s : b_v;
1490 buf[1][offset] = buf[1][offset + 1] = odd ? r_y_h : g_u_s;
1491 break;
1492 case V4L2_PIX_FMT_SGBRG16:
1493 buf[0][offset] = buf[0][offset + 1] = odd ? b_v : g_u_s;
1494 buf[1][offset] = buf[1][offset + 1] = odd ? g_u_s : r_y_h;
1495 break;
1496 case V4L2_PIX_FMT_SGRBG16:
1497 buf[0][offset] = buf[0][offset + 1] = odd ? r_y_h : g_u_s;
1498 buf[1][offset] = buf[1][offset + 1] = odd ? g_u_s : b_v;
1499 break;
1500 case V4L2_PIX_FMT_SRGGB16:
1501 buf[0][offset] = buf[0][offset + 1] = odd ? g_u_s : r_y_h;
1502 buf[1][offset] = buf[1][offset + 1] = odd ? b_v : g_u_s;
1503 break;
1507 unsigned tpg_g_interleaved_plane(const struct tpg_data *tpg, unsigned buf_line)
1509 switch (tpg->fourcc) {
1510 case V4L2_PIX_FMT_SBGGR8:
1511 case V4L2_PIX_FMT_SGBRG8:
1512 case V4L2_PIX_FMT_SGRBG8:
1513 case V4L2_PIX_FMT_SRGGB8:
1514 case V4L2_PIX_FMT_SBGGR10:
1515 case V4L2_PIX_FMT_SGBRG10:
1516 case V4L2_PIX_FMT_SGRBG10:
1517 case V4L2_PIX_FMT_SRGGB10:
1518 case V4L2_PIX_FMT_SBGGR12:
1519 case V4L2_PIX_FMT_SGBRG12:
1520 case V4L2_PIX_FMT_SGRBG12:
1521 case V4L2_PIX_FMT_SRGGB12:
1522 case V4L2_PIX_FMT_SBGGR16:
1523 case V4L2_PIX_FMT_SGBRG16:
1524 case V4L2_PIX_FMT_SGRBG16:
1525 case V4L2_PIX_FMT_SRGGB16:
1526 return buf_line & 1;
1527 default:
1528 return 0;
1531 EXPORT_SYMBOL_GPL(tpg_g_interleaved_plane);
1533 /* Return how many pattern lines are used by the current pattern. */
1534 static unsigned tpg_get_pat_lines(const struct tpg_data *tpg)
1536 switch (tpg->pattern) {
1537 case TPG_PAT_CHECKERS_16X16:
1538 case TPG_PAT_CHECKERS_2X2:
1539 case TPG_PAT_CHECKERS_1X1:
1540 case TPG_PAT_COLOR_CHECKERS_2X2:
1541 case TPG_PAT_COLOR_CHECKERS_1X1:
1542 case TPG_PAT_ALTERNATING_HLINES:
1543 case TPG_PAT_CROSS_1_PIXEL:
1544 case TPG_PAT_CROSS_2_PIXELS:
1545 case TPG_PAT_CROSS_10_PIXELS:
1546 return 2;
1547 case TPG_PAT_100_COLORSQUARES:
1548 case TPG_PAT_100_HCOLORBAR:
1549 return 8;
1550 default:
1551 return 1;
1555 /* Which pattern line should be used for the given frame line. */
1556 static unsigned tpg_get_pat_line(const struct tpg_data *tpg, unsigned line)
1558 switch (tpg->pattern) {
1559 case TPG_PAT_CHECKERS_16X16:
1560 return (line >> 4) & 1;
1561 case TPG_PAT_CHECKERS_1X1:
1562 case TPG_PAT_COLOR_CHECKERS_1X1:
1563 case TPG_PAT_ALTERNATING_HLINES:
1564 return line & 1;
1565 case TPG_PAT_CHECKERS_2X2:
1566 case TPG_PAT_COLOR_CHECKERS_2X2:
1567 return (line & 2) >> 1;
1568 case TPG_PAT_100_COLORSQUARES:
1569 case TPG_PAT_100_HCOLORBAR:
1570 return (line * 8) / tpg->src_height;
1571 case TPG_PAT_CROSS_1_PIXEL:
1572 return line == tpg->src_height / 2;
1573 case TPG_PAT_CROSS_2_PIXELS:
1574 return (line + 1) / 2 == tpg->src_height / 4;
1575 case TPG_PAT_CROSS_10_PIXELS:
1576 return (line + 10) / 20 == tpg->src_height / 40;
1577 default:
1578 return 0;
1583 * Which color should be used for the given pattern line and X coordinate.
1584 * Note: x is in the range 0 to 2 * tpg->src_width.
1586 static enum tpg_color tpg_get_color(const struct tpg_data *tpg,
1587 unsigned pat_line, unsigned x)
1589 /* Maximum number of bars are TPG_COLOR_MAX - otherwise, the input print code
1590 should be modified */
1591 static const enum tpg_color bars[3][8] = {
1592 /* Standard ITU-R 75% color bar sequence */
1593 { TPG_COLOR_CSC_WHITE, TPG_COLOR_75_YELLOW,
1594 TPG_COLOR_75_CYAN, TPG_COLOR_75_GREEN,
1595 TPG_COLOR_75_MAGENTA, TPG_COLOR_75_RED,
1596 TPG_COLOR_75_BLUE, TPG_COLOR_100_BLACK, },
1597 /* Standard ITU-R 100% color bar sequence */
1598 { TPG_COLOR_100_WHITE, TPG_COLOR_100_YELLOW,
1599 TPG_COLOR_100_CYAN, TPG_COLOR_100_GREEN,
1600 TPG_COLOR_100_MAGENTA, TPG_COLOR_100_RED,
1601 TPG_COLOR_100_BLUE, TPG_COLOR_100_BLACK, },
1602 /* Color bar sequence suitable to test CSC */
1603 { TPG_COLOR_CSC_WHITE, TPG_COLOR_CSC_YELLOW,
1604 TPG_COLOR_CSC_CYAN, TPG_COLOR_CSC_GREEN,
1605 TPG_COLOR_CSC_MAGENTA, TPG_COLOR_CSC_RED,
1606 TPG_COLOR_CSC_BLUE, TPG_COLOR_CSC_BLACK, },
1609 switch (tpg->pattern) {
1610 case TPG_PAT_75_COLORBAR:
1611 case TPG_PAT_100_COLORBAR:
1612 case TPG_PAT_CSC_COLORBAR:
1613 return bars[tpg->pattern][((x * 8) / tpg->src_width) % 8];
1614 case TPG_PAT_100_COLORSQUARES:
1615 return bars[1][(pat_line + (x * 8) / tpg->src_width) % 8];
1616 case TPG_PAT_100_HCOLORBAR:
1617 return bars[1][pat_line];
1618 case TPG_PAT_BLACK:
1619 return TPG_COLOR_100_BLACK;
1620 case TPG_PAT_WHITE:
1621 return TPG_COLOR_100_WHITE;
1622 case TPG_PAT_RED:
1623 return TPG_COLOR_100_RED;
1624 case TPG_PAT_GREEN:
1625 return TPG_COLOR_100_GREEN;
1626 case TPG_PAT_BLUE:
1627 return TPG_COLOR_100_BLUE;
1628 case TPG_PAT_CHECKERS_16X16:
1629 return (((x >> 4) & 1) ^ (pat_line & 1)) ?
1630 TPG_COLOR_100_BLACK : TPG_COLOR_100_WHITE;
1631 case TPG_PAT_CHECKERS_1X1:
1632 return ((x & 1) ^ (pat_line & 1)) ?
1633 TPG_COLOR_100_WHITE : TPG_COLOR_100_BLACK;
1634 case TPG_PAT_COLOR_CHECKERS_1X1:
1635 return ((x & 1) ^ (pat_line & 1)) ?
1636 TPG_COLOR_100_RED : TPG_COLOR_100_BLUE;
1637 case TPG_PAT_CHECKERS_2X2:
1638 return (((x >> 1) & 1) ^ (pat_line & 1)) ?
1639 TPG_COLOR_100_WHITE : TPG_COLOR_100_BLACK;
1640 case TPG_PAT_COLOR_CHECKERS_2X2:
1641 return (((x >> 1) & 1) ^ (pat_line & 1)) ?
1642 TPG_COLOR_100_RED : TPG_COLOR_100_BLUE;
1643 case TPG_PAT_ALTERNATING_HLINES:
1644 return pat_line ? TPG_COLOR_100_WHITE : TPG_COLOR_100_BLACK;
1645 case TPG_PAT_ALTERNATING_VLINES:
1646 return (x & 1) ? TPG_COLOR_100_WHITE : TPG_COLOR_100_BLACK;
1647 case TPG_PAT_CROSS_1_PIXEL:
1648 if (pat_line || (x % tpg->src_width) == tpg->src_width / 2)
1649 return TPG_COLOR_100_BLACK;
1650 return TPG_COLOR_100_WHITE;
1651 case TPG_PAT_CROSS_2_PIXELS:
1652 if (pat_line || ((x % tpg->src_width) + 1) / 2 == tpg->src_width / 4)
1653 return TPG_COLOR_100_BLACK;
1654 return TPG_COLOR_100_WHITE;
1655 case TPG_PAT_CROSS_10_PIXELS:
1656 if (pat_line || ((x % tpg->src_width) + 10) / 20 == tpg->src_width / 40)
1657 return TPG_COLOR_100_BLACK;
1658 return TPG_COLOR_100_WHITE;
1659 case TPG_PAT_GRAY_RAMP:
1660 return TPG_COLOR_RAMP + ((x % tpg->src_width) * 256) / tpg->src_width;
1661 default:
1662 return TPG_COLOR_100_RED;
1667 * Given the pixel aspect ratio and video aspect ratio calculate the
1668 * coordinates of a centered square and the coordinates of the border of
1669 * the active video area. The coordinates are relative to the source
1670 * frame rectangle.
1672 static void tpg_calculate_square_border(struct tpg_data *tpg)
1674 unsigned w = tpg->src_width;
1675 unsigned h = tpg->src_height;
1676 unsigned sq_w, sq_h;
1678 sq_w = (w * 2 / 5) & ~1;
1679 if (((w - sq_w) / 2) & 1)
1680 sq_w += 2;
1681 sq_h = sq_w;
1682 tpg->square.width = sq_w;
1683 if (tpg->vid_aspect == TPG_VIDEO_ASPECT_16X9_ANAMORPHIC) {
1684 unsigned ana_sq_w = (sq_w / 4) * 3;
1686 if (((w - ana_sq_w) / 2) & 1)
1687 ana_sq_w += 2;
1688 tpg->square.width = ana_sq_w;
1690 tpg->square.left = (w - tpg->square.width) / 2;
1691 if (tpg->pix_aspect == TPG_PIXEL_ASPECT_NTSC)
1692 sq_h = sq_w * 10 / 11;
1693 else if (tpg->pix_aspect == TPG_PIXEL_ASPECT_PAL)
1694 sq_h = sq_w * 59 / 54;
1695 tpg->square.height = sq_h;
1696 tpg->square.top = (h - sq_h) / 2;
1697 tpg->border.left = 0;
1698 tpg->border.width = w;
1699 tpg->border.top = 0;
1700 tpg->border.height = h;
1701 switch (tpg->vid_aspect) {
1702 case TPG_VIDEO_ASPECT_4X3:
1703 if (tpg->pix_aspect)
1704 return;
1705 if (3 * w >= 4 * h) {
1706 tpg->border.width = ((4 * h) / 3) & ~1;
1707 if (((w - tpg->border.width) / 2) & ~1)
1708 tpg->border.width -= 2;
1709 tpg->border.left = (w - tpg->border.width) / 2;
1710 break;
1712 tpg->border.height = ((3 * w) / 4) & ~1;
1713 tpg->border.top = (h - tpg->border.height) / 2;
1714 break;
1715 case TPG_VIDEO_ASPECT_14X9_CENTRE:
1716 if (tpg->pix_aspect) {
1717 tpg->border.height = tpg->pix_aspect == TPG_PIXEL_ASPECT_NTSC ? 420 : 506;
1718 tpg->border.top = (h - tpg->border.height) / 2;
1719 break;
1721 if (9 * w >= 14 * h) {
1722 tpg->border.width = ((14 * h) / 9) & ~1;
1723 if (((w - tpg->border.width) / 2) & ~1)
1724 tpg->border.width -= 2;
1725 tpg->border.left = (w - tpg->border.width) / 2;
1726 break;
1728 tpg->border.height = ((9 * w) / 14) & ~1;
1729 tpg->border.top = (h - tpg->border.height) / 2;
1730 break;
1731 case TPG_VIDEO_ASPECT_16X9_CENTRE:
1732 if (tpg->pix_aspect) {
1733 tpg->border.height = tpg->pix_aspect == TPG_PIXEL_ASPECT_NTSC ? 368 : 442;
1734 tpg->border.top = (h - tpg->border.height) / 2;
1735 break;
1737 if (9 * w >= 16 * h) {
1738 tpg->border.width = ((16 * h) / 9) & ~1;
1739 if (((w - tpg->border.width) / 2) & ~1)
1740 tpg->border.width -= 2;
1741 tpg->border.left = (w - tpg->border.width) / 2;
1742 break;
1744 tpg->border.height = ((9 * w) / 16) & ~1;
1745 tpg->border.top = (h - tpg->border.height) / 2;
1746 break;
1747 default:
1748 break;
1752 static void tpg_precalculate_line(struct tpg_data *tpg)
1754 enum tpg_color contrast;
1755 u8 pix[TPG_MAX_PLANES][8];
1756 unsigned pat;
1757 unsigned p;
1758 unsigned x;
1760 switch (tpg->pattern) {
1761 case TPG_PAT_GREEN:
1762 contrast = TPG_COLOR_100_RED;
1763 break;
1764 case TPG_PAT_CSC_COLORBAR:
1765 contrast = TPG_COLOR_CSC_GREEN;
1766 break;
1767 default:
1768 contrast = TPG_COLOR_100_GREEN;
1769 break;
1772 for (pat = 0; pat < tpg_get_pat_lines(tpg); pat++) {
1773 /* Coarse scaling with Bresenham */
1774 unsigned int_part = tpg->src_width / tpg->scaled_width;
1775 unsigned fract_part = tpg->src_width % tpg->scaled_width;
1776 unsigned src_x = 0;
1777 unsigned error = 0;
1779 for (x = 0; x < tpg->scaled_width * 2; x += 2) {
1780 unsigned real_x = src_x;
1781 enum tpg_color color1, color2;
1783 real_x = tpg->hflip ? tpg->src_width * 2 - real_x - 2 : real_x;
1784 color1 = tpg_get_color(tpg, pat, real_x);
1786 src_x += int_part;
1787 error += fract_part;
1788 if (error >= tpg->scaled_width) {
1789 error -= tpg->scaled_width;
1790 src_x++;
1793 real_x = src_x;
1794 real_x = tpg->hflip ? tpg->src_width * 2 - real_x - 2 : real_x;
1795 color2 = tpg_get_color(tpg, pat, real_x);
1797 src_x += int_part;
1798 error += fract_part;
1799 if (error >= tpg->scaled_width) {
1800 error -= tpg->scaled_width;
1801 src_x++;
1804 gen_twopix(tpg, pix, tpg->hflip ? color2 : color1, 0);
1805 gen_twopix(tpg, pix, tpg->hflip ? color1 : color2, 1);
1806 for (p = 0; p < tpg->planes; p++) {
1807 unsigned twopixsize = tpg->twopixelsize[p];
1808 unsigned hdiv = tpg->hdownsampling[p];
1809 u8 *pos = tpg->lines[pat][p] + tpg_hdiv(tpg, p, x);
1811 memcpy(pos, pix[p], twopixsize / hdiv);
1816 if (tpg->vdownsampling[tpg->planes - 1] > 1) {
1817 unsigned pat_lines = tpg_get_pat_lines(tpg);
1819 for (pat = 0; pat < pat_lines; pat++) {
1820 unsigned next_pat = (pat + 1) % pat_lines;
1822 for (p = 1; p < tpg->planes; p++) {
1823 unsigned w = tpg_hdiv(tpg, p, tpg->scaled_width * 2);
1824 u8 *pos1 = tpg->lines[pat][p];
1825 u8 *pos2 = tpg->lines[next_pat][p];
1826 u8 *dest = tpg->downsampled_lines[pat][p];
1828 for (x = 0; x < w; x++, pos1++, pos2++, dest++)
1829 *dest = ((u16)*pos1 + (u16)*pos2) / 2;
1834 gen_twopix(tpg, pix, contrast, 0);
1835 gen_twopix(tpg, pix, contrast, 1);
1836 for (p = 0; p < tpg->planes; p++) {
1837 unsigned twopixsize = tpg->twopixelsize[p];
1838 u8 *pos = tpg->contrast_line[p];
1840 for (x = 0; x < tpg->scaled_width; x += 2, pos += twopixsize)
1841 memcpy(pos, pix[p], twopixsize);
1844 gen_twopix(tpg, pix, TPG_COLOR_100_BLACK, 0);
1845 gen_twopix(tpg, pix, TPG_COLOR_100_BLACK, 1);
1846 for (p = 0; p < tpg->planes; p++) {
1847 unsigned twopixsize = tpg->twopixelsize[p];
1848 u8 *pos = tpg->black_line[p];
1850 for (x = 0; x < tpg->scaled_width; x += 2, pos += twopixsize)
1851 memcpy(pos, pix[p], twopixsize);
1854 for (x = 0; x < tpg->scaled_width * 2; x += 2) {
1855 gen_twopix(tpg, pix, TPG_COLOR_RANDOM, 0);
1856 gen_twopix(tpg, pix, TPG_COLOR_RANDOM, 1);
1857 for (p = 0; p < tpg->planes; p++) {
1858 unsigned twopixsize = tpg->twopixelsize[p];
1859 u8 *pos = tpg->random_line[p] + x * twopixsize / 2;
1861 memcpy(pos, pix[p], twopixsize);
1865 gen_twopix(tpg, tpg->textbg, TPG_COLOR_TEXTBG, 0);
1866 gen_twopix(tpg, tpg->textbg, TPG_COLOR_TEXTBG, 1);
1867 gen_twopix(tpg, tpg->textfg, TPG_COLOR_TEXTFG, 0);
1868 gen_twopix(tpg, tpg->textfg, TPG_COLOR_TEXTFG, 1);
1871 /* need this to do rgb24 rendering */
1872 typedef struct { u16 __; u8 _; } __packed x24;
1874 #define PRINTSTR(PIXTYPE) do { \
1875 unsigned vdiv = tpg->vdownsampling[p]; \
1876 unsigned hdiv = tpg->hdownsampling[p]; \
1877 int line; \
1878 PIXTYPE fg; \
1879 PIXTYPE bg; \
1880 memcpy(&fg, tpg->textfg[p], sizeof(PIXTYPE)); \
1881 memcpy(&bg, tpg->textbg[p], sizeof(PIXTYPE)); \
1883 for (line = first; line < 16; line += vdiv * step) { \
1884 int l = tpg->vflip ? 15 - line : line; \
1885 PIXTYPE *pos = (PIXTYPE *)(basep[p][(line / vdiv) & 1] + \
1886 ((y * step + l) / (vdiv * div)) * tpg->bytesperline[p] + \
1887 (x / hdiv) * sizeof(PIXTYPE)); \
1888 unsigned s; \
1890 for (s = 0; s < len; s++) { \
1891 u8 chr = font8x16[(u8)text[s] * 16 + line]; \
1893 if (hdiv == 2 && tpg->hflip) { \
1894 pos[3] = (chr & (0x01 << 6) ? fg : bg); \
1895 pos[2] = (chr & (0x01 << 4) ? fg : bg); \
1896 pos[1] = (chr & (0x01 << 2) ? fg : bg); \
1897 pos[0] = (chr & (0x01 << 0) ? fg : bg); \
1898 } else if (hdiv == 2) { \
1899 pos[0] = (chr & (0x01 << 7) ? fg : bg); \
1900 pos[1] = (chr & (0x01 << 5) ? fg : bg); \
1901 pos[2] = (chr & (0x01 << 3) ? fg : bg); \
1902 pos[3] = (chr & (0x01 << 1) ? fg : bg); \
1903 } else if (tpg->hflip) { \
1904 pos[7] = (chr & (0x01 << 7) ? fg : bg); \
1905 pos[6] = (chr & (0x01 << 6) ? fg : bg); \
1906 pos[5] = (chr & (0x01 << 5) ? fg : bg); \
1907 pos[4] = (chr & (0x01 << 4) ? fg : bg); \
1908 pos[3] = (chr & (0x01 << 3) ? fg : bg); \
1909 pos[2] = (chr & (0x01 << 2) ? fg : bg); \
1910 pos[1] = (chr & (0x01 << 1) ? fg : bg); \
1911 pos[0] = (chr & (0x01 << 0) ? fg : bg); \
1912 } else { \
1913 pos[0] = (chr & (0x01 << 7) ? fg : bg); \
1914 pos[1] = (chr & (0x01 << 6) ? fg : bg); \
1915 pos[2] = (chr & (0x01 << 5) ? fg : bg); \
1916 pos[3] = (chr & (0x01 << 4) ? fg : bg); \
1917 pos[4] = (chr & (0x01 << 3) ? fg : bg); \
1918 pos[5] = (chr & (0x01 << 2) ? fg : bg); \
1919 pos[6] = (chr & (0x01 << 1) ? fg : bg); \
1920 pos[7] = (chr & (0x01 << 0) ? fg : bg); \
1923 pos += (tpg->hflip ? -8 : 8) / (int)hdiv; \
1926 } while (0)
1928 static noinline void tpg_print_str_2(const struct tpg_data *tpg, u8 *basep[TPG_MAX_PLANES][2],
1929 unsigned p, unsigned first, unsigned div, unsigned step,
1930 int y, int x, char *text, unsigned len)
1932 PRINTSTR(u8);
1935 static noinline void tpg_print_str_4(const struct tpg_data *tpg, u8 *basep[TPG_MAX_PLANES][2],
1936 unsigned p, unsigned first, unsigned div, unsigned step,
1937 int y, int x, char *text, unsigned len)
1939 PRINTSTR(u16);
1942 static noinline void tpg_print_str_6(const struct tpg_data *tpg, u8 *basep[TPG_MAX_PLANES][2],
1943 unsigned p, unsigned first, unsigned div, unsigned step,
1944 int y, int x, char *text, unsigned len)
1946 PRINTSTR(x24);
1949 static noinline void tpg_print_str_8(const struct tpg_data *tpg, u8 *basep[TPG_MAX_PLANES][2],
1950 unsigned p, unsigned first, unsigned div, unsigned step,
1951 int y, int x, char *text, unsigned len)
1953 PRINTSTR(u32);
1956 void tpg_gen_text(const struct tpg_data *tpg, u8 *basep[TPG_MAX_PLANES][2],
1957 int y, int x, char *text)
1959 unsigned step = V4L2_FIELD_HAS_T_OR_B(tpg->field) ? 2 : 1;
1960 unsigned div = step;
1961 unsigned first = 0;
1962 unsigned len = strlen(text);
1963 unsigned p;
1965 if (font8x16 == NULL || basep == NULL)
1966 return;
1968 /* Checks if it is possible to show string */
1969 if (y + 16 >= tpg->compose.height || x + 8 >= tpg->compose.width)
1970 return;
1972 if (len > (tpg->compose.width - x) / 8)
1973 len = (tpg->compose.width - x) / 8;
1974 if (tpg->vflip)
1975 y = tpg->compose.height - y - 16;
1976 if (tpg->hflip)
1977 x = tpg->compose.width - x - 8;
1978 y += tpg->compose.top;
1979 x += tpg->compose.left;
1980 if (tpg->field == V4L2_FIELD_BOTTOM)
1981 first = 1;
1982 else if (tpg->field == V4L2_FIELD_SEQ_TB || tpg->field == V4L2_FIELD_SEQ_BT)
1983 div = 2;
1985 for (p = 0; p < tpg->planes; p++) {
1986 /* Print text */
1987 switch (tpg->twopixelsize[p]) {
1988 case 2:
1989 tpg_print_str_2(tpg, basep, p, first, div, step, y, x,
1990 text, len);
1991 break;
1992 case 4:
1993 tpg_print_str_4(tpg, basep, p, first, div, step, y, x,
1994 text, len);
1995 break;
1996 case 6:
1997 tpg_print_str_6(tpg, basep, p, first, div, step, y, x,
1998 text, len);
1999 break;
2000 case 8:
2001 tpg_print_str_8(tpg, basep, p, first, div, step, y, x,
2002 text, len);
2003 break;
2007 EXPORT_SYMBOL_GPL(tpg_gen_text);
2009 void tpg_update_mv_step(struct tpg_data *tpg)
2011 int factor = tpg->mv_hor_mode > TPG_MOVE_NONE ? -1 : 1;
2013 if (tpg->hflip)
2014 factor = -factor;
2015 switch (tpg->mv_hor_mode) {
2016 case TPG_MOVE_NEG_FAST:
2017 case TPG_MOVE_POS_FAST:
2018 tpg->mv_hor_step = ((tpg->src_width + 319) / 320) * 4;
2019 break;
2020 case TPG_MOVE_NEG:
2021 case TPG_MOVE_POS:
2022 tpg->mv_hor_step = ((tpg->src_width + 639) / 640) * 4;
2023 break;
2024 case TPG_MOVE_NEG_SLOW:
2025 case TPG_MOVE_POS_SLOW:
2026 tpg->mv_hor_step = 2;
2027 break;
2028 case TPG_MOVE_NONE:
2029 tpg->mv_hor_step = 0;
2030 break;
2032 if (factor < 0)
2033 tpg->mv_hor_step = tpg->src_width - tpg->mv_hor_step;
2035 factor = tpg->mv_vert_mode > TPG_MOVE_NONE ? -1 : 1;
2036 switch (tpg->mv_vert_mode) {
2037 case TPG_MOVE_NEG_FAST:
2038 case TPG_MOVE_POS_FAST:
2039 tpg->mv_vert_step = ((tpg->src_width + 319) / 320) * 4;
2040 break;
2041 case TPG_MOVE_NEG:
2042 case TPG_MOVE_POS:
2043 tpg->mv_vert_step = ((tpg->src_width + 639) / 640) * 4;
2044 break;
2045 case TPG_MOVE_NEG_SLOW:
2046 case TPG_MOVE_POS_SLOW:
2047 tpg->mv_vert_step = 1;
2048 break;
2049 case TPG_MOVE_NONE:
2050 tpg->mv_vert_step = 0;
2051 break;
2053 if (factor < 0)
2054 tpg->mv_vert_step = tpg->src_height - tpg->mv_vert_step;
2056 EXPORT_SYMBOL_GPL(tpg_update_mv_step);
2058 /* Map the line number relative to the crop rectangle to a frame line number */
2059 static unsigned tpg_calc_frameline(const struct tpg_data *tpg, unsigned src_y,
2060 unsigned field)
2062 switch (field) {
2063 case V4L2_FIELD_TOP:
2064 return tpg->crop.top + src_y * 2;
2065 case V4L2_FIELD_BOTTOM:
2066 return tpg->crop.top + src_y * 2 + 1;
2067 default:
2068 return src_y + tpg->crop.top;
2073 * Map the line number relative to the compose rectangle to a destination
2074 * buffer line number.
2076 static unsigned tpg_calc_buffer_line(const struct tpg_data *tpg, unsigned y,
2077 unsigned field)
2079 y += tpg->compose.top;
2080 switch (field) {
2081 case V4L2_FIELD_SEQ_TB:
2082 if (y & 1)
2083 return tpg->buf_height / 2 + y / 2;
2084 return y / 2;
2085 case V4L2_FIELD_SEQ_BT:
2086 if (y & 1)
2087 return y / 2;
2088 return tpg->buf_height / 2 + y / 2;
2089 default:
2090 return y;
2094 static void tpg_recalc(struct tpg_data *tpg)
2096 if (tpg->recalc_colors) {
2097 tpg->recalc_colors = false;
2098 tpg->recalc_lines = true;
2099 tpg->real_xfer_func = tpg->xfer_func;
2100 tpg->real_ycbcr_enc = tpg->ycbcr_enc;
2101 tpg->real_hsv_enc = tpg->hsv_enc;
2102 tpg->real_quantization = tpg->quantization;
2104 if (tpg->xfer_func == V4L2_XFER_FUNC_DEFAULT)
2105 tpg->real_xfer_func =
2106 V4L2_MAP_XFER_FUNC_DEFAULT(tpg->colorspace);
2108 if (tpg->ycbcr_enc == V4L2_YCBCR_ENC_DEFAULT)
2109 tpg->real_ycbcr_enc =
2110 V4L2_MAP_YCBCR_ENC_DEFAULT(tpg->colorspace);
2112 if (tpg->quantization == V4L2_QUANTIZATION_DEFAULT)
2113 tpg->real_quantization =
2114 V4L2_MAP_QUANTIZATION_DEFAULT(
2115 tpg->color_enc != TGP_COLOR_ENC_YCBCR,
2116 tpg->colorspace, tpg->real_ycbcr_enc);
2118 tpg_precalculate_colors(tpg);
2120 if (tpg->recalc_square_border) {
2121 tpg->recalc_square_border = false;
2122 tpg_calculate_square_border(tpg);
2124 if (tpg->recalc_lines) {
2125 tpg->recalc_lines = false;
2126 tpg_precalculate_line(tpg);
2130 void tpg_calc_text_basep(struct tpg_data *tpg,
2131 u8 *basep[TPG_MAX_PLANES][2], unsigned p, u8 *vbuf)
2133 unsigned stride = tpg->bytesperline[p];
2134 unsigned h = tpg->buf_height;
2136 tpg_recalc(tpg);
2138 basep[p][0] = vbuf;
2139 basep[p][1] = vbuf;
2140 h /= tpg->vdownsampling[p];
2141 if (tpg->field == V4L2_FIELD_SEQ_TB)
2142 basep[p][1] += h * stride / 2;
2143 else if (tpg->field == V4L2_FIELD_SEQ_BT)
2144 basep[p][0] += h * stride / 2;
2145 if (p == 0 && tpg->interleaved)
2146 tpg_calc_text_basep(tpg, basep, 1, vbuf);
2148 EXPORT_SYMBOL_GPL(tpg_calc_text_basep);
2150 static int tpg_pattern_avg(const struct tpg_data *tpg,
2151 unsigned pat1, unsigned pat2)
2153 unsigned pat_lines = tpg_get_pat_lines(tpg);
2155 if (pat1 == (pat2 + 1) % pat_lines)
2156 return pat2;
2157 if (pat2 == (pat1 + 1) % pat_lines)
2158 return pat1;
2159 return -1;
2162 static const char *tpg_color_enc_str(enum tgp_color_enc
2163 color_enc)
2165 switch (color_enc) {
2166 case TGP_COLOR_ENC_HSV:
2167 return "HSV";
2168 case TGP_COLOR_ENC_YCBCR:
2169 return "Y'CbCr";
2170 case TGP_COLOR_ENC_LUMA:
2171 return "Luma";
2172 case TGP_COLOR_ENC_RGB:
2173 default:
2174 return "R'G'B";
2179 void tpg_log_status(struct tpg_data *tpg)
2181 pr_info("tpg source WxH: %ux%u (%s)\n",
2182 tpg->src_width, tpg->src_height,
2183 tpg_color_enc_str(tpg->color_enc));
2184 pr_info("tpg field: %u\n", tpg->field);
2185 pr_info("tpg crop: %ux%u@%dx%d\n", tpg->crop.width, tpg->crop.height,
2186 tpg->crop.left, tpg->crop.top);
2187 pr_info("tpg compose: %ux%u@%dx%d\n", tpg->compose.width, tpg->compose.height,
2188 tpg->compose.left, tpg->compose.top);
2189 pr_info("tpg colorspace: %d\n", tpg->colorspace);
2190 pr_info("tpg transfer function: %d/%d\n", tpg->xfer_func, tpg->real_xfer_func);
2191 if (tpg->color_enc == TGP_COLOR_ENC_HSV)
2192 pr_info("tpg HSV encoding: %d/%d\n",
2193 tpg->hsv_enc, tpg->real_hsv_enc);
2194 else if (tpg->color_enc == TGP_COLOR_ENC_YCBCR)
2195 pr_info("tpg Y'CbCr encoding: %d/%d\n",
2196 tpg->ycbcr_enc, tpg->real_ycbcr_enc);
2197 pr_info("tpg quantization: %d/%d\n", tpg->quantization, tpg->real_quantization);
2198 pr_info("tpg RGB range: %d/%d\n", tpg->rgb_range, tpg->real_rgb_range);
2200 EXPORT_SYMBOL_GPL(tpg_log_status);
2203 * This struct contains common parameters used by both the drawing of the
2204 * test pattern and the drawing of the extras (borders, square, etc.)
2206 struct tpg_draw_params {
2207 /* common data */
2208 bool is_tv;
2209 bool is_60hz;
2210 unsigned twopixsize;
2211 unsigned img_width;
2212 unsigned stride;
2213 unsigned hmax;
2214 unsigned frame_line;
2215 unsigned frame_line_next;
2217 /* test pattern */
2218 unsigned mv_hor_old;
2219 unsigned mv_hor_new;
2220 unsigned mv_vert_old;
2221 unsigned mv_vert_new;
2223 /* extras */
2224 unsigned wss_width;
2225 unsigned wss_random_offset;
2226 unsigned sav_eav_f;
2227 unsigned left_pillar_width;
2228 unsigned right_pillar_start;
2231 static void tpg_fill_params_pattern(const struct tpg_data *tpg, unsigned p,
2232 struct tpg_draw_params *params)
2234 params->mv_hor_old =
2235 tpg_hscale_div(tpg, p, tpg->mv_hor_count % tpg->src_width);
2236 params->mv_hor_new =
2237 tpg_hscale_div(tpg, p, (tpg->mv_hor_count + tpg->mv_hor_step) %
2238 tpg->src_width);
2239 params->mv_vert_old = tpg->mv_vert_count % tpg->src_height;
2240 params->mv_vert_new =
2241 (tpg->mv_vert_count + tpg->mv_vert_step) % tpg->src_height;
2244 static void tpg_fill_params_extras(const struct tpg_data *tpg,
2245 unsigned p,
2246 struct tpg_draw_params *params)
2248 unsigned left_pillar_width = 0;
2249 unsigned right_pillar_start = params->img_width;
2251 params->wss_width = tpg->crop.left < tpg->src_width / 2 ?
2252 tpg->src_width / 2 - tpg->crop.left : 0;
2253 if (params->wss_width > tpg->crop.width)
2254 params->wss_width = tpg->crop.width;
2255 params->wss_width = tpg_hscale_div(tpg, p, params->wss_width);
2256 params->wss_random_offset =
2257 params->twopixsize * prandom_u32_max(tpg->src_width / 2);
2259 if (tpg->crop.left < tpg->border.left) {
2260 left_pillar_width = tpg->border.left - tpg->crop.left;
2261 if (left_pillar_width > tpg->crop.width)
2262 left_pillar_width = tpg->crop.width;
2263 left_pillar_width = tpg_hscale_div(tpg, p, left_pillar_width);
2265 params->left_pillar_width = left_pillar_width;
2267 if (tpg->crop.left + tpg->crop.width >
2268 tpg->border.left + tpg->border.width) {
2269 right_pillar_start =
2270 tpg->border.left + tpg->border.width - tpg->crop.left;
2271 right_pillar_start =
2272 tpg_hscale_div(tpg, p, right_pillar_start);
2273 if (right_pillar_start > params->img_width)
2274 right_pillar_start = params->img_width;
2276 params->right_pillar_start = right_pillar_start;
2278 params->sav_eav_f = tpg->field ==
2279 (params->is_60hz ? V4L2_FIELD_TOP : V4L2_FIELD_BOTTOM);
2282 static void tpg_fill_plane_extras(const struct tpg_data *tpg,
2283 const struct tpg_draw_params *params,
2284 unsigned p, unsigned h, u8 *vbuf)
2286 unsigned twopixsize = params->twopixsize;
2287 unsigned img_width = params->img_width;
2288 unsigned frame_line = params->frame_line;
2289 const struct v4l2_rect *sq = &tpg->square;
2290 const struct v4l2_rect *b = &tpg->border;
2291 const struct v4l2_rect *c = &tpg->crop;
2293 if (params->is_tv && !params->is_60hz &&
2294 frame_line == 0 && params->wss_width) {
2296 * Replace the first half of the top line of a 50 Hz frame
2297 * with random data to simulate a WSS signal.
2299 u8 *wss = tpg->random_line[p] + params->wss_random_offset;
2301 memcpy(vbuf, wss, params->wss_width);
2304 if (tpg->show_border && frame_line >= b->top &&
2305 frame_line < b->top + b->height) {
2306 unsigned bottom = b->top + b->height - 1;
2307 unsigned left = params->left_pillar_width;
2308 unsigned right = params->right_pillar_start;
2310 if (frame_line == b->top || frame_line == b->top + 1 ||
2311 frame_line == bottom || frame_line == bottom - 1) {
2312 memcpy(vbuf + left, tpg->contrast_line[p],
2313 right - left);
2314 } else {
2315 if (b->left >= c->left &&
2316 b->left < c->left + c->width)
2317 memcpy(vbuf + left,
2318 tpg->contrast_line[p], twopixsize);
2319 if (b->left + b->width > c->left &&
2320 b->left + b->width <= c->left + c->width)
2321 memcpy(vbuf + right - twopixsize,
2322 tpg->contrast_line[p], twopixsize);
2325 if (tpg->qual != TPG_QUAL_NOISE && frame_line >= b->top &&
2326 frame_line < b->top + b->height) {
2327 memcpy(vbuf, tpg->black_line[p], params->left_pillar_width);
2328 memcpy(vbuf + params->right_pillar_start, tpg->black_line[p],
2329 img_width - params->right_pillar_start);
2331 if (tpg->show_square && frame_line >= sq->top &&
2332 frame_line < sq->top + sq->height &&
2333 sq->left < c->left + c->width &&
2334 sq->left + sq->width >= c->left) {
2335 unsigned left = sq->left;
2336 unsigned width = sq->width;
2338 if (c->left > left) {
2339 width -= c->left - left;
2340 left = c->left;
2342 if (c->left + c->width < left + width)
2343 width -= left + width - c->left - c->width;
2344 left -= c->left;
2345 left = tpg_hscale_div(tpg, p, left);
2346 width = tpg_hscale_div(tpg, p, width);
2347 memcpy(vbuf + left, tpg->contrast_line[p], width);
2349 if (tpg->insert_sav) {
2350 unsigned offset = tpg_hdiv(tpg, p, tpg->compose.width / 3);
2351 u8 *p = vbuf + offset;
2352 unsigned vact = 0, hact = 0;
2354 p[0] = 0xff;
2355 p[1] = 0;
2356 p[2] = 0;
2357 p[3] = 0x80 | (params->sav_eav_f << 6) |
2358 (vact << 5) | (hact << 4) |
2359 ((hact ^ vact) << 3) |
2360 ((hact ^ params->sav_eav_f) << 2) |
2361 ((params->sav_eav_f ^ vact) << 1) |
2362 (hact ^ vact ^ params->sav_eav_f);
2364 if (tpg->insert_eav) {
2365 unsigned offset = tpg_hdiv(tpg, p, tpg->compose.width * 2 / 3);
2366 u8 *p = vbuf + offset;
2367 unsigned vact = 0, hact = 1;
2369 p[0] = 0xff;
2370 p[1] = 0;
2371 p[2] = 0;
2372 p[3] = 0x80 | (params->sav_eav_f << 6) |
2373 (vact << 5) | (hact << 4) |
2374 ((hact ^ vact) << 3) |
2375 ((hact ^ params->sav_eav_f) << 2) |
2376 ((params->sav_eav_f ^ vact) << 1) |
2377 (hact ^ vact ^ params->sav_eav_f);
2381 static void tpg_fill_plane_pattern(const struct tpg_data *tpg,
2382 const struct tpg_draw_params *params,
2383 unsigned p, unsigned h, u8 *vbuf)
2385 unsigned twopixsize = params->twopixsize;
2386 unsigned img_width = params->img_width;
2387 unsigned mv_hor_old = params->mv_hor_old;
2388 unsigned mv_hor_new = params->mv_hor_new;
2389 unsigned mv_vert_old = params->mv_vert_old;
2390 unsigned mv_vert_new = params->mv_vert_new;
2391 unsigned frame_line = params->frame_line;
2392 unsigned frame_line_next = params->frame_line_next;
2393 unsigned line_offset = tpg_hscale_div(tpg, p, tpg->crop.left);
2394 bool even;
2395 bool fill_blank = false;
2396 unsigned pat_line_old;
2397 unsigned pat_line_new;
2398 u8 *linestart_older;
2399 u8 *linestart_newer;
2400 u8 *linestart_top;
2401 u8 *linestart_bottom;
2403 even = !(frame_line & 1);
2405 if (h >= params->hmax) {
2406 if (params->hmax == tpg->compose.height)
2407 return;
2408 if (!tpg->perc_fill_blank)
2409 return;
2410 fill_blank = true;
2413 if (tpg->vflip) {
2414 frame_line = tpg->src_height - frame_line - 1;
2415 frame_line_next = tpg->src_height - frame_line_next - 1;
2418 if (fill_blank) {
2419 linestart_older = tpg->contrast_line[p];
2420 linestart_newer = tpg->contrast_line[p];
2421 } else if (tpg->qual != TPG_QUAL_NOISE &&
2422 (frame_line < tpg->border.top ||
2423 frame_line >= tpg->border.top + tpg->border.height)) {
2424 linestart_older = tpg->black_line[p];
2425 linestart_newer = tpg->black_line[p];
2426 } else if (tpg->pattern == TPG_PAT_NOISE || tpg->qual == TPG_QUAL_NOISE) {
2427 linestart_older = tpg->random_line[p] +
2428 twopixsize * prandom_u32_max(tpg->src_width / 2);
2429 linestart_newer = tpg->random_line[p] +
2430 twopixsize * prandom_u32_max(tpg->src_width / 2);
2431 } else {
2432 unsigned frame_line_old =
2433 (frame_line + mv_vert_old) % tpg->src_height;
2434 unsigned frame_line_new =
2435 (frame_line + mv_vert_new) % tpg->src_height;
2436 unsigned pat_line_next_old;
2437 unsigned pat_line_next_new;
2439 pat_line_old = tpg_get_pat_line(tpg, frame_line_old);
2440 pat_line_new = tpg_get_pat_line(tpg, frame_line_new);
2441 linestart_older = tpg->lines[pat_line_old][p] + mv_hor_old;
2442 linestart_newer = tpg->lines[pat_line_new][p] + mv_hor_new;
2444 if (tpg->vdownsampling[p] > 1 && frame_line != frame_line_next) {
2445 int avg_pat;
2448 * Now decide whether we need to use downsampled_lines[].
2449 * That's necessary if the two lines use different patterns.
2451 pat_line_next_old = tpg_get_pat_line(tpg,
2452 (frame_line_next + mv_vert_old) % tpg->src_height);
2453 pat_line_next_new = tpg_get_pat_line(tpg,
2454 (frame_line_next + mv_vert_new) % tpg->src_height);
2456 switch (tpg->field) {
2457 case V4L2_FIELD_INTERLACED:
2458 case V4L2_FIELD_INTERLACED_BT:
2459 case V4L2_FIELD_INTERLACED_TB:
2460 avg_pat = tpg_pattern_avg(tpg, pat_line_old, pat_line_new);
2461 if (avg_pat < 0)
2462 break;
2463 linestart_older = tpg->downsampled_lines[avg_pat][p] + mv_hor_old;
2464 linestart_newer = linestart_older;
2465 break;
2466 case V4L2_FIELD_NONE:
2467 case V4L2_FIELD_TOP:
2468 case V4L2_FIELD_BOTTOM:
2469 case V4L2_FIELD_SEQ_BT:
2470 case V4L2_FIELD_SEQ_TB:
2471 avg_pat = tpg_pattern_avg(tpg, pat_line_old, pat_line_next_old);
2472 if (avg_pat >= 0)
2473 linestart_older = tpg->downsampled_lines[avg_pat][p] +
2474 mv_hor_old;
2475 avg_pat = tpg_pattern_avg(tpg, pat_line_new, pat_line_next_new);
2476 if (avg_pat >= 0)
2477 linestart_newer = tpg->downsampled_lines[avg_pat][p] +
2478 mv_hor_new;
2479 break;
2482 linestart_older += line_offset;
2483 linestart_newer += line_offset;
2485 if (tpg->field_alternate) {
2486 linestart_top = linestart_bottom = linestart_older;
2487 } else if (params->is_60hz) {
2488 linestart_top = linestart_newer;
2489 linestart_bottom = linestart_older;
2490 } else {
2491 linestart_top = linestart_older;
2492 linestart_bottom = linestart_newer;
2495 switch (tpg->field) {
2496 case V4L2_FIELD_INTERLACED:
2497 case V4L2_FIELD_INTERLACED_TB:
2498 case V4L2_FIELD_SEQ_TB:
2499 case V4L2_FIELD_SEQ_BT:
2500 if (even)
2501 memcpy(vbuf, linestart_top, img_width);
2502 else
2503 memcpy(vbuf, linestart_bottom, img_width);
2504 break;
2505 case V4L2_FIELD_INTERLACED_BT:
2506 if (even)
2507 memcpy(vbuf, linestart_bottom, img_width);
2508 else
2509 memcpy(vbuf, linestart_top, img_width);
2510 break;
2511 case V4L2_FIELD_TOP:
2512 memcpy(vbuf, linestart_top, img_width);
2513 break;
2514 case V4L2_FIELD_BOTTOM:
2515 memcpy(vbuf, linestart_bottom, img_width);
2516 break;
2517 case V4L2_FIELD_NONE:
2518 default:
2519 memcpy(vbuf, linestart_older, img_width);
2520 break;
2524 void tpg_fill_plane_buffer(struct tpg_data *tpg, v4l2_std_id std,
2525 unsigned p, u8 *vbuf)
2527 struct tpg_draw_params params;
2528 unsigned factor = V4L2_FIELD_HAS_T_OR_B(tpg->field) ? 2 : 1;
2530 /* Coarse scaling with Bresenham */
2531 unsigned int_part = (tpg->crop.height / factor) / tpg->compose.height;
2532 unsigned fract_part = (tpg->crop.height / factor) % tpg->compose.height;
2533 unsigned src_y = 0;
2534 unsigned error = 0;
2535 unsigned h;
2537 tpg_recalc(tpg);
2539 params.is_tv = std;
2540 params.is_60hz = std & V4L2_STD_525_60;
2541 params.twopixsize = tpg->twopixelsize[p];
2542 params.img_width = tpg_hdiv(tpg, p, tpg->compose.width);
2543 params.stride = tpg->bytesperline[p];
2544 params.hmax = (tpg->compose.height * tpg->perc_fill) / 100;
2546 tpg_fill_params_pattern(tpg, p, &params);
2547 tpg_fill_params_extras(tpg, p, &params);
2549 vbuf += tpg_hdiv(tpg, p, tpg->compose.left);
2551 for (h = 0; h < tpg->compose.height; h++) {
2552 unsigned buf_line;
2554 params.frame_line = tpg_calc_frameline(tpg, src_y, tpg->field);
2555 params.frame_line_next = params.frame_line;
2556 buf_line = tpg_calc_buffer_line(tpg, h, tpg->field);
2557 src_y += int_part;
2558 error += fract_part;
2559 if (error >= tpg->compose.height) {
2560 error -= tpg->compose.height;
2561 src_y++;
2565 * For line-interleaved formats determine the 'plane'
2566 * based on the buffer line.
2568 if (tpg_g_interleaved(tpg))
2569 p = tpg_g_interleaved_plane(tpg, buf_line);
2571 if (tpg->vdownsampling[p] > 1) {
2573 * When doing vertical downsampling the field setting
2574 * matters: for SEQ_BT/TB we downsample each field
2575 * separately (i.e. lines 0+2 are combined, as are
2576 * lines 1+3), for the other field settings we combine
2577 * odd and even lines. Doing that for SEQ_BT/TB would
2578 * be really weird.
2580 if (tpg->field == V4L2_FIELD_SEQ_BT ||
2581 tpg->field == V4L2_FIELD_SEQ_TB) {
2582 unsigned next_src_y = src_y;
2584 if ((h & 3) >= 2)
2585 continue;
2586 next_src_y += int_part;
2587 if (error + fract_part >= tpg->compose.height)
2588 next_src_y++;
2589 params.frame_line_next =
2590 tpg_calc_frameline(tpg, next_src_y, tpg->field);
2591 } else {
2592 if (h & 1)
2593 continue;
2594 params.frame_line_next =
2595 tpg_calc_frameline(tpg, src_y, tpg->field);
2598 buf_line /= tpg->vdownsampling[p];
2600 tpg_fill_plane_pattern(tpg, &params, p, h,
2601 vbuf + buf_line * params.stride);
2602 tpg_fill_plane_extras(tpg, &params, p, h,
2603 vbuf + buf_line * params.stride);
2606 EXPORT_SYMBOL_GPL(tpg_fill_plane_buffer);
2608 void tpg_fillbuffer(struct tpg_data *tpg, v4l2_std_id std, unsigned p, u8 *vbuf)
2610 unsigned offset = 0;
2611 unsigned i;
2613 if (tpg->buffers > 1) {
2614 tpg_fill_plane_buffer(tpg, std, p, vbuf);
2615 return;
2618 for (i = 0; i < tpg_g_planes(tpg); i++) {
2619 tpg_fill_plane_buffer(tpg, std, i, vbuf + offset);
2620 offset += tpg_calc_plane_size(tpg, i);
2623 EXPORT_SYMBOL_GPL(tpg_fillbuffer);
2625 MODULE_DESCRIPTION("V4L2 Test Pattern Generator");
2626 MODULE_AUTHOR("Hans Verkuil");
2627 MODULE_LICENSE("GPL");