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