Merge branch 'fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/evalenti/linux...
[linux/fpc-iii.git] / drivers / media / platform / vivid / vivid-tpg.c
blobda862bb2e5f86141a7ec15016928f322a5c04e1d
1 /*
2 * vivid-tpg.c - Test Pattern Generator
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.
7 * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
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.
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.
23 #include "vivid-tpg.h"
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
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
63 * Sine table: sin[0] = 127 * sin(-180 degrees)
64 * sin[128] = 127 * sin(0 degrees)
65 * sin[256] = 127 * sin(180 degrees)
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,
87 #define cos(idx) sin[((idx) + 64) % sizeof(sin)]
89 /* Global font descriptor */
90 static const u8 *font8x16;
92 void tpg_set_font(const u8 *f)
94 font8x16 = f;
97 void tpg_init(struct tpg_data *tpg, unsigned w, unsigned h)
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;
118 int tpg_alloc(struct tpg_data *tpg, unsigned max_w)
120 unsigned pat;
121 unsigned plane;
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;
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;
138 for (plane = 0; plane < TPG_MAX_PLANES; plane++) {
139 unsigned pixelsz = plane ? 2 : 4;
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;
151 return 0;
154 void tpg_free(struct tpg_data *tpg)
156 unsigned pat;
157 unsigned plane;
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;
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;
178 bool tpg_s_fourcc(struct tpg_data *tpg, u32 fourcc)
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;
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_YUV422M:
255 case V4L2_PIX_FMT_YVU422M:
256 tpg->buffers = 3;
257 /* fall through */
258 case V4L2_PIX_FMT_YUV422P:
259 tpg->vdownsampling[1] = 1;
260 tpg->vdownsampling[2] = 1;
261 tpg->hdownsampling[1] = 2;
262 tpg->hdownsampling[2] = 2;
263 tpg->planes = 3;
264 tpg->is_yuv = true;
265 break;
266 case V4L2_PIX_FMT_NV16M:
267 case V4L2_PIX_FMT_NV61M:
268 tpg->buffers = 2;
269 /* fall through */
270 case V4L2_PIX_FMT_NV16:
271 case V4L2_PIX_FMT_NV61:
272 tpg->vdownsampling[1] = 1;
273 tpg->hdownsampling[1] = 1;
274 tpg->hmask[1] = ~1;
275 tpg->planes = 2;
276 tpg->is_yuv = true;
277 break;
278 case V4L2_PIX_FMT_NV12M:
279 case V4L2_PIX_FMT_NV21M:
280 tpg->buffers = 2;
281 /* fall through */
282 case V4L2_PIX_FMT_NV12:
283 case V4L2_PIX_FMT_NV21:
284 tpg->vdownsampling[1] = 2;
285 tpg->hdownsampling[1] = 1;
286 tpg->hmask[1] = ~1;
287 tpg->planes = 2;
288 tpg->is_yuv = true;
289 break;
290 case V4L2_PIX_FMT_YUV444M:
291 case V4L2_PIX_FMT_YVU444M:
292 tpg->buffers = 3;
293 tpg->planes = 3;
294 tpg->vdownsampling[1] = 1;
295 tpg->vdownsampling[2] = 1;
296 tpg->hdownsampling[1] = 1;
297 tpg->hdownsampling[2] = 1;
298 tpg->is_yuv = true;
299 break;
300 case V4L2_PIX_FMT_NV24:
301 case V4L2_PIX_FMT_NV42:
302 tpg->vdownsampling[1] = 1;
303 tpg->hdownsampling[1] = 1;
304 tpg->planes = 2;
305 tpg->is_yuv = true;
306 break;
307 case V4L2_PIX_FMT_YUYV:
308 case V4L2_PIX_FMT_UYVY:
309 case V4L2_PIX_FMT_YVYU:
310 case V4L2_PIX_FMT_VYUY:
311 tpg->hmask[0] = ~1;
312 tpg->is_yuv = true;
313 break;
314 default:
315 return false;
318 switch (fourcc) {
319 case V4L2_PIX_FMT_GREY:
320 case V4L2_PIX_FMT_RGB332:
321 tpg->twopixelsize[0] = 2;
322 break;
323 case V4L2_PIX_FMT_RGB565:
324 case V4L2_PIX_FMT_RGB565X:
325 case V4L2_PIX_FMT_RGB444:
326 case V4L2_PIX_FMT_XRGB444:
327 case V4L2_PIX_FMT_ARGB444:
328 case V4L2_PIX_FMT_RGB555:
329 case V4L2_PIX_FMT_XRGB555:
330 case V4L2_PIX_FMT_ARGB555:
331 case V4L2_PIX_FMT_RGB555X:
332 case V4L2_PIX_FMT_XRGB555X:
333 case V4L2_PIX_FMT_ARGB555X:
334 case V4L2_PIX_FMT_YUYV:
335 case V4L2_PIX_FMT_UYVY:
336 case V4L2_PIX_FMT_YVYU:
337 case V4L2_PIX_FMT_VYUY:
338 case V4L2_PIX_FMT_YUV444:
339 case V4L2_PIX_FMT_YUV555:
340 case V4L2_PIX_FMT_YUV565:
341 case V4L2_PIX_FMT_Y16:
342 case V4L2_PIX_FMT_Y16_BE:
343 tpg->twopixelsize[0] = 2 * 2;
344 break;
345 case V4L2_PIX_FMT_RGB24:
346 case V4L2_PIX_FMT_BGR24:
347 tpg->twopixelsize[0] = 2 * 3;
348 break;
349 case V4L2_PIX_FMT_BGR666:
350 case V4L2_PIX_FMT_RGB32:
351 case V4L2_PIX_FMT_BGR32:
352 case V4L2_PIX_FMT_XRGB32:
353 case V4L2_PIX_FMT_XBGR32:
354 case V4L2_PIX_FMT_ARGB32:
355 case V4L2_PIX_FMT_ABGR32:
356 case V4L2_PIX_FMT_YUV32:
357 tpg->twopixelsize[0] = 2 * 4;
358 break;
359 case V4L2_PIX_FMT_NV12:
360 case V4L2_PIX_FMT_NV21:
361 case V4L2_PIX_FMT_NV12M:
362 case V4L2_PIX_FMT_NV21M:
363 case V4L2_PIX_FMT_NV16:
364 case V4L2_PIX_FMT_NV61:
365 case V4L2_PIX_FMT_NV16M:
366 case V4L2_PIX_FMT_NV61M:
367 case V4L2_PIX_FMT_SBGGR8:
368 case V4L2_PIX_FMT_SGBRG8:
369 case V4L2_PIX_FMT_SGRBG8:
370 case V4L2_PIX_FMT_SRGGB8:
371 tpg->twopixelsize[0] = 2;
372 tpg->twopixelsize[1] = 2;
373 break;
374 case V4L2_PIX_FMT_SRGGB10:
375 case V4L2_PIX_FMT_SGRBG10:
376 case V4L2_PIX_FMT_SGBRG10:
377 case V4L2_PIX_FMT_SBGGR10:
378 case V4L2_PIX_FMT_SRGGB12:
379 case V4L2_PIX_FMT_SGRBG12:
380 case V4L2_PIX_FMT_SGBRG12:
381 case V4L2_PIX_FMT_SBGGR12:
382 tpg->twopixelsize[0] = 4;
383 tpg->twopixelsize[1] = 4;
384 break;
385 case V4L2_PIX_FMT_YUV444M:
386 case V4L2_PIX_FMT_YVU444M:
387 case V4L2_PIX_FMT_YUV422M:
388 case V4L2_PIX_FMT_YVU422M:
389 case V4L2_PIX_FMT_YUV422P:
390 case V4L2_PIX_FMT_YUV420:
391 case V4L2_PIX_FMT_YVU420:
392 case V4L2_PIX_FMT_YUV420M:
393 case V4L2_PIX_FMT_YVU420M:
394 tpg->twopixelsize[0] = 2;
395 tpg->twopixelsize[1] = 2;
396 tpg->twopixelsize[2] = 2;
397 break;
398 case V4L2_PIX_FMT_NV24:
399 case V4L2_PIX_FMT_NV42:
400 tpg->twopixelsize[0] = 2;
401 tpg->twopixelsize[1] = 4;
402 break;
404 return true;
407 void tpg_s_crop_compose(struct tpg_data *tpg, const struct v4l2_rect *crop,
408 const struct v4l2_rect *compose)
410 tpg->crop = *crop;
411 tpg->compose = *compose;
412 tpg->scaled_width = (tpg->src_width * tpg->compose.width +
413 tpg->crop.width - 1) / tpg->crop.width;
414 tpg->scaled_width &= ~1;
415 if (tpg->scaled_width > tpg->max_line_width)
416 tpg->scaled_width = tpg->max_line_width;
417 if (tpg->scaled_width < 2)
418 tpg->scaled_width = 2;
419 tpg->recalc_lines = true;
422 void tpg_reset_source(struct tpg_data *tpg, unsigned width, unsigned height,
423 u32 field)
425 unsigned p;
427 tpg->src_width = width;
428 tpg->src_height = height;
429 tpg->field = field;
430 tpg->buf_height = height;
431 if (V4L2_FIELD_HAS_T_OR_B(field))
432 tpg->buf_height /= 2;
433 tpg->scaled_width = width;
434 tpg->crop.top = tpg->crop.left = 0;
435 tpg->crop.width = width;
436 tpg->crop.height = height;
437 tpg->compose.top = tpg->compose.left = 0;
438 tpg->compose.width = width;
439 tpg->compose.height = tpg->buf_height;
440 for (p = 0; p < tpg->planes; p++)
441 tpg->bytesperline[p] = (width * tpg->twopixelsize[p]) /
442 (2 * tpg->hdownsampling[p]);
443 tpg->recalc_square_border = true;
446 static enum tpg_color tpg_get_textbg_color(struct tpg_data *tpg)
448 switch (tpg->pattern) {
449 case TPG_PAT_BLACK:
450 return TPG_COLOR_100_WHITE;
451 case TPG_PAT_CSC_COLORBAR:
452 return TPG_COLOR_CSC_BLACK;
453 default:
454 return TPG_COLOR_100_BLACK;
458 static enum tpg_color tpg_get_textfg_color(struct tpg_data *tpg)
460 switch (tpg->pattern) {
461 case TPG_PAT_75_COLORBAR:
462 case TPG_PAT_CSC_COLORBAR:
463 return TPG_COLOR_CSC_WHITE;
464 case TPG_PAT_BLACK:
465 return TPG_COLOR_100_BLACK;
466 default:
467 return TPG_COLOR_100_WHITE;
471 static inline int rec709_to_linear(int v)
473 v = clamp(v, 0, 0xff0);
474 return tpg_rec709_to_linear[v];
477 static inline int linear_to_rec709(int v)
479 v = clamp(v, 0, 0xff0);
480 return tpg_linear_to_rec709[v];
483 static void rgb2ycbcr(const int m[3][3], int r, int g, int b,
484 int y_offset, int *y, int *cb, int *cr)
486 *y = ((m[0][0] * r + m[0][1] * g + m[0][2] * b) >> 16) + (y_offset << 4);
487 *cb = ((m[1][0] * r + m[1][1] * g + m[1][2] * b) >> 16) + (128 << 4);
488 *cr = ((m[2][0] * r + m[2][1] * g + m[2][2] * b) >> 16) + (128 << 4);
491 static void color_to_ycbcr(struct tpg_data *tpg, int r, int g, int b,
492 int *y, int *cb, int *cr)
494 #define COEFF(v, r) ((int)(0.5 + (v) * (r) * 256.0))
496 static const int bt601[3][3] = {
497 { COEFF(0.299, 219), COEFF(0.587, 219), COEFF(0.114, 219) },
498 { COEFF(-0.169, 224), COEFF(-0.331, 224), COEFF(0.5, 224) },
499 { COEFF(0.5, 224), COEFF(-0.419, 224), COEFF(-0.081, 224) },
501 static const int bt601_full[3][3] = {
502 { COEFF(0.299, 255), COEFF(0.587, 255), COEFF(0.114, 255) },
503 { COEFF(-0.169, 255), COEFF(-0.331, 255), COEFF(0.5, 255) },
504 { COEFF(0.5, 255), COEFF(-0.419, 255), COEFF(-0.081, 255) },
506 static const int rec709[3][3] = {
507 { COEFF(0.2126, 219), COEFF(0.7152, 219), COEFF(0.0722, 219) },
508 { COEFF(-0.1146, 224), COEFF(-0.3854, 224), COEFF(0.5, 224) },
509 { COEFF(0.5, 224), COEFF(-0.4542, 224), COEFF(-0.0458, 224) },
511 static const int rec709_full[3][3] = {
512 { COEFF(0.2126, 255), COEFF(0.7152, 255), COEFF(0.0722, 255) },
513 { COEFF(-0.1146, 255), COEFF(-0.3854, 255), COEFF(0.5, 255) },
514 { COEFF(0.5, 255), COEFF(-0.4542, 255), COEFF(-0.0458, 255) },
516 static const int smpte240m[3][3] = {
517 { COEFF(0.212, 219), COEFF(0.701, 219), COEFF(0.087, 219) },
518 { COEFF(-0.116, 224), COEFF(-0.384, 224), COEFF(0.5, 224) },
519 { COEFF(0.5, 224), COEFF(-0.445, 224), COEFF(-0.055, 224) },
521 static const int smpte240m_full[3][3] = {
522 { COEFF(0.212, 255), COEFF(0.701, 255), COEFF(0.087, 255) },
523 { COEFF(-0.116, 255), COEFF(-0.384, 255), COEFF(0.5, 255) },
524 { COEFF(0.5, 255), COEFF(-0.445, 255), COEFF(-0.055, 255) },
526 static const int bt2020[3][3] = {
527 { COEFF(0.2627, 219), COEFF(0.6780, 219), COEFF(0.0593, 219) },
528 { COEFF(-0.1396, 224), COEFF(-0.3604, 224), COEFF(0.5, 224) },
529 { COEFF(0.5, 224), COEFF(-0.4598, 224), COEFF(-0.0402, 224) },
531 static const int bt2020_full[3][3] = {
532 { COEFF(0.2627, 255), COEFF(0.6780, 255), COEFF(0.0593, 255) },
533 { COEFF(-0.1396, 255), COEFF(-0.3604, 255), COEFF(0.5, 255) },
534 { COEFF(0.5, 255), COEFF(-0.4698, 255), COEFF(-0.0402, 255) },
536 static const int bt2020c[4] = {
537 COEFF(1.0 / 1.9404, 224), COEFF(1.0 / 1.5816, 224),
538 COEFF(1.0 / 1.7184, 224), COEFF(1.0 / 0.9936, 224),
540 static const int bt2020c_full[4] = {
541 COEFF(1.0 / 1.9404, 255), COEFF(1.0 / 1.5816, 255),
542 COEFF(1.0 / 1.7184, 255), COEFF(1.0 / 0.9936, 255),
545 bool full = tpg->real_quantization == V4L2_QUANTIZATION_FULL_RANGE;
546 unsigned y_offset = full ? 0 : 16;
547 int lin_y, yc;
549 switch (tpg->real_ycbcr_enc) {
550 case V4L2_YCBCR_ENC_601:
551 case V4L2_YCBCR_ENC_SYCC:
552 rgb2ycbcr(full ? bt601_full : bt601, r, g, b, y_offset, y, cb, cr);
553 break;
554 case V4L2_YCBCR_ENC_XV601:
555 /* Ignore quantization range, there is only one possible
556 * Y'CbCr encoding. */
557 rgb2ycbcr(bt601, r, g, b, 16, y, cb, cr);
558 break;
559 case V4L2_YCBCR_ENC_XV709:
560 /* Ignore quantization range, there is only one possible
561 * Y'CbCr encoding. */
562 rgb2ycbcr(rec709, r, g, b, 16, y, cb, cr);
563 break;
564 case V4L2_YCBCR_ENC_BT2020:
565 rgb2ycbcr(full ? bt2020_full : bt2020, r, g, b, y_offset, y, cb, cr);
566 break;
567 case V4L2_YCBCR_ENC_BT2020_CONST_LUM:
568 lin_y = (COEFF(0.2627, 255) * rec709_to_linear(r) +
569 COEFF(0.6780, 255) * rec709_to_linear(g) +
570 COEFF(0.0593, 255) * rec709_to_linear(b)) >> 16;
571 yc = linear_to_rec709(lin_y);
572 *y = full ? yc : (yc * 219) / 255 + (16 << 4);
573 if (b <= yc)
574 *cb = (((b - yc) * (full ? bt2020c_full[0] : bt2020c[0])) >> 16) + (128 << 4);
575 else
576 *cb = (((b - yc) * (full ? bt2020c_full[1] : bt2020c[1])) >> 16) + (128 << 4);
577 if (r <= yc)
578 *cr = (((r - yc) * (full ? bt2020c_full[2] : bt2020c[2])) >> 16) + (128 << 4);
579 else
580 *cr = (((r - yc) * (full ? bt2020c_full[3] : bt2020c[3])) >> 16) + (128 << 4);
581 break;
582 case V4L2_YCBCR_ENC_SMPTE240M:
583 rgb2ycbcr(full ? smpte240m_full : smpte240m, r, g, b, y_offset, y, cb, cr);
584 break;
585 case V4L2_YCBCR_ENC_709:
586 default:
587 rgb2ycbcr(full ? rec709_full : rec709, r, g, b, y_offset, y, cb, cr);
588 break;
592 static void ycbcr2rgb(const int m[3][3], int y, int cb, int cr,
593 int y_offset, int *r, int *g, int *b)
595 y -= y_offset << 4;
596 cb -= 128 << 4;
597 cr -= 128 << 4;
598 *r = m[0][0] * y + m[0][1] * cb + m[0][2] * cr;
599 *g = m[1][0] * y + m[1][1] * cb + m[1][2] * cr;
600 *b = m[2][0] * y + m[2][1] * cb + m[2][2] * cr;
601 *r = clamp(*r >> 12, 0, 0xff0);
602 *g = clamp(*g >> 12, 0, 0xff0);
603 *b = clamp(*b >> 12, 0, 0xff0);
606 static void ycbcr_to_color(struct tpg_data *tpg, int y, int cb, int cr,
607 int *r, int *g, int *b)
609 #undef COEFF
610 #define COEFF(v, r) ((int)(0.5 + (v) * ((255.0 * 255.0 * 16.0) / (r))))
611 static const int bt601[3][3] = {
612 { COEFF(1, 219), COEFF(0, 224), COEFF(1.4020, 224) },
613 { COEFF(1, 219), COEFF(-0.3441, 224), COEFF(-0.7141, 224) },
614 { COEFF(1, 219), COEFF(1.7720, 224), COEFF(0, 224) },
616 static const int bt601_full[3][3] = {
617 { COEFF(1, 255), COEFF(0, 255), COEFF(1.4020, 255) },
618 { COEFF(1, 255), COEFF(-0.3441, 255), COEFF(-0.7141, 255) },
619 { COEFF(1, 255), COEFF(1.7720, 255), COEFF(0, 255) },
621 static const int rec709[3][3] = {
622 { COEFF(1, 219), COEFF(0, 224), COEFF(1.5748, 224) },
623 { COEFF(1, 219), COEFF(-0.1873, 224), COEFF(-0.4681, 224) },
624 { COEFF(1, 219), COEFF(1.8556, 224), COEFF(0, 224) },
626 static const int rec709_full[3][3] = {
627 { COEFF(1, 255), COEFF(0, 255), COEFF(1.5748, 255) },
628 { COEFF(1, 255), COEFF(-0.1873, 255), COEFF(-0.4681, 255) },
629 { COEFF(1, 255), COEFF(1.8556, 255), COEFF(0, 255) },
631 static const int smpte240m[3][3] = {
632 { COEFF(1, 219), COEFF(0, 224), COEFF(1.5756, 224) },
633 { COEFF(1, 219), COEFF(-0.2253, 224), COEFF(-0.4767, 224) },
634 { COEFF(1, 219), COEFF(1.8270, 224), COEFF(0, 224) },
636 static const int smpte240m_full[3][3] = {
637 { COEFF(1, 255), COEFF(0, 255), COEFF(1.5756, 255) },
638 { COEFF(1, 255), COEFF(-0.2253, 255), COEFF(-0.4767, 255) },
639 { COEFF(1, 255), COEFF(1.8270, 255), COEFF(0, 255) },
641 static const int bt2020[3][3] = {
642 { COEFF(1, 219), COEFF(0, 224), COEFF(1.4746, 224) },
643 { COEFF(1, 219), COEFF(-0.1646, 224), COEFF(-0.5714, 224) },
644 { COEFF(1, 219), COEFF(1.8814, 224), COEFF(0, 224) },
646 static const int bt2020_full[3][3] = {
647 { COEFF(1, 255), COEFF(0, 255), COEFF(1.4746, 255) },
648 { COEFF(1, 255), COEFF(-0.1646, 255), COEFF(-0.5714, 255) },
649 { COEFF(1, 255), COEFF(1.8814, 255), COEFF(0, 255) },
651 static const int bt2020c[4] = {
652 COEFF(1.9404, 224), COEFF(1.5816, 224),
653 COEFF(1.7184, 224), COEFF(0.9936, 224),
655 static const int bt2020c_full[4] = {
656 COEFF(1.9404, 255), COEFF(1.5816, 255),
657 COEFF(1.7184, 255), COEFF(0.9936, 255),
660 bool full = tpg->real_quantization == V4L2_QUANTIZATION_FULL_RANGE;
661 unsigned y_offset = full ? 0 : 16;
662 int y_fac = full ? COEFF(1.0, 255) : COEFF(1.0, 219);
663 int lin_r, lin_g, lin_b, lin_y;
665 switch (tpg->real_ycbcr_enc) {
666 case V4L2_YCBCR_ENC_601:
667 case V4L2_YCBCR_ENC_SYCC:
668 ycbcr2rgb(full ? bt601_full : bt601, y, cb, cr, y_offset, r, g, b);
669 break;
670 case V4L2_YCBCR_ENC_XV601:
671 /* Ignore quantization range, there is only one possible
672 * Y'CbCr encoding. */
673 ycbcr2rgb(bt601, y, cb, cr, 16, r, g, b);
674 break;
675 case V4L2_YCBCR_ENC_XV709:
676 /* Ignore quantization range, there is only one possible
677 * Y'CbCr encoding. */
678 ycbcr2rgb(rec709, y, cb, cr, 16, r, g, b);
679 break;
680 case V4L2_YCBCR_ENC_BT2020:
681 ycbcr2rgb(full ? bt2020_full : bt2020, y, cb, cr, y_offset, r, g, b);
682 break;
683 case V4L2_YCBCR_ENC_BT2020_CONST_LUM:
684 y -= full ? 0 : 16 << 4;
685 cb -= 128 << 4;
686 cr -= 128 << 4;
688 if (cb <= 0)
689 *b = y_fac * y + (full ? bt2020c_full[0] : bt2020c[0]) * cb;
690 else
691 *b = y_fac * y + (full ? bt2020c_full[1] : bt2020c[1]) * cb;
692 *b = *b >> 12;
693 if (cr <= 0)
694 *r = y_fac * y + (full ? bt2020c_full[2] : bt2020c[2]) * cr;
695 else
696 *r = y_fac * y + (full ? bt2020c_full[3] : bt2020c[3]) * cr;
697 *r = *r >> 12;
698 lin_r = rec709_to_linear(*r);
699 lin_b = rec709_to_linear(*b);
700 lin_y = rec709_to_linear((y * 255) / (full ? 255 : 219));
702 lin_g = COEFF(1.0 / 0.6780, 255) * lin_y -
703 COEFF(0.2627 / 0.6780, 255) * lin_r -
704 COEFF(0.0593 / 0.6780, 255) * lin_b;
705 *g = linear_to_rec709(lin_g >> 12);
706 break;
707 case V4L2_YCBCR_ENC_SMPTE240M:
708 ycbcr2rgb(full ? smpte240m_full : smpte240m, y, cb, cr, y_offset, r, g, b);
709 break;
710 case V4L2_YCBCR_ENC_709:
711 default:
712 ycbcr2rgb(full ? rec709_full : rec709, y, cb, cr, y_offset, r, g, b);
713 break;
717 /* precalculate color bar values to speed up rendering */
718 static void precalculate_color(struct tpg_data *tpg, int k)
720 int col = k;
721 int r = tpg_colors[col].r;
722 int g = tpg_colors[col].g;
723 int b = tpg_colors[col].b;
725 if (k == TPG_COLOR_TEXTBG) {
726 col = tpg_get_textbg_color(tpg);
728 r = tpg_colors[col].r;
729 g = tpg_colors[col].g;
730 b = tpg_colors[col].b;
731 } else if (k == TPG_COLOR_TEXTFG) {
732 col = tpg_get_textfg_color(tpg);
734 r = tpg_colors[col].r;
735 g = tpg_colors[col].g;
736 b = tpg_colors[col].b;
737 } else if (tpg->pattern == TPG_PAT_NOISE) {
738 r = g = b = prandom_u32_max(256);
739 } else if (k == TPG_COLOR_RANDOM) {
740 r = g = b = tpg->qual_offset + prandom_u32_max(196);
741 } else if (k >= TPG_COLOR_RAMP) {
742 r = g = b = k - TPG_COLOR_RAMP;
745 if (tpg->pattern == TPG_PAT_CSC_COLORBAR && col <= TPG_COLOR_CSC_BLACK) {
746 r = tpg_csc_colors[tpg->colorspace][tpg->real_xfer_func][col].r;
747 g = tpg_csc_colors[tpg->colorspace][tpg->real_xfer_func][col].g;
748 b = tpg_csc_colors[tpg->colorspace][tpg->real_xfer_func][col].b;
749 } else {
750 r <<= 4;
751 g <<= 4;
752 b <<= 4;
754 if (tpg->qual == TPG_QUAL_GRAY || tpg->fourcc == V4L2_PIX_FMT_GREY ||
755 tpg->fourcc == V4L2_PIX_FMT_Y16 ||
756 tpg->fourcc == V4L2_PIX_FMT_Y16_BE) {
757 /* Rec. 709 Luma function */
758 /* (0.2126, 0.7152, 0.0722) * (255 * 256) */
759 r = g = b = (13879 * r + 46688 * g + 4713 * b) >> 16;
763 * The assumption is that the RGB output is always full range,
764 * so only if the rgb_range overrides the 'real' rgb range do
765 * we need to convert the RGB values.
767 * Remember that r, g and b are still in the 0 - 0xff0 range.
769 if (tpg->real_rgb_range == V4L2_DV_RGB_RANGE_LIMITED &&
770 tpg->rgb_range == V4L2_DV_RGB_RANGE_FULL) {
772 * Convert from full range (which is what r, g and b are)
773 * to limited range (which is the 'real' RGB range), which
774 * is then interpreted as full range.
776 r = (r * 219) / 255 + (16 << 4);
777 g = (g * 219) / 255 + (16 << 4);
778 b = (b * 219) / 255 + (16 << 4);
779 } else if (tpg->real_rgb_range != V4L2_DV_RGB_RANGE_LIMITED &&
780 tpg->rgb_range == V4L2_DV_RGB_RANGE_LIMITED) {
782 * Clamp r, g and b to the limited range and convert to full
783 * range since that's what we deliver.
785 r = clamp(r, 16 << 4, 235 << 4);
786 g = clamp(g, 16 << 4, 235 << 4);
787 b = clamp(b, 16 << 4, 235 << 4);
788 r = (r - (16 << 4)) * 255 / 219;
789 g = (g - (16 << 4)) * 255 / 219;
790 b = (b - (16 << 4)) * 255 / 219;
793 if (tpg->brightness != 128 || tpg->contrast != 128 ||
794 tpg->saturation != 128 || tpg->hue) {
795 /* Implement these operations */
796 int y, cb, cr;
797 int tmp_cb, tmp_cr;
799 /* First convert to YCbCr */
801 color_to_ycbcr(tpg, r, g, b, &y, &cb, &cr);
803 y = (16 << 4) + ((y - (16 << 4)) * tpg->contrast) / 128;
804 y += (tpg->brightness << 4) - (128 << 4);
806 cb -= 128 << 4;
807 cr -= 128 << 4;
808 tmp_cb = (cb * cos(128 + tpg->hue)) / 127 + (cr * sin[128 + tpg->hue]) / 127;
809 tmp_cr = (cr * cos(128 + tpg->hue)) / 127 - (cb * sin[128 + tpg->hue]) / 127;
811 cb = (128 << 4) + (tmp_cb * tpg->contrast * tpg->saturation) / (128 * 128);
812 cr = (128 << 4) + (tmp_cr * tpg->contrast * tpg->saturation) / (128 * 128);
813 if (tpg->is_yuv) {
814 tpg->colors[k][0] = clamp(y >> 4, 1, 254);
815 tpg->colors[k][1] = clamp(cb >> 4, 1, 254);
816 tpg->colors[k][2] = clamp(cr >> 4, 1, 254);
817 return;
819 ycbcr_to_color(tpg, y, cb, cr, &r, &g, &b);
822 if (tpg->is_yuv) {
823 /* Convert to YCbCr */
824 int y, cb, cr;
826 color_to_ycbcr(tpg, r, g, b, &y, &cb, &cr);
828 if (tpg->real_quantization == V4L2_QUANTIZATION_LIM_RANGE) {
829 y = clamp(y, 16 << 4, 235 << 4);
830 cb = clamp(cb, 16 << 4, 240 << 4);
831 cr = clamp(cr, 16 << 4, 240 << 4);
833 y = clamp(y >> 4, 1, 254);
834 cb = clamp(cb >> 4, 1, 254);
835 cr = clamp(cr >> 4, 1, 254);
836 switch (tpg->fourcc) {
837 case V4L2_PIX_FMT_YUV444:
838 y >>= 4;
839 cb >>= 4;
840 cr >>= 4;
841 break;
842 case V4L2_PIX_FMT_YUV555:
843 y >>= 3;
844 cb >>= 3;
845 cr >>= 3;
846 break;
847 case V4L2_PIX_FMT_YUV565:
848 y >>= 3;
849 cb >>= 2;
850 cr >>= 3;
851 break;
853 tpg->colors[k][0] = y;
854 tpg->colors[k][1] = cb;
855 tpg->colors[k][2] = cr;
856 } else {
857 if (tpg->real_quantization == V4L2_QUANTIZATION_LIM_RANGE) {
858 r = (r * 219) / 255 + (16 << 4);
859 g = (g * 219) / 255 + (16 << 4);
860 b = (b * 219) / 255 + (16 << 4);
862 switch (tpg->fourcc) {
863 case V4L2_PIX_FMT_RGB332:
864 r >>= 9;
865 g >>= 9;
866 b >>= 10;
867 break;
868 case V4L2_PIX_FMT_RGB565:
869 case V4L2_PIX_FMT_RGB565X:
870 r >>= 7;
871 g >>= 6;
872 b >>= 7;
873 break;
874 case V4L2_PIX_FMT_RGB444:
875 case V4L2_PIX_FMT_XRGB444:
876 case V4L2_PIX_FMT_ARGB444:
877 r >>= 8;
878 g >>= 8;
879 b >>= 8;
880 break;
881 case V4L2_PIX_FMT_RGB555:
882 case V4L2_PIX_FMT_XRGB555:
883 case V4L2_PIX_FMT_ARGB555:
884 case V4L2_PIX_FMT_RGB555X:
885 case V4L2_PIX_FMT_XRGB555X:
886 case V4L2_PIX_FMT_ARGB555X:
887 r >>= 7;
888 g >>= 7;
889 b >>= 7;
890 break;
891 case V4L2_PIX_FMT_BGR666:
892 r >>= 6;
893 g >>= 6;
894 b >>= 6;
895 break;
896 default:
897 r >>= 4;
898 g >>= 4;
899 b >>= 4;
900 break;
903 tpg->colors[k][0] = r;
904 tpg->colors[k][1] = g;
905 tpg->colors[k][2] = b;
909 static void tpg_precalculate_colors(struct tpg_data *tpg)
911 int k;
913 for (k = 0; k < TPG_COLOR_MAX; k++)
914 precalculate_color(tpg, k);
917 /* 'odd' is true for pixels 1, 3, 5, etc. and false for pixels 0, 2, 4, etc. */
918 static void gen_twopix(struct tpg_data *tpg,
919 u8 buf[TPG_MAX_PLANES][8], int color, bool odd)
921 unsigned offset = odd * tpg->twopixelsize[0] / 2;
922 u8 alpha = tpg->alpha_component;
923 u8 r_y, g_u, b_v;
925 if (tpg->alpha_red_only && color != TPG_COLOR_CSC_RED &&
926 color != TPG_COLOR_100_RED &&
927 color != TPG_COLOR_75_RED)
928 alpha = 0;
929 if (color == TPG_COLOR_RANDOM)
930 precalculate_color(tpg, color);
931 r_y = tpg->colors[color][0]; /* R or precalculated Y */
932 g_u = tpg->colors[color][1]; /* G or precalculated U */
933 b_v = tpg->colors[color][2]; /* B or precalculated V */
935 switch (tpg->fourcc) {
936 case V4L2_PIX_FMT_GREY:
937 buf[0][offset] = r_y;
938 break;
939 case V4L2_PIX_FMT_Y16:
941 * Ideally both bytes should be set to r_y, but then you won't
942 * be able to detect endian problems. So keep it 0 except for
943 * the corner case where r_y is 0xff so white really will be
944 * white (0xffff).
946 buf[0][offset] = r_y == 0xff ? r_y : 0;
947 buf[0][offset+1] = r_y;
948 break;
949 case V4L2_PIX_FMT_Y16_BE:
950 /* See comment for V4L2_PIX_FMT_Y16 above */
951 buf[0][offset] = r_y;
952 buf[0][offset+1] = r_y == 0xff ? r_y : 0;
953 break;
954 case V4L2_PIX_FMT_YUV422M:
955 case V4L2_PIX_FMT_YUV422P:
956 case V4L2_PIX_FMT_YUV420:
957 case V4L2_PIX_FMT_YUV420M:
958 buf[0][offset] = r_y;
959 if (odd) {
960 buf[1][0] = (buf[1][0] + g_u) / 2;
961 buf[2][0] = (buf[2][0] + b_v) / 2;
962 buf[1][1] = buf[1][0];
963 buf[2][1] = buf[2][0];
964 break;
966 buf[1][0] = g_u;
967 buf[2][0] = b_v;
968 break;
969 case V4L2_PIX_FMT_YVU422M:
970 case V4L2_PIX_FMT_YVU420:
971 case V4L2_PIX_FMT_YVU420M:
972 buf[0][offset] = r_y;
973 if (odd) {
974 buf[1][0] = (buf[1][0] + b_v) / 2;
975 buf[2][0] = (buf[2][0] + g_u) / 2;
976 buf[1][1] = buf[1][0];
977 buf[2][1] = buf[2][0];
978 break;
980 buf[1][0] = b_v;
981 buf[2][0] = g_u;
982 break;
984 case V4L2_PIX_FMT_NV12:
985 case V4L2_PIX_FMT_NV12M:
986 case V4L2_PIX_FMT_NV16:
987 case V4L2_PIX_FMT_NV16M:
988 buf[0][offset] = r_y;
989 if (odd) {
990 buf[1][0] = (buf[1][0] + g_u) / 2;
991 buf[1][1] = (buf[1][1] + b_v) / 2;
992 break;
994 buf[1][0] = g_u;
995 buf[1][1] = b_v;
996 break;
997 case V4L2_PIX_FMT_NV21:
998 case V4L2_PIX_FMT_NV21M:
999 case V4L2_PIX_FMT_NV61:
1000 case V4L2_PIX_FMT_NV61M:
1001 buf[0][offset] = r_y;
1002 if (odd) {
1003 buf[1][0] = (buf[1][0] + b_v) / 2;
1004 buf[1][1] = (buf[1][1] + g_u) / 2;
1005 break;
1007 buf[1][0] = b_v;
1008 buf[1][1] = g_u;
1009 break;
1011 case V4L2_PIX_FMT_YUV444M:
1012 buf[0][offset] = r_y;
1013 buf[1][offset] = g_u;
1014 buf[2][offset] = b_v;
1015 break;
1017 case V4L2_PIX_FMT_YVU444M:
1018 buf[0][offset] = r_y;
1019 buf[1][offset] = b_v;
1020 buf[2][offset] = g_u;
1021 break;
1023 case V4L2_PIX_FMT_NV24:
1024 buf[0][offset] = r_y;
1025 buf[1][2 * offset] = g_u;
1026 buf[1][2 * offset + 1] = b_v;
1027 break;
1029 case V4L2_PIX_FMT_NV42:
1030 buf[0][offset] = r_y;
1031 buf[1][2 * offset] = b_v;
1032 buf[1][2 * offset + 1] = g_u;
1033 break;
1035 case V4L2_PIX_FMT_YUYV:
1036 buf[0][offset] = r_y;
1037 if (odd) {
1038 buf[0][1] = (buf[0][1] + g_u) / 2;
1039 buf[0][3] = (buf[0][3] + b_v) / 2;
1040 break;
1042 buf[0][1] = g_u;
1043 buf[0][3] = b_v;
1044 break;
1045 case V4L2_PIX_FMT_UYVY:
1046 buf[0][offset + 1] = r_y;
1047 if (odd) {
1048 buf[0][0] = (buf[0][0] + g_u) / 2;
1049 buf[0][2] = (buf[0][2] + b_v) / 2;
1050 break;
1052 buf[0][0] = g_u;
1053 buf[0][2] = b_v;
1054 break;
1055 case V4L2_PIX_FMT_YVYU:
1056 buf[0][offset] = r_y;
1057 if (odd) {
1058 buf[0][1] = (buf[0][1] + b_v) / 2;
1059 buf[0][3] = (buf[0][3] + g_u) / 2;
1060 break;
1062 buf[0][1] = b_v;
1063 buf[0][3] = g_u;
1064 break;
1065 case V4L2_PIX_FMT_VYUY:
1066 buf[0][offset + 1] = r_y;
1067 if (odd) {
1068 buf[0][0] = (buf[0][0] + b_v) / 2;
1069 buf[0][2] = (buf[0][2] + g_u) / 2;
1070 break;
1072 buf[0][0] = b_v;
1073 buf[0][2] = g_u;
1074 break;
1075 case V4L2_PIX_FMT_RGB332:
1076 buf[0][offset] = (r_y << 5) | (g_u << 2) | b_v;
1077 break;
1078 case V4L2_PIX_FMT_YUV565:
1079 case V4L2_PIX_FMT_RGB565:
1080 buf[0][offset] = (g_u << 5) | b_v;
1081 buf[0][offset + 1] = (r_y << 3) | (g_u >> 3);
1082 break;
1083 case V4L2_PIX_FMT_RGB565X:
1084 buf[0][offset] = (r_y << 3) | (g_u >> 3);
1085 buf[0][offset + 1] = (g_u << 5) | b_v;
1086 break;
1087 case V4L2_PIX_FMT_RGB444:
1088 case V4L2_PIX_FMT_XRGB444:
1089 alpha = 0;
1090 /* fall through */
1091 case V4L2_PIX_FMT_YUV444:
1092 case V4L2_PIX_FMT_ARGB444:
1093 buf[0][offset] = (g_u << 4) | b_v;
1094 buf[0][offset + 1] = (alpha & 0xf0) | r_y;
1095 break;
1096 case V4L2_PIX_FMT_RGB555:
1097 case V4L2_PIX_FMT_XRGB555:
1098 alpha = 0;
1099 /* fall through */
1100 case V4L2_PIX_FMT_YUV555:
1101 case V4L2_PIX_FMT_ARGB555:
1102 buf[0][offset] = (g_u << 5) | b_v;
1103 buf[0][offset + 1] = (alpha & 0x80) | (r_y << 2) | (g_u >> 3);
1104 break;
1105 case V4L2_PIX_FMT_RGB555X:
1106 case V4L2_PIX_FMT_XRGB555X:
1107 alpha = 0;
1108 /* fall through */
1109 case V4L2_PIX_FMT_ARGB555X:
1110 buf[0][offset] = (alpha & 0x80) | (r_y << 2) | (g_u >> 3);
1111 buf[0][offset + 1] = (g_u << 5) | b_v;
1112 break;
1113 case V4L2_PIX_FMT_RGB24:
1114 buf[0][offset] = r_y;
1115 buf[0][offset + 1] = g_u;
1116 buf[0][offset + 2] = b_v;
1117 break;
1118 case V4L2_PIX_FMT_BGR24:
1119 buf[0][offset] = b_v;
1120 buf[0][offset + 1] = g_u;
1121 buf[0][offset + 2] = r_y;
1122 break;
1123 case V4L2_PIX_FMT_BGR666:
1124 buf[0][offset] = (b_v << 2) | (g_u >> 4);
1125 buf[0][offset + 1] = (g_u << 4) | (r_y >> 2);
1126 buf[0][offset + 2] = r_y << 6;
1127 buf[0][offset + 3] = 0;
1128 break;
1129 case V4L2_PIX_FMT_RGB32:
1130 case V4L2_PIX_FMT_XRGB32:
1131 alpha = 0;
1132 /* fall through */
1133 case V4L2_PIX_FMT_YUV32:
1134 case V4L2_PIX_FMT_ARGB32:
1135 buf[0][offset] = alpha;
1136 buf[0][offset + 1] = r_y;
1137 buf[0][offset + 2] = g_u;
1138 buf[0][offset + 3] = b_v;
1139 break;
1140 case V4L2_PIX_FMT_BGR32:
1141 case V4L2_PIX_FMT_XBGR32:
1142 alpha = 0;
1143 /* fall through */
1144 case V4L2_PIX_FMT_ABGR32:
1145 buf[0][offset] = b_v;
1146 buf[0][offset + 1] = g_u;
1147 buf[0][offset + 2] = r_y;
1148 buf[0][offset + 3] = alpha;
1149 break;
1150 case V4L2_PIX_FMT_SBGGR8:
1151 buf[0][offset] = odd ? g_u : b_v;
1152 buf[1][offset] = odd ? r_y : g_u;
1153 break;
1154 case V4L2_PIX_FMT_SGBRG8:
1155 buf[0][offset] = odd ? b_v : g_u;
1156 buf[1][offset] = odd ? g_u : r_y;
1157 break;
1158 case V4L2_PIX_FMT_SGRBG8:
1159 buf[0][offset] = odd ? r_y : g_u;
1160 buf[1][offset] = odd ? g_u : b_v;
1161 break;
1162 case V4L2_PIX_FMT_SRGGB8:
1163 buf[0][offset] = odd ? g_u : r_y;
1164 buf[1][offset] = odd ? b_v : g_u;
1165 break;
1166 case V4L2_PIX_FMT_SBGGR10:
1167 buf[0][offset] = odd ? g_u << 2 : b_v << 2;
1168 buf[0][offset + 1] = odd ? g_u >> 6 : b_v >> 6;
1169 buf[1][offset] = odd ? r_y << 2 : g_u << 2;
1170 buf[1][offset + 1] = odd ? r_y >> 6 : g_u >> 6;
1171 buf[0][offset] |= (buf[0][offset] >> 2) & 3;
1172 buf[1][offset] |= (buf[1][offset] >> 2) & 3;
1173 break;
1174 case V4L2_PIX_FMT_SGBRG10:
1175 buf[0][offset] = odd ? b_v << 2 : g_u << 2;
1176 buf[0][offset + 1] = odd ? b_v >> 6 : g_u >> 6;
1177 buf[1][offset] = odd ? g_u << 2 : r_y << 2;
1178 buf[1][offset + 1] = odd ? g_u >> 6 : r_y >> 6;
1179 buf[0][offset] |= (buf[0][offset] >> 2) & 3;
1180 buf[1][offset] |= (buf[1][offset] >> 2) & 3;
1181 break;
1182 case V4L2_PIX_FMT_SGRBG10:
1183 buf[0][offset] = odd ? r_y << 2 : g_u << 2;
1184 buf[0][offset + 1] = odd ? r_y >> 6 : g_u >> 6;
1185 buf[1][offset] = odd ? g_u << 2 : b_v << 2;
1186 buf[1][offset + 1] = odd ? g_u >> 6 : b_v >> 6;
1187 buf[0][offset] |= (buf[0][offset] >> 2) & 3;
1188 buf[1][offset] |= (buf[1][offset] >> 2) & 3;
1189 break;
1190 case V4L2_PIX_FMT_SRGGB10:
1191 buf[0][offset] = odd ? g_u << 2 : r_y << 2;
1192 buf[0][offset + 1] = odd ? g_u >> 6 : r_y >> 6;
1193 buf[1][offset] = odd ? b_v << 2 : g_u << 2;
1194 buf[1][offset + 1] = odd ? b_v >> 6 : g_u >> 6;
1195 buf[0][offset] |= (buf[0][offset] >> 2) & 3;
1196 buf[1][offset] |= (buf[1][offset] >> 2) & 3;
1197 break;
1198 case V4L2_PIX_FMT_SBGGR12:
1199 buf[0][offset] = odd ? g_u << 4 : b_v << 4;
1200 buf[0][offset + 1] = odd ? g_u >> 4 : b_v >> 4;
1201 buf[1][offset] = odd ? r_y << 4 : g_u << 4;
1202 buf[1][offset + 1] = odd ? r_y >> 4 : g_u >> 4;
1203 buf[0][offset] |= (buf[0][offset] >> 4) & 0xf;
1204 buf[1][offset] |= (buf[1][offset] >> 4) & 0xf;
1205 break;
1206 case V4L2_PIX_FMT_SGBRG12:
1207 buf[0][offset] = odd ? b_v << 4 : g_u << 4;
1208 buf[0][offset + 1] = odd ? b_v >> 4 : g_u >> 4;
1209 buf[1][offset] = odd ? g_u << 4 : r_y << 4;
1210 buf[1][offset + 1] = odd ? g_u >> 4 : r_y >> 4;
1211 buf[0][offset] |= (buf[0][offset] >> 4) & 0xf;
1212 buf[1][offset] |= (buf[1][offset] >> 4) & 0xf;
1213 break;
1214 case V4L2_PIX_FMT_SGRBG12:
1215 buf[0][offset] = odd ? r_y << 4 : g_u << 4;
1216 buf[0][offset + 1] = odd ? r_y >> 4 : g_u >> 4;
1217 buf[1][offset] = odd ? g_u << 4 : b_v << 4;
1218 buf[1][offset + 1] = odd ? g_u >> 4 : b_v >> 4;
1219 buf[0][offset] |= (buf[0][offset] >> 4) & 0xf;
1220 buf[1][offset] |= (buf[1][offset] >> 4) & 0xf;
1221 break;
1222 case V4L2_PIX_FMT_SRGGB12:
1223 buf[0][offset] = odd ? g_u << 4 : r_y << 4;
1224 buf[0][offset + 1] = odd ? g_u >> 4 : r_y >> 4;
1225 buf[1][offset] = odd ? b_v << 4 : g_u << 4;
1226 buf[1][offset + 1] = odd ? b_v >> 4 : g_u >> 4;
1227 buf[0][offset] |= (buf[0][offset] >> 4) & 0xf;
1228 buf[1][offset] |= (buf[1][offset] >> 4) & 0xf;
1229 break;
1233 unsigned tpg_g_interleaved_plane(const struct tpg_data *tpg, unsigned buf_line)
1235 switch (tpg->fourcc) {
1236 case V4L2_PIX_FMT_SBGGR8:
1237 case V4L2_PIX_FMT_SGBRG8:
1238 case V4L2_PIX_FMT_SGRBG8:
1239 case V4L2_PIX_FMT_SRGGB8:
1240 case V4L2_PIX_FMT_SBGGR10:
1241 case V4L2_PIX_FMT_SGBRG10:
1242 case V4L2_PIX_FMT_SGRBG10:
1243 case V4L2_PIX_FMT_SRGGB10:
1244 case V4L2_PIX_FMT_SBGGR12:
1245 case V4L2_PIX_FMT_SGBRG12:
1246 case V4L2_PIX_FMT_SGRBG12:
1247 case V4L2_PIX_FMT_SRGGB12:
1248 return buf_line & 1;
1249 default:
1250 return 0;
1254 /* Return how many pattern lines are used by the current pattern. */
1255 static unsigned tpg_get_pat_lines(const struct tpg_data *tpg)
1257 switch (tpg->pattern) {
1258 case TPG_PAT_CHECKERS_16X16:
1259 case TPG_PAT_CHECKERS_2X2:
1260 case TPG_PAT_CHECKERS_1X1:
1261 case TPG_PAT_COLOR_CHECKERS_2X2:
1262 case TPG_PAT_COLOR_CHECKERS_1X1:
1263 case TPG_PAT_ALTERNATING_HLINES:
1264 case TPG_PAT_CROSS_1_PIXEL:
1265 case TPG_PAT_CROSS_2_PIXELS:
1266 case TPG_PAT_CROSS_10_PIXELS:
1267 return 2;
1268 case TPG_PAT_100_COLORSQUARES:
1269 case TPG_PAT_100_HCOLORBAR:
1270 return 8;
1271 default:
1272 return 1;
1276 /* Which pattern line should be used for the given frame line. */
1277 static unsigned tpg_get_pat_line(const struct tpg_data *tpg, unsigned line)
1279 switch (tpg->pattern) {
1280 case TPG_PAT_CHECKERS_16X16:
1281 return (line >> 4) & 1;
1282 case TPG_PAT_CHECKERS_1X1:
1283 case TPG_PAT_COLOR_CHECKERS_1X1:
1284 case TPG_PAT_ALTERNATING_HLINES:
1285 return line & 1;
1286 case TPG_PAT_CHECKERS_2X2:
1287 case TPG_PAT_COLOR_CHECKERS_2X2:
1288 return (line & 2) >> 1;
1289 case TPG_PAT_100_COLORSQUARES:
1290 case TPG_PAT_100_HCOLORBAR:
1291 return (line * 8) / tpg->src_height;
1292 case TPG_PAT_CROSS_1_PIXEL:
1293 return line == tpg->src_height / 2;
1294 case TPG_PAT_CROSS_2_PIXELS:
1295 return (line + 1) / 2 == tpg->src_height / 4;
1296 case TPG_PAT_CROSS_10_PIXELS:
1297 return (line + 10) / 20 == tpg->src_height / 40;
1298 default:
1299 return 0;
1304 * Which color should be used for the given pattern line and X coordinate.
1305 * Note: x is in the range 0 to 2 * tpg->src_width.
1307 static enum tpg_color tpg_get_color(const struct tpg_data *tpg,
1308 unsigned pat_line, unsigned x)
1310 /* Maximum number of bars are TPG_COLOR_MAX - otherwise, the input print code
1311 should be modified */
1312 static const enum tpg_color bars[3][8] = {
1313 /* Standard ITU-R 75% color bar sequence */
1314 { TPG_COLOR_CSC_WHITE, TPG_COLOR_75_YELLOW,
1315 TPG_COLOR_75_CYAN, TPG_COLOR_75_GREEN,
1316 TPG_COLOR_75_MAGENTA, TPG_COLOR_75_RED,
1317 TPG_COLOR_75_BLUE, TPG_COLOR_100_BLACK, },
1318 /* Standard ITU-R 100% color bar sequence */
1319 { TPG_COLOR_100_WHITE, TPG_COLOR_100_YELLOW,
1320 TPG_COLOR_100_CYAN, TPG_COLOR_100_GREEN,
1321 TPG_COLOR_100_MAGENTA, TPG_COLOR_100_RED,
1322 TPG_COLOR_100_BLUE, TPG_COLOR_100_BLACK, },
1323 /* Color bar sequence suitable to test CSC */
1324 { TPG_COLOR_CSC_WHITE, TPG_COLOR_CSC_YELLOW,
1325 TPG_COLOR_CSC_CYAN, TPG_COLOR_CSC_GREEN,
1326 TPG_COLOR_CSC_MAGENTA, TPG_COLOR_CSC_RED,
1327 TPG_COLOR_CSC_BLUE, TPG_COLOR_CSC_BLACK, },
1330 switch (tpg->pattern) {
1331 case TPG_PAT_75_COLORBAR:
1332 case TPG_PAT_100_COLORBAR:
1333 case TPG_PAT_CSC_COLORBAR:
1334 return bars[tpg->pattern][((x * 8) / tpg->src_width) % 8];
1335 case TPG_PAT_100_COLORSQUARES:
1336 return bars[1][(pat_line + (x * 8) / tpg->src_width) % 8];
1337 case TPG_PAT_100_HCOLORBAR:
1338 return bars[1][pat_line];
1339 case TPG_PAT_BLACK:
1340 return TPG_COLOR_100_BLACK;
1341 case TPG_PAT_WHITE:
1342 return TPG_COLOR_100_WHITE;
1343 case TPG_PAT_RED:
1344 return TPG_COLOR_100_RED;
1345 case TPG_PAT_GREEN:
1346 return TPG_COLOR_100_GREEN;
1347 case TPG_PAT_BLUE:
1348 return TPG_COLOR_100_BLUE;
1349 case TPG_PAT_CHECKERS_16X16:
1350 return (((x >> 4) & 1) ^ (pat_line & 1)) ?
1351 TPG_COLOR_100_BLACK : TPG_COLOR_100_WHITE;
1352 case TPG_PAT_CHECKERS_1X1:
1353 return ((x & 1) ^ (pat_line & 1)) ?
1354 TPG_COLOR_100_WHITE : TPG_COLOR_100_BLACK;
1355 case TPG_PAT_COLOR_CHECKERS_1X1:
1356 return ((x & 1) ^ (pat_line & 1)) ?
1357 TPG_COLOR_100_RED : TPG_COLOR_100_BLUE;
1358 case TPG_PAT_CHECKERS_2X2:
1359 return (((x >> 1) & 1) ^ (pat_line & 1)) ?
1360 TPG_COLOR_100_WHITE : TPG_COLOR_100_BLACK;
1361 case TPG_PAT_COLOR_CHECKERS_2X2:
1362 return (((x >> 1) & 1) ^ (pat_line & 1)) ?
1363 TPG_COLOR_100_RED : TPG_COLOR_100_BLUE;
1364 case TPG_PAT_ALTERNATING_HLINES:
1365 return pat_line ? TPG_COLOR_100_WHITE : TPG_COLOR_100_BLACK;
1366 case TPG_PAT_ALTERNATING_VLINES:
1367 return (x & 1) ? TPG_COLOR_100_WHITE : TPG_COLOR_100_BLACK;
1368 case TPG_PAT_CROSS_1_PIXEL:
1369 if (pat_line || (x % tpg->src_width) == tpg->src_width / 2)
1370 return TPG_COLOR_100_BLACK;
1371 return TPG_COLOR_100_WHITE;
1372 case TPG_PAT_CROSS_2_PIXELS:
1373 if (pat_line || ((x % tpg->src_width) + 1) / 2 == tpg->src_width / 4)
1374 return TPG_COLOR_100_BLACK;
1375 return TPG_COLOR_100_WHITE;
1376 case TPG_PAT_CROSS_10_PIXELS:
1377 if (pat_line || ((x % tpg->src_width) + 10) / 20 == tpg->src_width / 40)
1378 return TPG_COLOR_100_BLACK;
1379 return TPG_COLOR_100_WHITE;
1380 case TPG_PAT_GRAY_RAMP:
1381 return TPG_COLOR_RAMP + ((x % tpg->src_width) * 256) / tpg->src_width;
1382 default:
1383 return TPG_COLOR_100_RED;
1388 * Given the pixel aspect ratio and video aspect ratio calculate the
1389 * coordinates of a centered square and the coordinates of the border of
1390 * the active video area. The coordinates are relative to the source
1391 * frame rectangle.
1393 static void tpg_calculate_square_border(struct tpg_data *tpg)
1395 unsigned w = tpg->src_width;
1396 unsigned h = tpg->src_height;
1397 unsigned sq_w, sq_h;
1399 sq_w = (w * 2 / 5) & ~1;
1400 if (((w - sq_w) / 2) & 1)
1401 sq_w += 2;
1402 sq_h = sq_w;
1403 tpg->square.width = sq_w;
1404 if (tpg->vid_aspect == TPG_VIDEO_ASPECT_16X9_ANAMORPHIC) {
1405 unsigned ana_sq_w = (sq_w / 4) * 3;
1407 if (((w - ana_sq_w) / 2) & 1)
1408 ana_sq_w += 2;
1409 tpg->square.width = ana_sq_w;
1411 tpg->square.left = (w - tpg->square.width) / 2;
1412 if (tpg->pix_aspect == TPG_PIXEL_ASPECT_NTSC)
1413 sq_h = sq_w * 10 / 11;
1414 else if (tpg->pix_aspect == TPG_PIXEL_ASPECT_PAL)
1415 sq_h = sq_w * 59 / 54;
1416 tpg->square.height = sq_h;
1417 tpg->square.top = (h - sq_h) / 2;
1418 tpg->border.left = 0;
1419 tpg->border.width = w;
1420 tpg->border.top = 0;
1421 tpg->border.height = h;
1422 switch (tpg->vid_aspect) {
1423 case TPG_VIDEO_ASPECT_4X3:
1424 if (tpg->pix_aspect)
1425 return;
1426 if (3 * w >= 4 * h) {
1427 tpg->border.width = ((4 * h) / 3) & ~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;
1433 tpg->border.height = ((3 * w) / 4) & ~1;
1434 tpg->border.top = (h - tpg->border.height) / 2;
1435 break;
1436 case TPG_VIDEO_ASPECT_14X9_CENTRE:
1437 if (tpg->pix_aspect) {
1438 tpg->border.height = tpg->pix_aspect == TPG_PIXEL_ASPECT_NTSC ? 420 : 506;
1439 tpg->border.top = (h - tpg->border.height) / 2;
1440 break;
1442 if (9 * w >= 14 * h) {
1443 tpg->border.width = ((14 * h) / 9) & ~1;
1444 if (((w - tpg->border.width) / 2) & ~1)
1445 tpg->border.width -= 2;
1446 tpg->border.left = (w - tpg->border.width) / 2;
1447 break;
1449 tpg->border.height = ((9 * w) / 14) & ~1;
1450 tpg->border.top = (h - tpg->border.height) / 2;
1451 break;
1452 case TPG_VIDEO_ASPECT_16X9_CENTRE:
1453 if (tpg->pix_aspect) {
1454 tpg->border.height = tpg->pix_aspect == TPG_PIXEL_ASPECT_NTSC ? 368 : 442;
1455 tpg->border.top = (h - tpg->border.height) / 2;
1456 break;
1458 if (9 * w >= 16 * h) {
1459 tpg->border.width = ((16 * h) / 9) & ~1;
1460 if (((w - tpg->border.width) / 2) & ~1)
1461 tpg->border.width -= 2;
1462 tpg->border.left = (w - tpg->border.width) / 2;
1463 break;
1465 tpg->border.height = ((9 * w) / 16) & ~1;
1466 tpg->border.top = (h - tpg->border.height) / 2;
1467 break;
1468 default:
1469 break;
1473 static void tpg_precalculate_line(struct tpg_data *tpg)
1475 enum tpg_color contrast;
1476 u8 pix[TPG_MAX_PLANES][8];
1477 unsigned pat;
1478 unsigned p;
1479 unsigned x;
1481 switch (tpg->pattern) {
1482 case TPG_PAT_GREEN:
1483 contrast = TPG_COLOR_100_RED;
1484 break;
1485 case TPG_PAT_CSC_COLORBAR:
1486 contrast = TPG_COLOR_CSC_GREEN;
1487 break;
1488 default:
1489 contrast = TPG_COLOR_100_GREEN;
1490 break;
1493 for (pat = 0; pat < tpg_get_pat_lines(tpg); pat++) {
1494 /* Coarse scaling with Bresenham */
1495 unsigned int_part = tpg->src_width / tpg->scaled_width;
1496 unsigned fract_part = tpg->src_width % tpg->scaled_width;
1497 unsigned src_x = 0;
1498 unsigned error = 0;
1500 for (x = 0; x < tpg->scaled_width * 2; x += 2) {
1501 unsigned real_x = src_x;
1502 enum tpg_color color1, color2;
1504 real_x = tpg->hflip ? tpg->src_width * 2 - real_x - 2 : real_x;
1505 color1 = tpg_get_color(tpg, pat, real_x);
1507 src_x += int_part;
1508 error += fract_part;
1509 if (error >= tpg->scaled_width) {
1510 error -= tpg->scaled_width;
1511 src_x++;
1514 real_x = src_x;
1515 real_x = tpg->hflip ? tpg->src_width * 2 - real_x - 2 : real_x;
1516 color2 = tpg_get_color(tpg, pat, real_x);
1518 src_x += int_part;
1519 error += fract_part;
1520 if (error >= tpg->scaled_width) {
1521 error -= tpg->scaled_width;
1522 src_x++;
1525 gen_twopix(tpg, pix, tpg->hflip ? color2 : color1, 0);
1526 gen_twopix(tpg, pix, tpg->hflip ? color1 : color2, 1);
1527 for (p = 0; p < tpg->planes; p++) {
1528 unsigned twopixsize = tpg->twopixelsize[p];
1529 unsigned hdiv = tpg->hdownsampling[p];
1530 u8 *pos = tpg->lines[pat][p] + tpg_hdiv(tpg, p, x);
1532 memcpy(pos, pix[p], twopixsize / hdiv);
1537 if (tpg->vdownsampling[tpg->planes - 1] > 1) {
1538 unsigned pat_lines = tpg_get_pat_lines(tpg);
1540 for (pat = 0; pat < pat_lines; pat++) {
1541 unsigned next_pat = (pat + 1) % pat_lines;
1543 for (p = 1; p < tpg->planes; p++) {
1544 unsigned w = tpg_hdiv(tpg, p, tpg->scaled_width * 2);
1545 u8 *pos1 = tpg->lines[pat][p];
1546 u8 *pos2 = tpg->lines[next_pat][p];
1547 u8 *dest = tpg->downsampled_lines[pat][p];
1549 for (x = 0; x < w; x++, pos1++, pos2++, dest++)
1550 *dest = ((u16)*pos1 + (u16)*pos2) / 2;
1555 gen_twopix(tpg, pix, contrast, 0);
1556 gen_twopix(tpg, pix, contrast, 1);
1557 for (p = 0; p < tpg->planes; p++) {
1558 unsigned twopixsize = tpg->twopixelsize[p];
1559 u8 *pos = tpg->contrast_line[p];
1561 for (x = 0; x < tpg->scaled_width; x += 2, pos += twopixsize)
1562 memcpy(pos, pix[p], twopixsize);
1565 gen_twopix(tpg, pix, TPG_COLOR_100_BLACK, 0);
1566 gen_twopix(tpg, pix, TPG_COLOR_100_BLACK, 1);
1567 for (p = 0; p < tpg->planes; p++) {
1568 unsigned twopixsize = tpg->twopixelsize[p];
1569 u8 *pos = tpg->black_line[p];
1571 for (x = 0; x < tpg->scaled_width; x += 2, pos += twopixsize)
1572 memcpy(pos, pix[p], twopixsize);
1575 for (x = 0; x < tpg->scaled_width * 2; x += 2) {
1576 gen_twopix(tpg, pix, TPG_COLOR_RANDOM, 0);
1577 gen_twopix(tpg, pix, TPG_COLOR_RANDOM, 1);
1578 for (p = 0; p < tpg->planes; p++) {
1579 unsigned twopixsize = tpg->twopixelsize[p];
1580 u8 *pos = tpg->random_line[p] + x * twopixsize / 2;
1582 memcpy(pos, pix[p], twopixsize);
1586 gen_twopix(tpg, tpg->textbg, TPG_COLOR_TEXTBG, 0);
1587 gen_twopix(tpg, tpg->textbg, TPG_COLOR_TEXTBG, 1);
1588 gen_twopix(tpg, tpg->textfg, TPG_COLOR_TEXTFG, 0);
1589 gen_twopix(tpg, tpg->textfg, TPG_COLOR_TEXTFG, 1);
1592 /* need this to do rgb24 rendering */
1593 typedef struct { u16 __; u8 _; } __packed x24;
1595 #define PRINTSTR(PIXTYPE) do { \
1596 unsigned vdiv = tpg->vdownsampling[p]; \
1597 unsigned hdiv = tpg->hdownsampling[p]; \
1598 int line; \
1599 PIXTYPE fg; \
1600 PIXTYPE bg; \
1601 memcpy(&fg, tpg->textfg[p], sizeof(PIXTYPE)); \
1602 memcpy(&bg, tpg->textbg[p], sizeof(PIXTYPE)); \
1604 for (line = first; line < 16; line += vdiv * step) { \
1605 int l = tpg->vflip ? 15 - line : line; \
1606 PIXTYPE *pos = (PIXTYPE *)(basep[p][(line / vdiv) & 1] + \
1607 ((y * step + l) / (vdiv * div)) * tpg->bytesperline[p] + \
1608 (x / hdiv) * sizeof(PIXTYPE)); \
1609 unsigned s; \
1611 for (s = 0; s < len; s++) { \
1612 u8 chr = font8x16[text[s] * 16 + line]; \
1614 if (hdiv == 2 && tpg->hflip) { \
1615 pos[3] = (chr & (0x01 << 6) ? fg : bg); \
1616 pos[2] = (chr & (0x01 << 4) ? fg : bg); \
1617 pos[1] = (chr & (0x01 << 2) ? fg : bg); \
1618 pos[0] = (chr & (0x01 << 0) ? fg : bg); \
1619 } else if (hdiv == 2) { \
1620 pos[0] = (chr & (0x01 << 7) ? fg : bg); \
1621 pos[1] = (chr & (0x01 << 5) ? fg : bg); \
1622 pos[2] = (chr & (0x01 << 3) ? fg : bg); \
1623 pos[3] = (chr & (0x01 << 1) ? fg : bg); \
1624 } else if (tpg->hflip) { \
1625 pos[7] = (chr & (0x01 << 7) ? fg : bg); \
1626 pos[6] = (chr & (0x01 << 6) ? fg : bg); \
1627 pos[5] = (chr & (0x01 << 5) ? fg : bg); \
1628 pos[4] = (chr & (0x01 << 4) ? fg : bg); \
1629 pos[3] = (chr & (0x01 << 3) ? fg : bg); \
1630 pos[2] = (chr & (0x01 << 2) ? fg : bg); \
1631 pos[1] = (chr & (0x01 << 1) ? fg : bg); \
1632 pos[0] = (chr & (0x01 << 0) ? fg : bg); \
1633 } else { \
1634 pos[0] = (chr & (0x01 << 7) ? fg : bg); \
1635 pos[1] = (chr & (0x01 << 6) ? fg : bg); \
1636 pos[2] = (chr & (0x01 << 5) ? fg : bg); \
1637 pos[3] = (chr & (0x01 << 4) ? fg : bg); \
1638 pos[4] = (chr & (0x01 << 3) ? fg : bg); \
1639 pos[5] = (chr & (0x01 << 2) ? fg : bg); \
1640 pos[6] = (chr & (0x01 << 1) ? fg : bg); \
1641 pos[7] = (chr & (0x01 << 0) ? fg : bg); \
1644 pos += (tpg->hflip ? -8 : 8) / hdiv; \
1647 } while (0)
1649 static noinline void tpg_print_str_2(const struct tpg_data *tpg, u8 *basep[TPG_MAX_PLANES][2],
1650 unsigned p, unsigned first, unsigned div, unsigned step,
1651 int y, int x, char *text, unsigned len)
1653 PRINTSTR(u8);
1656 static noinline void tpg_print_str_4(const struct tpg_data *tpg, u8 *basep[TPG_MAX_PLANES][2],
1657 unsigned p, unsigned first, unsigned div, unsigned step,
1658 int y, int x, char *text, unsigned len)
1660 PRINTSTR(u16);
1663 static noinline void tpg_print_str_6(const struct tpg_data *tpg, u8 *basep[TPG_MAX_PLANES][2],
1664 unsigned p, unsigned first, unsigned div, unsigned step,
1665 int y, int x, char *text, unsigned len)
1667 PRINTSTR(x24);
1670 static noinline void tpg_print_str_8(const struct tpg_data *tpg, u8 *basep[TPG_MAX_PLANES][2],
1671 unsigned p, unsigned first, unsigned div, unsigned step,
1672 int y, int x, char *text, unsigned len)
1674 PRINTSTR(u32);
1677 void tpg_gen_text(const struct tpg_data *tpg, u8 *basep[TPG_MAX_PLANES][2],
1678 int y, int x, char *text)
1680 unsigned step = V4L2_FIELD_HAS_T_OR_B(tpg->field) ? 2 : 1;
1681 unsigned div = step;
1682 unsigned first = 0;
1683 unsigned len = strlen(text);
1684 unsigned p;
1686 if (font8x16 == NULL || basep == NULL)
1687 return;
1689 /* Checks if it is possible to show string */
1690 if (y + 16 >= tpg->compose.height || x + 8 >= tpg->compose.width)
1691 return;
1693 if (len > (tpg->compose.width - x) / 8)
1694 len = (tpg->compose.width - x) / 8;
1695 if (tpg->vflip)
1696 y = tpg->compose.height - y - 16;
1697 if (tpg->hflip)
1698 x = tpg->compose.width - x - 8;
1699 y += tpg->compose.top;
1700 x += tpg->compose.left;
1701 if (tpg->field == V4L2_FIELD_BOTTOM)
1702 first = 1;
1703 else if (tpg->field == V4L2_FIELD_SEQ_TB || tpg->field == V4L2_FIELD_SEQ_BT)
1704 div = 2;
1706 for (p = 0; p < tpg->planes; p++) {
1707 /* Print text */
1708 switch (tpg->twopixelsize[p]) {
1709 case 2:
1710 tpg_print_str_2(tpg, basep, p, first, div, step, y, x,
1711 text, len);
1712 break;
1713 case 4:
1714 tpg_print_str_4(tpg, basep, p, first, div, step, y, x,
1715 text, len);
1716 break;
1717 case 6:
1718 tpg_print_str_6(tpg, basep, p, first, div, step, y, x,
1719 text, len);
1720 break;
1721 case 8:
1722 tpg_print_str_8(tpg, basep, p, first, div, step, y, x,
1723 text, len);
1724 break;
1729 void tpg_update_mv_step(struct tpg_data *tpg)
1731 int factor = tpg->mv_hor_mode > TPG_MOVE_NONE ? -1 : 1;
1733 if (tpg->hflip)
1734 factor = -factor;
1735 switch (tpg->mv_hor_mode) {
1736 case TPG_MOVE_NEG_FAST:
1737 case TPG_MOVE_POS_FAST:
1738 tpg->mv_hor_step = ((tpg->src_width + 319) / 320) * 4;
1739 break;
1740 case TPG_MOVE_NEG:
1741 case TPG_MOVE_POS:
1742 tpg->mv_hor_step = ((tpg->src_width + 639) / 640) * 4;
1743 break;
1744 case TPG_MOVE_NEG_SLOW:
1745 case TPG_MOVE_POS_SLOW:
1746 tpg->mv_hor_step = 2;
1747 break;
1748 case TPG_MOVE_NONE:
1749 tpg->mv_hor_step = 0;
1750 break;
1752 if (factor < 0)
1753 tpg->mv_hor_step = tpg->src_width - tpg->mv_hor_step;
1755 factor = tpg->mv_vert_mode > TPG_MOVE_NONE ? -1 : 1;
1756 switch (tpg->mv_vert_mode) {
1757 case TPG_MOVE_NEG_FAST:
1758 case TPG_MOVE_POS_FAST:
1759 tpg->mv_vert_step = ((tpg->src_width + 319) / 320) * 4;
1760 break;
1761 case TPG_MOVE_NEG:
1762 case TPG_MOVE_POS:
1763 tpg->mv_vert_step = ((tpg->src_width + 639) / 640) * 4;
1764 break;
1765 case TPG_MOVE_NEG_SLOW:
1766 case TPG_MOVE_POS_SLOW:
1767 tpg->mv_vert_step = 1;
1768 break;
1769 case TPG_MOVE_NONE:
1770 tpg->mv_vert_step = 0;
1771 break;
1773 if (factor < 0)
1774 tpg->mv_vert_step = tpg->src_height - tpg->mv_vert_step;
1777 /* Map the line number relative to the crop rectangle to a frame line number */
1778 static unsigned tpg_calc_frameline(const struct tpg_data *tpg, unsigned src_y,
1779 unsigned field)
1781 switch (field) {
1782 case V4L2_FIELD_TOP:
1783 return tpg->crop.top + src_y * 2;
1784 case V4L2_FIELD_BOTTOM:
1785 return tpg->crop.top + src_y * 2 + 1;
1786 default:
1787 return src_y + tpg->crop.top;
1792 * Map the line number relative to the compose rectangle to a destination
1793 * buffer line number.
1795 static unsigned tpg_calc_buffer_line(const struct tpg_data *tpg, unsigned y,
1796 unsigned field)
1798 y += tpg->compose.top;
1799 switch (field) {
1800 case V4L2_FIELD_SEQ_TB:
1801 if (y & 1)
1802 return tpg->buf_height / 2 + y / 2;
1803 return y / 2;
1804 case V4L2_FIELD_SEQ_BT:
1805 if (y & 1)
1806 return y / 2;
1807 return tpg->buf_height / 2 + y / 2;
1808 default:
1809 return y;
1813 static void tpg_recalc(struct tpg_data *tpg)
1815 if (tpg->recalc_colors) {
1816 tpg->recalc_colors = false;
1817 tpg->recalc_lines = true;
1818 tpg->real_xfer_func = tpg->xfer_func;
1819 tpg->real_ycbcr_enc = tpg->ycbcr_enc;
1820 tpg->real_quantization = tpg->quantization;
1822 if (tpg->xfer_func == V4L2_XFER_FUNC_DEFAULT)
1823 tpg->real_xfer_func =
1824 V4L2_MAP_XFER_FUNC_DEFAULT(tpg->colorspace);
1826 if (tpg->ycbcr_enc == V4L2_YCBCR_ENC_DEFAULT)
1827 tpg->real_ycbcr_enc =
1828 V4L2_MAP_YCBCR_ENC_DEFAULT(tpg->colorspace);
1830 if (tpg->quantization == V4L2_QUANTIZATION_DEFAULT)
1831 tpg->real_quantization =
1832 V4L2_MAP_QUANTIZATION_DEFAULT(!tpg->is_yuv,
1833 tpg->colorspace, tpg->real_ycbcr_enc);
1835 tpg_precalculate_colors(tpg);
1837 if (tpg->recalc_square_border) {
1838 tpg->recalc_square_border = false;
1839 tpg_calculate_square_border(tpg);
1841 if (tpg->recalc_lines) {
1842 tpg->recalc_lines = false;
1843 tpg_precalculate_line(tpg);
1847 void tpg_calc_text_basep(struct tpg_data *tpg,
1848 u8 *basep[TPG_MAX_PLANES][2], unsigned p, u8 *vbuf)
1850 unsigned stride = tpg->bytesperline[p];
1851 unsigned h = tpg->buf_height;
1853 tpg_recalc(tpg);
1855 basep[p][0] = vbuf;
1856 basep[p][1] = vbuf;
1857 h /= tpg->vdownsampling[p];
1858 if (tpg->field == V4L2_FIELD_SEQ_TB)
1859 basep[p][1] += h * stride / 2;
1860 else if (tpg->field == V4L2_FIELD_SEQ_BT)
1861 basep[p][0] += h * stride / 2;
1862 if (p == 0 && tpg->interleaved)
1863 tpg_calc_text_basep(tpg, basep, 1, vbuf);
1866 static int tpg_pattern_avg(const struct tpg_data *tpg,
1867 unsigned pat1, unsigned pat2)
1869 unsigned pat_lines = tpg_get_pat_lines(tpg);
1871 if (pat1 == (pat2 + 1) % pat_lines)
1872 return pat2;
1873 if (pat2 == (pat1 + 1) % pat_lines)
1874 return pat1;
1875 return -1;
1878 void tpg_log_status(struct tpg_data *tpg)
1880 pr_info("tpg source WxH: %ux%u (%s)\n",
1881 tpg->src_width, tpg->src_height,
1882 tpg->is_yuv ? "YCbCr" : "RGB");
1883 pr_info("tpg field: %u\n", tpg->field);
1884 pr_info("tpg crop: %ux%u@%dx%d\n", tpg->crop.width, tpg->crop.height,
1885 tpg->crop.left, tpg->crop.top);
1886 pr_info("tpg compose: %ux%u@%dx%d\n", tpg->compose.width, tpg->compose.height,
1887 tpg->compose.left, tpg->compose.top);
1888 pr_info("tpg colorspace: %d\n", tpg->colorspace);
1889 pr_info("tpg transfer function: %d/%d\n", tpg->xfer_func, tpg->real_xfer_func);
1890 pr_info("tpg Y'CbCr encoding: %d/%d\n", tpg->ycbcr_enc, tpg->real_ycbcr_enc);
1891 pr_info("tpg quantization: %d/%d\n", tpg->quantization, tpg->real_quantization);
1892 pr_info("tpg RGB range: %d/%d\n", tpg->rgb_range, tpg->real_rgb_range);
1896 * This struct contains common parameters used by both the drawing of the
1897 * test pattern and the drawing of the extras (borders, square, etc.)
1899 struct tpg_draw_params {
1900 /* common data */
1901 bool is_tv;
1902 bool is_60hz;
1903 unsigned twopixsize;
1904 unsigned img_width;
1905 unsigned stride;
1906 unsigned hmax;
1907 unsigned frame_line;
1908 unsigned frame_line_next;
1910 /* test pattern */
1911 unsigned mv_hor_old;
1912 unsigned mv_hor_new;
1913 unsigned mv_vert_old;
1914 unsigned mv_vert_new;
1916 /* extras */
1917 unsigned wss_width;
1918 unsigned wss_random_offset;
1919 unsigned sav_eav_f;
1920 unsigned left_pillar_width;
1921 unsigned right_pillar_start;
1924 static void tpg_fill_params_pattern(const struct tpg_data *tpg, unsigned p,
1925 struct tpg_draw_params *params)
1927 params->mv_hor_old =
1928 tpg_hscale_div(tpg, p, tpg->mv_hor_count % tpg->src_width);
1929 params->mv_hor_new =
1930 tpg_hscale_div(tpg, p, (tpg->mv_hor_count + tpg->mv_hor_step) %
1931 tpg->src_width);
1932 params->mv_vert_old = tpg->mv_vert_count % tpg->src_height;
1933 params->mv_vert_new =
1934 (tpg->mv_vert_count + tpg->mv_vert_step) % tpg->src_height;
1937 static void tpg_fill_params_extras(const struct tpg_data *tpg,
1938 unsigned p,
1939 struct tpg_draw_params *params)
1941 unsigned left_pillar_width = 0;
1942 unsigned right_pillar_start = params->img_width;
1944 params->wss_width = tpg->crop.left < tpg->src_width / 2 ?
1945 tpg->src_width / 2 - tpg->crop.left : 0;
1946 if (params->wss_width > tpg->crop.width)
1947 params->wss_width = tpg->crop.width;
1948 params->wss_width = tpg_hscale_div(tpg, p, params->wss_width);
1949 params->wss_random_offset =
1950 params->twopixsize * prandom_u32_max(tpg->src_width / 2);
1952 if (tpg->crop.left < tpg->border.left) {
1953 left_pillar_width = tpg->border.left - tpg->crop.left;
1954 if (left_pillar_width > tpg->crop.width)
1955 left_pillar_width = tpg->crop.width;
1956 left_pillar_width = tpg_hscale_div(tpg, p, left_pillar_width);
1958 params->left_pillar_width = left_pillar_width;
1960 if (tpg->crop.left + tpg->crop.width >
1961 tpg->border.left + tpg->border.width) {
1962 right_pillar_start =
1963 tpg->border.left + tpg->border.width - tpg->crop.left;
1964 right_pillar_start =
1965 tpg_hscale_div(tpg, p, right_pillar_start);
1966 if (right_pillar_start > params->img_width)
1967 right_pillar_start = params->img_width;
1969 params->right_pillar_start = right_pillar_start;
1971 params->sav_eav_f = tpg->field ==
1972 (params->is_60hz ? V4L2_FIELD_TOP : V4L2_FIELD_BOTTOM);
1975 static void tpg_fill_plane_extras(const struct tpg_data *tpg,
1976 const struct tpg_draw_params *params,
1977 unsigned p, unsigned h, u8 *vbuf)
1979 unsigned twopixsize = params->twopixsize;
1980 unsigned img_width = params->img_width;
1981 unsigned frame_line = params->frame_line;
1982 const struct v4l2_rect *sq = &tpg->square;
1983 const struct v4l2_rect *b = &tpg->border;
1984 const struct v4l2_rect *c = &tpg->crop;
1986 if (params->is_tv && !params->is_60hz &&
1987 frame_line == 0 && params->wss_width) {
1989 * Replace the first half of the top line of a 50 Hz frame
1990 * with random data to simulate a WSS signal.
1992 u8 *wss = tpg->random_line[p] + params->wss_random_offset;
1994 memcpy(vbuf, wss, params->wss_width);
1997 if (tpg->show_border && frame_line >= b->top &&
1998 frame_line < b->top + b->height) {
1999 unsigned bottom = b->top + b->height - 1;
2000 unsigned left = params->left_pillar_width;
2001 unsigned right = params->right_pillar_start;
2003 if (frame_line == b->top || frame_line == b->top + 1 ||
2004 frame_line == bottom || frame_line == bottom - 1) {
2005 memcpy(vbuf + left, tpg->contrast_line[p],
2006 right - left);
2007 } else {
2008 if (b->left >= c->left &&
2009 b->left < c->left + c->width)
2010 memcpy(vbuf + left,
2011 tpg->contrast_line[p], twopixsize);
2012 if (b->left + b->width > c->left &&
2013 b->left + b->width <= c->left + c->width)
2014 memcpy(vbuf + right - twopixsize,
2015 tpg->contrast_line[p], twopixsize);
2018 if (tpg->qual != TPG_QUAL_NOISE && frame_line >= b->top &&
2019 frame_line < b->top + b->height) {
2020 memcpy(vbuf, tpg->black_line[p], params->left_pillar_width);
2021 memcpy(vbuf + params->right_pillar_start, tpg->black_line[p],
2022 img_width - params->right_pillar_start);
2024 if (tpg->show_square && frame_line >= sq->top &&
2025 frame_line < sq->top + sq->height &&
2026 sq->left < c->left + c->width &&
2027 sq->left + sq->width >= c->left) {
2028 unsigned left = sq->left;
2029 unsigned width = sq->width;
2031 if (c->left > left) {
2032 width -= c->left - left;
2033 left = c->left;
2035 if (c->left + c->width < left + width)
2036 width -= left + width - c->left - c->width;
2037 left -= c->left;
2038 left = tpg_hscale_div(tpg, p, left);
2039 width = tpg_hscale_div(tpg, p, width);
2040 memcpy(vbuf + left, tpg->contrast_line[p], width);
2042 if (tpg->insert_sav) {
2043 unsigned offset = tpg_hdiv(tpg, p, tpg->compose.width / 3);
2044 u8 *p = vbuf + offset;
2045 unsigned vact = 0, hact = 0;
2047 p[0] = 0xff;
2048 p[1] = 0;
2049 p[2] = 0;
2050 p[3] = 0x80 | (params->sav_eav_f << 6) |
2051 (vact << 5) | (hact << 4) |
2052 ((hact ^ vact) << 3) |
2053 ((hact ^ params->sav_eav_f) << 2) |
2054 ((params->sav_eav_f ^ vact) << 1) |
2055 (hact ^ vact ^ params->sav_eav_f);
2057 if (tpg->insert_eav) {
2058 unsigned offset = tpg_hdiv(tpg, p, tpg->compose.width * 2 / 3);
2059 u8 *p = vbuf + offset;
2060 unsigned vact = 0, hact = 1;
2062 p[0] = 0xff;
2063 p[1] = 0;
2064 p[2] = 0;
2065 p[3] = 0x80 | (params->sav_eav_f << 6) |
2066 (vact << 5) | (hact << 4) |
2067 ((hact ^ vact) << 3) |
2068 ((hact ^ params->sav_eav_f) << 2) |
2069 ((params->sav_eav_f ^ vact) << 1) |
2070 (hact ^ vact ^ params->sav_eav_f);
2074 static void tpg_fill_plane_pattern(const struct tpg_data *tpg,
2075 const struct tpg_draw_params *params,
2076 unsigned p, unsigned h, u8 *vbuf)
2078 unsigned twopixsize = params->twopixsize;
2079 unsigned img_width = params->img_width;
2080 unsigned mv_hor_old = params->mv_hor_old;
2081 unsigned mv_hor_new = params->mv_hor_new;
2082 unsigned mv_vert_old = params->mv_vert_old;
2083 unsigned mv_vert_new = params->mv_vert_new;
2084 unsigned frame_line = params->frame_line;
2085 unsigned frame_line_next = params->frame_line_next;
2086 unsigned line_offset = tpg_hscale_div(tpg, p, tpg->crop.left);
2087 bool even;
2088 bool fill_blank = false;
2089 unsigned pat_line_old;
2090 unsigned pat_line_new;
2091 u8 *linestart_older;
2092 u8 *linestart_newer;
2093 u8 *linestart_top;
2094 u8 *linestart_bottom;
2096 even = !(frame_line & 1);
2098 if (h >= params->hmax) {
2099 if (params->hmax == tpg->compose.height)
2100 return;
2101 if (!tpg->perc_fill_blank)
2102 return;
2103 fill_blank = true;
2106 if (tpg->vflip) {
2107 frame_line = tpg->src_height - frame_line - 1;
2108 frame_line_next = tpg->src_height - frame_line_next - 1;
2111 if (fill_blank) {
2112 linestart_older = tpg->contrast_line[p];
2113 linestart_newer = tpg->contrast_line[p];
2114 } else if (tpg->qual != TPG_QUAL_NOISE &&
2115 (frame_line < tpg->border.top ||
2116 frame_line >= tpg->border.top + tpg->border.height)) {
2117 linestart_older = tpg->black_line[p];
2118 linestart_newer = tpg->black_line[p];
2119 } else if (tpg->pattern == TPG_PAT_NOISE || tpg->qual == TPG_QUAL_NOISE) {
2120 linestart_older = tpg->random_line[p] +
2121 twopixsize * prandom_u32_max(tpg->src_width / 2);
2122 linestart_newer = tpg->random_line[p] +
2123 twopixsize * prandom_u32_max(tpg->src_width / 2);
2124 } else {
2125 unsigned frame_line_old =
2126 (frame_line + mv_vert_old) % tpg->src_height;
2127 unsigned frame_line_new =
2128 (frame_line + mv_vert_new) % tpg->src_height;
2129 unsigned pat_line_next_old;
2130 unsigned pat_line_next_new;
2132 pat_line_old = tpg_get_pat_line(tpg, frame_line_old);
2133 pat_line_new = tpg_get_pat_line(tpg, frame_line_new);
2134 linestart_older = tpg->lines[pat_line_old][p] + mv_hor_old;
2135 linestart_newer = tpg->lines[pat_line_new][p] + mv_hor_new;
2137 if (tpg->vdownsampling[p] > 1 && frame_line != frame_line_next) {
2138 int avg_pat;
2141 * Now decide whether we need to use downsampled_lines[].
2142 * That's necessary if the two lines use different patterns.
2144 pat_line_next_old = tpg_get_pat_line(tpg,
2145 (frame_line_next + mv_vert_old) % tpg->src_height);
2146 pat_line_next_new = tpg_get_pat_line(tpg,
2147 (frame_line_next + mv_vert_new) % tpg->src_height);
2149 switch (tpg->field) {
2150 case V4L2_FIELD_INTERLACED:
2151 case V4L2_FIELD_INTERLACED_BT:
2152 case V4L2_FIELD_INTERLACED_TB:
2153 avg_pat = tpg_pattern_avg(tpg, pat_line_old, pat_line_new);
2154 if (avg_pat < 0)
2155 break;
2156 linestart_older = tpg->downsampled_lines[avg_pat][p] + mv_hor_old;
2157 linestart_newer = linestart_older;
2158 break;
2159 case V4L2_FIELD_NONE:
2160 case V4L2_FIELD_TOP:
2161 case V4L2_FIELD_BOTTOM:
2162 case V4L2_FIELD_SEQ_BT:
2163 case V4L2_FIELD_SEQ_TB:
2164 avg_pat = tpg_pattern_avg(tpg, pat_line_old, pat_line_next_old);
2165 if (avg_pat >= 0)
2166 linestart_older = tpg->downsampled_lines[avg_pat][p] +
2167 mv_hor_old;
2168 avg_pat = tpg_pattern_avg(tpg, pat_line_new, pat_line_next_new);
2169 if (avg_pat >= 0)
2170 linestart_newer = tpg->downsampled_lines[avg_pat][p] +
2171 mv_hor_new;
2172 break;
2175 linestart_older += line_offset;
2176 linestart_newer += line_offset;
2178 if (tpg->field_alternate) {
2179 linestart_top = linestart_bottom = linestart_older;
2180 } else if (params->is_60hz) {
2181 linestart_top = linestart_newer;
2182 linestart_bottom = linestart_older;
2183 } else {
2184 linestart_top = linestart_older;
2185 linestart_bottom = linestart_newer;
2188 switch (tpg->field) {
2189 case V4L2_FIELD_INTERLACED:
2190 case V4L2_FIELD_INTERLACED_TB:
2191 case V4L2_FIELD_SEQ_TB:
2192 case V4L2_FIELD_SEQ_BT:
2193 if (even)
2194 memcpy(vbuf, linestart_top, img_width);
2195 else
2196 memcpy(vbuf, linestart_bottom, img_width);
2197 break;
2198 case V4L2_FIELD_INTERLACED_BT:
2199 if (even)
2200 memcpy(vbuf, linestart_bottom, img_width);
2201 else
2202 memcpy(vbuf, linestart_top, img_width);
2203 break;
2204 case V4L2_FIELD_TOP:
2205 memcpy(vbuf, linestart_top, img_width);
2206 break;
2207 case V4L2_FIELD_BOTTOM:
2208 memcpy(vbuf, linestart_bottom, img_width);
2209 break;
2210 case V4L2_FIELD_NONE:
2211 default:
2212 memcpy(vbuf, linestart_older, img_width);
2213 break;
2217 void tpg_fill_plane_buffer(struct tpg_data *tpg, v4l2_std_id std,
2218 unsigned p, u8 *vbuf)
2220 struct tpg_draw_params params;
2221 unsigned factor = V4L2_FIELD_HAS_T_OR_B(tpg->field) ? 2 : 1;
2223 /* Coarse scaling with Bresenham */
2224 unsigned int_part = (tpg->crop.height / factor) / tpg->compose.height;
2225 unsigned fract_part = (tpg->crop.height / factor) % tpg->compose.height;
2226 unsigned src_y = 0;
2227 unsigned error = 0;
2228 unsigned h;
2230 tpg_recalc(tpg);
2232 params.is_tv = std;
2233 params.is_60hz = std & V4L2_STD_525_60;
2234 params.twopixsize = tpg->twopixelsize[p];
2235 params.img_width = tpg_hdiv(tpg, p, tpg->compose.width);
2236 params.stride = tpg->bytesperline[p];
2237 params.hmax = (tpg->compose.height * tpg->perc_fill) / 100;
2239 tpg_fill_params_pattern(tpg, p, &params);
2240 tpg_fill_params_extras(tpg, p, &params);
2242 vbuf += tpg_hdiv(tpg, p, tpg->compose.left);
2244 for (h = 0; h < tpg->compose.height; h++) {
2245 unsigned buf_line;
2247 params.frame_line = tpg_calc_frameline(tpg, src_y, tpg->field);
2248 params.frame_line_next = params.frame_line;
2249 buf_line = tpg_calc_buffer_line(tpg, h, tpg->field);
2250 src_y += int_part;
2251 error += fract_part;
2252 if (error >= tpg->compose.height) {
2253 error -= tpg->compose.height;
2254 src_y++;
2258 * For line-interleaved formats determine the 'plane'
2259 * based on the buffer line.
2261 if (tpg_g_interleaved(tpg))
2262 p = tpg_g_interleaved_plane(tpg, buf_line);
2264 if (tpg->vdownsampling[p] > 1) {
2266 * When doing vertical downsampling the field setting
2267 * matters: for SEQ_BT/TB we downsample each field
2268 * separately (i.e. lines 0+2 are combined, as are
2269 * lines 1+3), for the other field settings we combine
2270 * odd and even lines. Doing that for SEQ_BT/TB would
2271 * be really weird.
2273 if (tpg->field == V4L2_FIELD_SEQ_BT ||
2274 tpg->field == V4L2_FIELD_SEQ_TB) {
2275 unsigned next_src_y = src_y;
2277 if ((h & 3) >= 2)
2278 continue;
2279 next_src_y += int_part;
2280 if (error + fract_part >= tpg->compose.height)
2281 next_src_y++;
2282 params.frame_line_next =
2283 tpg_calc_frameline(tpg, next_src_y, tpg->field);
2284 } else {
2285 if (h & 1)
2286 continue;
2287 params.frame_line_next =
2288 tpg_calc_frameline(tpg, src_y, tpg->field);
2291 buf_line /= tpg->vdownsampling[p];
2293 tpg_fill_plane_pattern(tpg, &params, p, h,
2294 vbuf + buf_line * params.stride);
2295 tpg_fill_plane_extras(tpg, &params, p, h,
2296 vbuf + buf_line * params.stride);
2300 void tpg_fillbuffer(struct tpg_data *tpg, v4l2_std_id std, unsigned p, u8 *vbuf)
2302 unsigned offset = 0;
2303 unsigned i;
2305 if (tpg->buffers > 1) {
2306 tpg_fill_plane_buffer(tpg, std, p, vbuf);
2307 return;
2310 for (i = 0; i < tpg_g_planes(tpg); i++) {
2311 tpg_fill_plane_buffer(tpg, std, i, vbuf + offset);
2312 offset += tpg_calc_plane_size(tpg, i);