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