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