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