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