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