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