blob: f76ef3e2f498042dcef45e692770eca429d47dca [file] [log] [blame]
Hans Verkuil63881df2014-08-25 08:02:14 -03001/*
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 */
26const 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",
Hans Verkuil1a05d312015-03-07 12:49:57 -030038 "2x2 Checkers",
Hans Verkuil63881df2014-08-25 08:02:14 -030039 "1x1 Checkers",
Hans Verkuil1a05d312015-03-07 12:49:57 -030040 "2x2 Red/Green Checkers",
41 "1x1 Red/Green Checkers",
Hans Verkuil63881df2014-08-25 08:02:14 -030042 "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 */
53const 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 */
67static 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 */
90static const u8 *font8x16;
91
92void tpg_set_font(const u8 *f)
93{
94 font8x16 = f;
95}
96
97void 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
118int 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 ? 1 : 4;
127
128 tpg->lines[pat][plane] = vzalloc(max_w * 2 * pixelsz);
129 if (!tpg->lines[pat][plane])
130 return -ENOMEM;
Hans Verkuil5d7c5392015-03-07 14:06:43 -0300131 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;
Hans Verkuil63881df2014-08-25 08:02:14 -0300136 }
137 }
138 for (plane = 0; plane < TPG_MAX_PLANES; plane++) {
139 unsigned pixelsz = plane ? 1 : 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;
Hans Verkuilc204e1f2014-10-07 08:58:55 -0300147 tpg->random_line[plane] = vzalloc(max_w * 2 * pixelsz);
Hans Verkuil63881df2014-08-25 08:02:14 -0300148 if (!tpg->random_line[plane])
149 return -ENOMEM;
150 }
151 return 0;
152}
153
154void 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;
Hans Verkuil5d7c5392015-03-07 14:06:43 -0300163 if (plane == 0)
164 continue;
165 vfree(tpg->downsampled_lines[pat][plane]);
166 tpg->downsampled_lines[pat][plane] = NULL;
Hans Verkuil63881df2014-08-25 08:02:14 -0300167 }
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
178bool tpg_s_fourcc(struct tpg_data *tpg, u32 fourcc)
179{
180 tpg->fourcc = fourcc;
181 tpg->planes = 1;
Hans Verkuil06d1f0c2015-03-07 13:01:53 -0300182 tpg->buffers = 1;
Hans Verkuil63881df2014-08-25 08:02:14 -0300183 tpg->recalc_colors = true;
Hans Verkuilba01f672015-03-07 13:57:27 -0300184 tpg->vdownsampling[0] = 1;
185 tpg->hdownsampling[0] = 1;
Hans Verkuil9991def2015-03-08 05:53:10 -0300186 tpg->hmask[0] = ~0;
187 tpg->hmask[1] = ~0;
188 tpg->hmask[2] = ~0;
Hans Verkuil06d1f0c2015-03-07 13:01:53 -0300189
Hans Verkuil63881df2014-08-25 08:02:14 -0300190 switch (fourcc) {
191 case V4L2_PIX_FMT_RGB565:
192 case V4L2_PIX_FMT_RGB565X:
193 case V4L2_PIX_FMT_RGB555:
194 case V4L2_PIX_FMT_XRGB555:
195 case V4L2_PIX_FMT_ARGB555:
196 case V4L2_PIX_FMT_RGB555X:
197 case V4L2_PIX_FMT_RGB24:
198 case V4L2_PIX_FMT_BGR24:
199 case V4L2_PIX_FMT_RGB32:
200 case V4L2_PIX_FMT_BGR32:
201 case V4L2_PIX_FMT_XRGB32:
202 case V4L2_PIX_FMT_XBGR32:
203 case V4L2_PIX_FMT_ARGB32:
204 case V4L2_PIX_FMT_ABGR32:
Hans Verkuil51f30962015-03-07 14:57:50 -0300205 case V4L2_PIX_FMT_GREY:
Mauro Carvalho Chehab6c515a42014-09-03 15:53:45 -0300206 tpg->is_yuv = false;
Hans Verkuil63881df2014-08-25 08:02:14 -0300207 break;
Hans Verkuil68c90d62015-03-07 14:55:09 -0300208 case V4L2_PIX_FMT_YUV420M:
209 case V4L2_PIX_FMT_YVU420M:
210 tpg->buffers = 3;
211 /* fall through */
212 case V4L2_PIX_FMT_YUV420:
213 case V4L2_PIX_FMT_YVU420:
214 tpg->vdownsampling[1] = 2;
215 tpg->vdownsampling[2] = 2;
216 tpg->hdownsampling[1] = 2;
217 tpg->hdownsampling[2] = 2;
218 tpg->planes = 3;
219 tpg->is_yuv = true;
220 break;
221 case V4L2_PIX_FMT_YUV422P:
222 tpg->vdownsampling[1] = 1;
223 tpg->vdownsampling[2] = 1;
224 tpg->hdownsampling[1] = 2;
225 tpg->hdownsampling[2] = 2;
226 tpg->planes = 3;
227 tpg->is_yuv = true;
228 break;
Hans Verkuil63881df2014-08-25 08:02:14 -0300229 case V4L2_PIX_FMT_NV16M:
230 case V4L2_PIX_FMT_NV61M:
Hans Verkuil68c90d62015-03-07 14:55:09 -0300231 tpg->buffers = 2;
232 /* fall through */
233 case V4L2_PIX_FMT_NV16:
234 case V4L2_PIX_FMT_NV61:
Hans Verkuilba01f672015-03-07 13:57:27 -0300235 tpg->vdownsampling[1] = 1;
236 tpg->hdownsampling[1] = 1;
Hans Verkuil9991def2015-03-08 05:53:10 -0300237 tpg->hmask[1] = ~1;
Hans Verkuil63881df2014-08-25 08:02:14 -0300238 tpg->planes = 2;
Hans Verkuil68c90d62015-03-07 14:55:09 -0300239 tpg->is_yuv = true;
240 break;
241 case V4L2_PIX_FMT_NV12M:
242 case V4L2_PIX_FMT_NV21M:
243 tpg->buffers = 2;
244 /* fall through */
245 case V4L2_PIX_FMT_NV12:
246 case V4L2_PIX_FMT_NV21:
247 tpg->vdownsampling[1] = 2;
248 tpg->hdownsampling[1] = 1;
Hans Verkuil9991def2015-03-08 05:53:10 -0300249 tpg->hmask[1] = ~1;
Hans Verkuil68c90d62015-03-07 14:55:09 -0300250 tpg->planes = 2;
251 tpg->is_yuv = true;
252 break;
Hans Verkuil63881df2014-08-25 08:02:14 -0300253 case V4L2_PIX_FMT_YUYV:
254 case V4L2_PIX_FMT_UYVY:
255 case V4L2_PIX_FMT_YVYU:
256 case V4L2_PIX_FMT_VYUY:
Hans Verkuil9991def2015-03-08 05:53:10 -0300257 tpg->hmask[0] = ~1;
Mauro Carvalho Chehab6c515a42014-09-03 15:53:45 -0300258 tpg->is_yuv = true;
Hans Verkuil63881df2014-08-25 08:02:14 -0300259 break;
260 default:
261 return false;
262 }
263
264 switch (fourcc) {
265 case V4L2_PIX_FMT_RGB565:
266 case V4L2_PIX_FMT_RGB565X:
267 case V4L2_PIX_FMT_RGB555:
268 case V4L2_PIX_FMT_XRGB555:
269 case V4L2_PIX_FMT_ARGB555:
270 case V4L2_PIX_FMT_RGB555X:
271 case V4L2_PIX_FMT_YUYV:
272 case V4L2_PIX_FMT_UYVY:
273 case V4L2_PIX_FMT_YVYU:
274 case V4L2_PIX_FMT_VYUY:
275 tpg->twopixelsize[0] = 2 * 2;
276 break;
277 case V4L2_PIX_FMT_RGB24:
278 case V4L2_PIX_FMT_BGR24:
279 tpg->twopixelsize[0] = 2 * 3;
280 break;
281 case V4L2_PIX_FMT_RGB32:
282 case V4L2_PIX_FMT_BGR32:
283 case V4L2_PIX_FMT_XRGB32:
284 case V4L2_PIX_FMT_XBGR32:
285 case V4L2_PIX_FMT_ARGB32:
286 case V4L2_PIX_FMT_ABGR32:
287 tpg->twopixelsize[0] = 2 * 4;
288 break;
Hans Verkuil51f30962015-03-07 14:57:50 -0300289 case V4L2_PIX_FMT_GREY:
290 tpg->twopixelsize[0] = 2;
291 break;
Hans Verkuil68c90d62015-03-07 14:55:09 -0300292 case V4L2_PIX_FMT_NV12:
293 case V4L2_PIX_FMT_NV21:
294 case V4L2_PIX_FMT_NV12M:
295 case V4L2_PIX_FMT_NV21M:
296 tpg->twopixelsize[0] = 2;
297 tpg->twopixelsize[1] = 2;
298 break;
299 case V4L2_PIX_FMT_NV16:
300 case V4L2_PIX_FMT_NV61:
Hans Verkuil63881df2014-08-25 08:02:14 -0300301 case V4L2_PIX_FMT_NV16M:
302 case V4L2_PIX_FMT_NV61M:
303 tpg->twopixelsize[0] = 2;
304 tpg->twopixelsize[1] = 2;
305 break;
Hans Verkuil68c90d62015-03-07 14:55:09 -0300306 case V4L2_PIX_FMT_YUV422P:
307 case V4L2_PIX_FMT_YUV420:
308 case V4L2_PIX_FMT_YVU420:
309 case V4L2_PIX_FMT_YUV420M:
310 case V4L2_PIX_FMT_YVU420M:
311 tpg->twopixelsize[0] = 2;
312 tpg->twopixelsize[1] = 2;
313 tpg->twopixelsize[2] = 2;
314 break;
Hans Verkuil63881df2014-08-25 08:02:14 -0300315 }
316 return true;
317}
318
319void tpg_s_crop_compose(struct tpg_data *tpg, const struct v4l2_rect *crop,
320 const struct v4l2_rect *compose)
321{
322 tpg->crop = *crop;
323 tpg->compose = *compose;
324 tpg->scaled_width = (tpg->src_width * tpg->compose.width +
325 tpg->crop.width - 1) / tpg->crop.width;
326 tpg->scaled_width &= ~1;
327 if (tpg->scaled_width > tpg->max_line_width)
328 tpg->scaled_width = tpg->max_line_width;
329 if (tpg->scaled_width < 2)
330 tpg->scaled_width = 2;
331 tpg->recalc_lines = true;
332}
333
334void tpg_reset_source(struct tpg_data *tpg, unsigned width, unsigned height,
Hans Verkuil73d81022014-09-03 10:18:57 -0300335 u32 field)
Hans Verkuil63881df2014-08-25 08:02:14 -0300336{
337 unsigned p;
338
339 tpg->src_width = width;
340 tpg->src_height = height;
341 tpg->field = field;
342 tpg->buf_height = height;
343 if (V4L2_FIELD_HAS_T_OR_B(field))
344 tpg->buf_height /= 2;
345 tpg->scaled_width = width;
346 tpg->crop.top = tpg->crop.left = 0;
347 tpg->crop.width = width;
348 tpg->crop.height = height;
349 tpg->compose.top = tpg->compose.left = 0;
350 tpg->compose.width = width;
351 tpg->compose.height = tpg->buf_height;
352 for (p = 0; p < tpg->planes; p++)
Hans Verkuilba01f672015-03-07 13:57:27 -0300353 tpg->bytesperline[p] = (width * tpg->twopixelsize[p]) /
354 (2 * tpg->hdownsampling[p]);
Hans Verkuil63881df2014-08-25 08:02:14 -0300355 tpg->recalc_square_border = true;
356}
357
358static enum tpg_color tpg_get_textbg_color(struct tpg_data *tpg)
359{
360 switch (tpg->pattern) {
361 case TPG_PAT_BLACK:
362 return TPG_COLOR_100_WHITE;
363 case TPG_PAT_CSC_COLORBAR:
364 return TPG_COLOR_CSC_BLACK;
365 default:
366 return TPG_COLOR_100_BLACK;
367 }
368}
369
370static enum tpg_color tpg_get_textfg_color(struct tpg_data *tpg)
371{
372 switch (tpg->pattern) {
373 case TPG_PAT_75_COLORBAR:
374 case TPG_PAT_CSC_COLORBAR:
375 return TPG_COLOR_CSC_WHITE;
376 case TPG_PAT_BLACK:
377 return TPG_COLOR_100_BLACK;
378 default:
379 return TPG_COLOR_100_WHITE;
380 }
381}
382
Hans Verkuil481b97a2014-11-17 10:14:32 -0300383static inline int rec709_to_linear(int v)
Hans Verkuil63881df2014-08-25 08:02:14 -0300384{
Hans Verkuil481b97a2014-11-17 10:14:32 -0300385 v = clamp(v, 0, 0xff0);
386 return tpg_rec709_to_linear[v];
387}
388
389static inline int linear_to_rec709(int v)
390{
391 v = clamp(v, 0, 0xff0);
392 return tpg_linear_to_rec709[v];
393}
394
395static void rgb2ycbcr(const int m[3][3], int r, int g, int b,
396 int y_offset, int *y, int *cb, int *cr)
397{
398 *y = ((m[0][0] * r + m[0][1] * g + m[0][2] * b) >> 16) + (y_offset << 4);
399 *cb = ((m[1][0] * r + m[1][1] * g + m[1][2] * b) >> 16) + (128 << 4);
400 *cr = ((m[2][0] * r + m[2][1] * g + m[2][2] * b) >> 16) + (128 << 4);
401}
402
403static void color_to_ycbcr(struct tpg_data *tpg, int r, int g, int b,
404 int *y, int *cb, int *cr)
405{
406#define COEFF(v, r) ((int)(0.5 + (v) * (r) * 256.0))
407
408 static const int bt601[3][3] = {
409 { COEFF(0.299, 219), COEFF(0.587, 219), COEFF(0.114, 219) },
410 { COEFF(-0.169, 224), COEFF(-0.331, 224), COEFF(0.5, 224) },
411 { COEFF(0.5, 224), COEFF(-0.419, 224), COEFF(-0.081, 224) },
412 };
413 static const int bt601_full[3][3] = {
414 { COEFF(0.299, 255), COEFF(0.587, 255), COEFF(0.114, 255) },
415 { COEFF(-0.169, 255), COEFF(-0.331, 255), COEFF(0.5, 255) },
416 { COEFF(0.5, 255), COEFF(-0.419, 255), COEFF(-0.081, 255) },
417 };
418 static const int rec709[3][3] = {
419 { COEFF(0.2126, 219), COEFF(0.7152, 219), COEFF(0.0722, 219) },
420 { COEFF(-0.1146, 224), COEFF(-0.3854, 224), COEFF(0.5, 224) },
421 { COEFF(0.5, 224), COEFF(-0.4542, 224), COEFF(-0.0458, 224) },
422 };
423 static const int rec709_full[3][3] = {
424 { COEFF(0.2126, 255), COEFF(0.7152, 255), COEFF(0.0722, 255) },
425 { COEFF(-0.1146, 255), COEFF(-0.3854, 255), COEFF(0.5, 255) },
426 { COEFF(0.5, 255), COEFF(-0.4542, 255), COEFF(-0.0458, 255) },
427 };
428 static const int smpte240m[3][3] = {
429 { COEFF(0.212, 219), COEFF(0.701, 219), COEFF(0.087, 219) },
430 { COEFF(-0.116, 224), COEFF(-0.384, 224), COEFF(0.5, 224) },
431 { COEFF(0.5, 224), COEFF(-0.445, 224), COEFF(-0.055, 224) },
432 };
433 static const int bt2020[3][3] = {
434 { COEFF(0.2726, 219), COEFF(0.6780, 219), COEFF(0.0593, 219) },
435 { COEFF(-0.1396, 224), COEFF(-0.3604, 224), COEFF(0.5, 224) },
436 { COEFF(0.5, 224), COEFF(-0.4629, 224), COEFF(-0.0405, 224) },
437 };
438 bool full = tpg->real_quantization == V4L2_QUANTIZATION_FULL_RANGE;
Hans Verkuilafad4dd2015-01-27 13:46:17 -0300439 unsigned y_offset = full ? 0 : 16;
Hans Verkuil481b97a2014-11-17 10:14:32 -0300440 int lin_y, yc;
441
442 switch (tpg->real_ycbcr_enc) {
443 case V4L2_YCBCR_ENC_601:
444 case V4L2_YCBCR_ENC_XV601:
445 case V4L2_YCBCR_ENC_SYCC:
Hans Verkuilafad4dd2015-01-27 13:46:17 -0300446 rgb2ycbcr(full ? bt601_full : bt601, r, g, b, y_offset, y, cb, cr);
Hans Verkuil481b97a2014-11-17 10:14:32 -0300447 break;
448 case V4L2_YCBCR_ENC_BT2020:
449 rgb2ycbcr(bt2020, r, g, b, 16, y, cb, cr);
450 break;
451 case V4L2_YCBCR_ENC_BT2020_CONST_LUM:
452 lin_y = (COEFF(0.2627, 255) * rec709_to_linear(r) +
453 COEFF(0.6780, 255) * rec709_to_linear(g) +
454 COEFF(0.0593, 255) * rec709_to_linear(b)) >> 16;
455 yc = linear_to_rec709(lin_y);
456 *y = (yc * 219) / 255 + (16 << 4);
457 if (b <= yc)
458 *cb = (((b - yc) * COEFF(1.0 / 1.9404, 224)) >> 16) + (128 << 4);
459 else
460 *cb = (((b - yc) * COEFF(1.0 / 1.5816, 224)) >> 16) + (128 << 4);
461 if (r <= yc)
462 *cr = (((r - yc) * COEFF(1.0 / 1.7184, 224)) >> 16) + (128 << 4);
463 else
464 *cr = (((r - yc) * COEFF(1.0 / 0.9936, 224)) >> 16) + (128 << 4);
465 break;
466 case V4L2_YCBCR_ENC_SMPTE240M:
467 rgb2ycbcr(smpte240m, r, g, b, 16, y, cb, cr);
468 break;
469 case V4L2_YCBCR_ENC_709:
470 case V4L2_YCBCR_ENC_XV709:
Hans Verkuil63881df2014-08-25 08:02:14 -0300471 default:
Hans Verkuilafad4dd2015-01-27 13:46:17 -0300472 rgb2ycbcr(full ? rec709_full : rec709, r, g, b, y_offset, y, cb, cr);
Hans Verkuil481b97a2014-11-17 10:14:32 -0300473 break;
Hans Verkuil63881df2014-08-25 08:02:14 -0300474 }
475}
476
Hans Verkuil481b97a2014-11-17 10:14:32 -0300477static void ycbcr2rgb(const int m[3][3], int y, int cb, int cr,
478 int y_offset, int *r, int *g, int *b)
Hans Verkuil63881df2014-08-25 08:02:14 -0300479{
Hans Verkuil481b97a2014-11-17 10:14:32 -0300480 y -= y_offset << 4;
Hans Verkuil63881df2014-08-25 08:02:14 -0300481 cb -= 128 << 4;
482 cr -= 128 << 4;
Hans Verkuil481b97a2014-11-17 10:14:32 -0300483 *r = m[0][0] * y + m[0][1] * cb + m[0][2] * cr;
484 *g = m[1][0] * y + m[1][1] * cb + m[1][2] * cr;
485 *b = m[2][0] * y + m[2][1] * cb + m[2][2] * cr;
486 *r = clamp(*r >> 12, 0, 0xff0);
487 *g = clamp(*g >> 12, 0, 0xff0);
488 *b = clamp(*b >> 12, 0, 0xff0);
Hans Verkuil63881df2014-08-25 08:02:14 -0300489}
490
Hans Verkuil481b97a2014-11-17 10:14:32 -0300491static void ycbcr_to_color(struct tpg_data *tpg, int y, int cb, int cr,
492 int *r, int *g, int *b)
Hans Verkuil63881df2014-08-25 08:02:14 -0300493{
Hans Verkuil481b97a2014-11-17 10:14:32 -0300494#undef COEFF
495#define COEFF(v, r) ((int)(0.5 + (v) * ((255.0 * 255.0 * 16.0) / (r))))
496 static const int bt601[3][3] = {
497 { COEFF(1, 219), COEFF(0, 224), COEFF(1.4020, 224) },
498 { COEFF(1, 219), COEFF(-0.3441, 224), COEFF(-0.7141, 224) },
499 { COEFF(1, 219), COEFF(1.7720, 224), COEFF(0, 224) },
500 };
501 static const int bt601_full[3][3] = {
502 { COEFF(1, 255), COEFF(0, 255), COEFF(1.4020, 255) },
503 { COEFF(1, 255), COEFF(-0.3441, 255), COEFF(-0.7141, 255) },
504 { COEFF(1, 255), COEFF(1.7720, 255), COEFF(0, 255) },
505 };
506 static const int rec709[3][3] = {
507 { COEFF(1, 219), COEFF(0, 224), COEFF(1.5748, 224) },
508 { COEFF(1, 219), COEFF(-0.1873, 224), COEFF(-0.4681, 224) },
509 { COEFF(1, 219), COEFF(1.8556, 224), COEFF(0, 224) },
510 };
511 static const int rec709_full[3][3] = {
512 { COEFF(1, 255), COEFF(0, 255), COEFF(1.5748, 255) },
513 { COEFF(1, 255), COEFF(-0.1873, 255), COEFF(-0.4681, 255) },
514 { COEFF(1, 255), COEFF(1.8556, 255), COEFF(0, 255) },
515 };
516 static const int smpte240m[3][3] = {
517 { COEFF(1, 219), COEFF(0, 224), COEFF(1.5756, 224) },
518 { COEFF(1, 219), COEFF(-0.2253, 224), COEFF(-0.4767, 224) },
519 { COEFF(1, 219), COEFF(1.8270, 224), COEFF(0, 224) },
520 };
521 static const int bt2020[3][3] = {
522 { COEFF(1, 219), COEFF(0, 224), COEFF(1.4746, 224) },
523 { COEFF(1, 219), COEFF(-0.1646, 224), COEFF(-0.5714, 224) },
524 { COEFF(1, 219), COEFF(1.8814, 224), COEFF(0, 224) },
525 };
526 bool full = tpg->real_quantization == V4L2_QUANTIZATION_FULL_RANGE;
Hans Verkuilafad4dd2015-01-27 13:46:17 -0300527 unsigned y_offset = full ? 0 : 16;
Hans Verkuil481b97a2014-11-17 10:14:32 -0300528 int lin_r, lin_g, lin_b, lin_y;
Hans Verkuil63881df2014-08-25 08:02:14 -0300529
Hans Verkuil481b97a2014-11-17 10:14:32 -0300530 switch (tpg->real_ycbcr_enc) {
531 case V4L2_YCBCR_ENC_601:
532 case V4L2_YCBCR_ENC_XV601:
533 case V4L2_YCBCR_ENC_SYCC:
Hans Verkuilafad4dd2015-01-27 13:46:17 -0300534 ycbcr2rgb(full ? bt601_full : bt601, y, cb, cr, y_offset, r, g, b);
Hans Verkuil63881df2014-08-25 08:02:14 -0300535 break;
Hans Verkuil481b97a2014-11-17 10:14:32 -0300536 case V4L2_YCBCR_ENC_BT2020:
537 ycbcr2rgb(bt2020, y, cb, cr, 16, r, g, b);
Hans Verkuil63881df2014-08-25 08:02:14 -0300538 break;
Hans Verkuil481b97a2014-11-17 10:14:32 -0300539 case V4L2_YCBCR_ENC_BT2020_CONST_LUM:
540 y -= 16 << 4;
541 cb -= 128 << 4;
542 cr -= 128 << 4;
543
544 if (cb <= 0)
545 *b = COEFF(1.0, 219) * y + COEFF(1.9404, 224) * cb;
546 else
547 *b = COEFF(1.0, 219) * y + COEFF(1.5816, 224) * cb;
548 *b = *b >> 12;
549 if (cr <= 0)
550 *r = COEFF(1.0, 219) * y + COEFF(1.7184, 224) * cr;
551 else
552 *r = COEFF(1.0, 219) * y + COEFF(0.9936, 224) * cr;
553 *r = *r >> 12;
554 lin_r = rec709_to_linear(*r);
555 lin_b = rec709_to_linear(*b);
556 lin_y = rec709_to_linear((y * 255) / 219);
557
558 lin_g = COEFF(1.0 / 0.6780, 255) * lin_y -
559 COEFF(0.2627 / 0.6780, 255) * lin_r -
560 COEFF(0.0593 / 0.6780, 255) * lin_b;
561 *g = linear_to_rec709(lin_g >> 12);
562 break;
563 case V4L2_YCBCR_ENC_SMPTE240M:
564 ycbcr2rgb(smpte240m, y, cb, cr, 16, r, g, b);
565 break;
566 case V4L2_YCBCR_ENC_709:
567 case V4L2_YCBCR_ENC_XV709:
Hans Verkuil63881df2014-08-25 08:02:14 -0300568 default:
Hans Verkuilafad4dd2015-01-27 13:46:17 -0300569 ycbcr2rgb(full ? rec709_full : rec709, y, cb, cr, y_offset, r, g, b);
Hans Verkuil63881df2014-08-25 08:02:14 -0300570 break;
571 }
Hans Verkuil63881df2014-08-25 08:02:14 -0300572}
573
574/* precalculate color bar values to speed up rendering */
575static void precalculate_color(struct tpg_data *tpg, int k)
576{
577 int col = k;
578 int r = tpg_colors[col].r;
579 int g = tpg_colors[col].g;
580 int b = tpg_colors[col].b;
581
582 if (k == TPG_COLOR_TEXTBG) {
583 col = tpg_get_textbg_color(tpg);
584
585 r = tpg_colors[col].r;
586 g = tpg_colors[col].g;
587 b = tpg_colors[col].b;
588 } else if (k == TPG_COLOR_TEXTFG) {
589 col = tpg_get_textfg_color(tpg);
590
591 r = tpg_colors[col].r;
592 g = tpg_colors[col].g;
593 b = tpg_colors[col].b;
594 } else if (tpg->pattern == TPG_PAT_NOISE) {
595 r = g = b = prandom_u32_max(256);
596 } else if (k == TPG_COLOR_RANDOM) {
597 r = g = b = tpg->qual_offset + prandom_u32_max(196);
598 } else if (k >= TPG_COLOR_RAMP) {
599 r = g = b = k - TPG_COLOR_RAMP;
600 }
601
602 if (tpg->pattern == TPG_PAT_CSC_COLORBAR && col <= TPG_COLOR_CSC_BLACK) {
603 r = tpg_csc_colors[tpg->colorspace][col].r;
604 g = tpg_csc_colors[tpg->colorspace][col].g;
605 b = tpg_csc_colors[tpg->colorspace][col].b;
606 } else {
607 r <<= 4;
608 g <<= 4;
609 b <<= 4;
610 }
Hans Verkuil51f30962015-03-07 14:57:50 -0300611 if (tpg->qual == TPG_QUAL_GRAY || tpg->fourcc == V4L2_PIX_FMT_GREY) {
Hans Verkuil481b97a2014-11-17 10:14:32 -0300612 /* Rec. 709 Luma function */
613 /* (0.2126, 0.7152, 0.0722) * (255 * 256) */
Hans Verkuil9c35bd42015-03-07 12:53:39 -0300614 r = g = b = (13879 * r + 46688 * g + 4713 * b) >> 16;
Hans Verkuil481b97a2014-11-17 10:14:32 -0300615 }
Hans Verkuil63881df2014-08-25 08:02:14 -0300616
617 /*
618 * The assumption is that the RGB output is always full range,
619 * so only if the rgb_range overrides the 'real' rgb range do
620 * we need to convert the RGB values.
621 *
Hans Verkuil63881df2014-08-25 08:02:14 -0300622 * Remember that r, g and b are still in the 0 - 0xff0 range.
623 */
624 if (tpg->real_rgb_range == V4L2_DV_RGB_RANGE_LIMITED &&
625 tpg->rgb_range == V4L2_DV_RGB_RANGE_FULL) {
626 /*
627 * Convert from full range (which is what r, g and b are)
628 * to limited range (which is the 'real' RGB range), which
629 * is then interpreted as full range.
630 */
631 r = (r * 219) / 255 + (16 << 4);
632 g = (g * 219) / 255 + (16 << 4);
633 b = (b * 219) / 255 + (16 << 4);
634 } else if (tpg->real_rgb_range != V4L2_DV_RGB_RANGE_LIMITED &&
635 tpg->rgb_range == V4L2_DV_RGB_RANGE_LIMITED) {
636 /*
637 * Clamp r, g and b to the limited range and convert to full
638 * range since that's what we deliver.
639 */
640 r = clamp(r, 16 << 4, 235 << 4);
641 g = clamp(g, 16 << 4, 235 << 4);
642 b = clamp(b, 16 << 4, 235 << 4);
643 r = (r - (16 << 4)) * 255 / 219;
644 g = (g - (16 << 4)) * 255 / 219;
645 b = (b - (16 << 4)) * 255 / 219;
646 }
647
648 if (tpg->brightness != 128 || tpg->contrast != 128 ||
649 tpg->saturation != 128 || tpg->hue) {
650 /* Implement these operations */
Hans Verkuil481b97a2014-11-17 10:14:32 -0300651 int y, cb, cr;
652 int tmp_cb, tmp_cr;
Hans Verkuil63881df2014-08-25 08:02:14 -0300653
654 /* First convert to YCbCr */
Hans Verkuil481b97a2014-11-17 10:14:32 -0300655
656 color_to_ycbcr(tpg, r, g, b, &y, &cb, &cr);
Hans Verkuil63881df2014-08-25 08:02:14 -0300657
658 y = (16 << 4) + ((y - (16 << 4)) * tpg->contrast) / 128;
659 y += (tpg->brightness << 4) - (128 << 4);
660
661 cb -= 128 << 4;
662 cr -= 128 << 4;
663 tmp_cb = (cb * cos(128 + tpg->hue)) / 127 + (cr * sin[128 + tpg->hue]) / 127;
664 tmp_cr = (cr * cos(128 + tpg->hue)) / 127 - (cb * sin[128 + tpg->hue]) / 127;
665
666 cb = (128 << 4) + (tmp_cb * tpg->contrast * tpg->saturation) / (128 * 128);
667 cr = (128 << 4) + (tmp_cr * tpg->contrast * tpg->saturation) / (128 * 128);
668 if (tpg->is_yuv) {
669 tpg->colors[k][0] = clamp(y >> 4, 1, 254);
670 tpg->colors[k][1] = clamp(cb >> 4, 1, 254);
671 tpg->colors[k][2] = clamp(cr >> 4, 1, 254);
672 return;
673 }
Hans Verkuil481b97a2014-11-17 10:14:32 -0300674 ycbcr_to_color(tpg, y, cb, cr, &r, &g, &b);
Hans Verkuil63881df2014-08-25 08:02:14 -0300675 }
676
677 if (tpg->is_yuv) {
678 /* Convert to YCbCr */
Hans Verkuil481b97a2014-11-17 10:14:32 -0300679 int y, cb, cr;
Hans Verkuil63881df2014-08-25 08:02:14 -0300680
Hans Verkuil481b97a2014-11-17 10:14:32 -0300681 color_to_ycbcr(tpg, r, g, b, &y, &cb, &cr);
682
683 if (tpg->real_quantization == V4L2_QUANTIZATION_LIM_RANGE) {
684 y = clamp(y, 16 << 4, 235 << 4);
685 cb = clamp(cb, 16 << 4, 240 << 4);
686 cr = clamp(cr, 16 << 4, 240 << 4);
687 }
Hans Verkuil63881df2014-08-25 08:02:14 -0300688 tpg->colors[k][0] = clamp(y >> 4, 1, 254);
689 tpg->colors[k][1] = clamp(cb >> 4, 1, 254);
690 tpg->colors[k][2] = clamp(cr >> 4, 1, 254);
691 } else {
Hans Verkuil481b97a2014-11-17 10:14:32 -0300692 if (tpg->real_quantization == V4L2_QUANTIZATION_LIM_RANGE) {
693 r = (r * 219) / 255 + (16 << 4);
694 g = (g * 219) / 255 + (16 << 4);
695 b = (b * 219) / 255 + (16 << 4);
696 }
Hans Verkuil63881df2014-08-25 08:02:14 -0300697 switch (tpg->fourcc) {
698 case V4L2_PIX_FMT_RGB565:
699 case V4L2_PIX_FMT_RGB565X:
700 r >>= 7;
701 g >>= 6;
702 b >>= 7;
703 break;
704 case V4L2_PIX_FMT_RGB555:
705 case V4L2_PIX_FMT_XRGB555:
706 case V4L2_PIX_FMT_ARGB555:
707 case V4L2_PIX_FMT_RGB555X:
708 r >>= 7;
709 g >>= 7;
710 b >>= 7;
711 break;
712 default:
713 r >>= 4;
714 g >>= 4;
715 b >>= 4;
716 break;
717 }
718
719 tpg->colors[k][0] = r;
720 tpg->colors[k][1] = g;
721 tpg->colors[k][2] = b;
722 }
723}
724
725static void tpg_precalculate_colors(struct tpg_data *tpg)
726{
727 int k;
728
729 for (k = 0; k < TPG_COLOR_MAX; k++)
730 precalculate_color(tpg, k);
731}
732
733/* 'odd' is true for pixels 1, 3, 5, etc. and false for pixels 0, 2, 4, etc. */
734static void gen_twopix(struct tpg_data *tpg,
735 u8 buf[TPG_MAX_PLANES][8], int color, bool odd)
736{
737 unsigned offset = odd * tpg->twopixelsize[0] / 2;
738 u8 alpha = tpg->alpha_component;
739 u8 r_y, g_u, b_v;
740
741 if (tpg->alpha_red_only && color != TPG_COLOR_CSC_RED &&
742 color != TPG_COLOR_100_RED &&
743 color != TPG_COLOR_75_RED)
744 alpha = 0;
745 if (color == TPG_COLOR_RANDOM)
746 precalculate_color(tpg, color);
747 r_y = tpg->colors[color][0]; /* R or precalculated Y */
748 g_u = tpg->colors[color][1]; /* G or precalculated U */
749 b_v = tpg->colors[color][2]; /* B or precalculated V */
750
751 switch (tpg->fourcc) {
Hans Verkuil51f30962015-03-07 14:57:50 -0300752 case V4L2_PIX_FMT_GREY:
753 buf[0][offset] = r_y;
754 break;
Hans Verkuil68c90d62015-03-07 14:55:09 -0300755 case V4L2_PIX_FMT_YUV422P:
756 case V4L2_PIX_FMT_YUV420:
757 case V4L2_PIX_FMT_YUV420M:
758 buf[0][offset] = r_y;
759 if (odd) {
760 buf[1][0] = (buf[1][0] + g_u) / 2;
761 buf[2][0] = (buf[2][0] + b_v) / 2;
762 buf[1][1] = buf[1][0];
763 buf[2][1] = buf[2][0];
764 break;
765 }
766 buf[1][0] = g_u;
767 buf[2][0] = b_v;
768 break;
769 case V4L2_PIX_FMT_YVU420:
770 case V4L2_PIX_FMT_YVU420M:
771 buf[0][offset] = r_y;
772 if (odd) {
773 buf[1][0] = (buf[1][0] + b_v) / 2;
774 buf[2][0] = (buf[2][0] + g_u) / 2;
775 buf[1][1] = buf[1][0];
776 buf[2][1] = buf[2][0];
777 break;
778 }
779 buf[1][0] = b_v;
780 buf[2][0] = g_u;
781 break;
782
783 case V4L2_PIX_FMT_NV12:
784 case V4L2_PIX_FMT_NV12M:
785 case V4L2_PIX_FMT_NV16:
Hans Verkuil63881df2014-08-25 08:02:14 -0300786 case V4L2_PIX_FMT_NV16M:
787 buf[0][offset] = r_y;
Hans Verkuil1f088dc2015-03-07 14:15:25 -0300788 if (odd) {
789 buf[1][0] = (buf[1][0] + g_u) / 2;
790 buf[1][1] = (buf[1][1] + b_v) / 2;
791 break;
792 }
793 buf[1][0] = g_u;
794 buf[1][1] = b_v;
Hans Verkuil63881df2014-08-25 08:02:14 -0300795 break;
Hans Verkuil68c90d62015-03-07 14:55:09 -0300796 case V4L2_PIX_FMT_NV21:
797 case V4L2_PIX_FMT_NV21M:
798 case V4L2_PIX_FMT_NV61:
Hans Verkuil63881df2014-08-25 08:02:14 -0300799 case V4L2_PIX_FMT_NV61M:
800 buf[0][offset] = r_y;
Hans Verkuil1f088dc2015-03-07 14:15:25 -0300801 if (odd) {
802 buf[1][0] = (buf[1][0] + b_v) / 2;
803 buf[1][1] = (buf[1][1] + g_u) / 2;
804 break;
805 }
806 buf[1][0] = b_v;
807 buf[1][1] = g_u;
Hans Verkuil63881df2014-08-25 08:02:14 -0300808 break;
809
810 case V4L2_PIX_FMT_YUYV:
811 buf[0][offset] = r_y;
Hans Verkuil1f088dc2015-03-07 14:15:25 -0300812 if (odd) {
813 buf[0][1] = (buf[0][1] + g_u) / 2;
814 buf[0][3] = (buf[0][3] + b_v) / 2;
815 break;
816 }
817 buf[0][1] = g_u;
818 buf[0][3] = b_v;
Hans Verkuil63881df2014-08-25 08:02:14 -0300819 break;
820 case V4L2_PIX_FMT_UYVY:
Hans Verkuil63881df2014-08-25 08:02:14 -0300821 buf[0][offset + 1] = r_y;
Hans Verkuil1f088dc2015-03-07 14:15:25 -0300822 if (odd) {
823 buf[0][0] = (buf[0][0] + g_u) / 2;
824 buf[0][2] = (buf[0][2] + b_v) / 2;
825 break;
826 }
827 buf[0][0] = g_u;
828 buf[0][2] = b_v;
Hans Verkuil63881df2014-08-25 08:02:14 -0300829 break;
830 case V4L2_PIX_FMT_YVYU:
831 buf[0][offset] = r_y;
Hans Verkuil1f088dc2015-03-07 14:15:25 -0300832 if (odd) {
833 buf[0][1] = (buf[0][1] + b_v) / 2;
834 buf[0][3] = (buf[0][3] + g_u) / 2;
835 break;
836 }
837 buf[0][1] = b_v;
838 buf[0][3] = g_u;
Hans Verkuil63881df2014-08-25 08:02:14 -0300839 break;
840 case V4L2_PIX_FMT_VYUY:
Hans Verkuil63881df2014-08-25 08:02:14 -0300841 buf[0][offset + 1] = r_y;
Hans Verkuil1f088dc2015-03-07 14:15:25 -0300842 if (odd) {
843 buf[0][0] = (buf[0][0] + b_v) / 2;
844 buf[0][2] = (buf[0][2] + g_u) / 2;
845 break;
846 }
847 buf[0][0] = b_v;
848 buf[0][2] = g_u;
Hans Verkuil63881df2014-08-25 08:02:14 -0300849 break;
850 case V4L2_PIX_FMT_RGB565:
851 buf[0][offset] = (g_u << 5) | b_v;
852 buf[0][offset + 1] = (r_y << 3) | (g_u >> 3);
853 break;
854 case V4L2_PIX_FMT_RGB565X:
855 buf[0][offset] = (r_y << 3) | (g_u >> 3);
856 buf[0][offset + 1] = (g_u << 5) | b_v;
857 break;
858 case V4L2_PIX_FMT_RGB555:
859 case V4L2_PIX_FMT_XRGB555:
860 alpha = 0;
861 /* fall through */
862 case V4L2_PIX_FMT_ARGB555:
863 buf[0][offset] = (g_u << 5) | b_v;
864 buf[0][offset + 1] = (alpha & 0x80) | (r_y << 2) | (g_u >> 3);
865 break;
866 case V4L2_PIX_FMT_RGB555X:
867 buf[0][offset] = (alpha & 0x80) | (r_y << 2) | (g_u >> 3);
868 buf[0][offset + 1] = (g_u << 5) | b_v;
869 break;
870 case V4L2_PIX_FMT_RGB24:
871 buf[0][offset] = r_y;
872 buf[0][offset + 1] = g_u;
873 buf[0][offset + 2] = b_v;
874 break;
875 case V4L2_PIX_FMT_BGR24:
876 buf[0][offset] = b_v;
877 buf[0][offset + 1] = g_u;
878 buf[0][offset + 2] = r_y;
879 break;
880 case V4L2_PIX_FMT_RGB32:
881 case V4L2_PIX_FMT_XRGB32:
882 alpha = 0;
883 /* fall through */
884 case V4L2_PIX_FMT_ARGB32:
885 buf[0][offset] = alpha;
886 buf[0][offset + 1] = r_y;
887 buf[0][offset + 2] = g_u;
888 buf[0][offset + 3] = b_v;
889 break;
890 case V4L2_PIX_FMT_BGR32:
891 case V4L2_PIX_FMT_XBGR32:
892 alpha = 0;
893 /* fall through */
894 case V4L2_PIX_FMT_ABGR32:
895 buf[0][offset] = b_v;
896 buf[0][offset + 1] = g_u;
897 buf[0][offset + 2] = r_y;
898 buf[0][offset + 3] = alpha;
899 break;
900 }
901}
902
903/* Return how many pattern lines are used by the current pattern. */
Hans Verkuil1a05d312015-03-07 12:49:57 -0300904static unsigned tpg_get_pat_lines(const struct tpg_data *tpg)
Hans Verkuil63881df2014-08-25 08:02:14 -0300905{
906 switch (tpg->pattern) {
907 case TPG_PAT_CHECKERS_16X16:
Hans Verkuil1a05d312015-03-07 12:49:57 -0300908 case TPG_PAT_CHECKERS_2X2:
Hans Verkuil63881df2014-08-25 08:02:14 -0300909 case TPG_PAT_CHECKERS_1X1:
Hans Verkuil1a05d312015-03-07 12:49:57 -0300910 case TPG_PAT_COLOR_CHECKERS_2X2:
911 case TPG_PAT_COLOR_CHECKERS_1X1:
Hans Verkuil63881df2014-08-25 08:02:14 -0300912 case TPG_PAT_ALTERNATING_HLINES:
913 case TPG_PAT_CROSS_1_PIXEL:
914 case TPG_PAT_CROSS_2_PIXELS:
915 case TPG_PAT_CROSS_10_PIXELS:
916 return 2;
917 case TPG_PAT_100_COLORSQUARES:
918 case TPG_PAT_100_HCOLORBAR:
919 return 8;
920 default:
921 return 1;
922 }
923}
924
925/* Which pattern line should be used for the given frame line. */
Hans Verkuil1a05d312015-03-07 12:49:57 -0300926static unsigned tpg_get_pat_line(const struct tpg_data *tpg, unsigned line)
Hans Verkuil63881df2014-08-25 08:02:14 -0300927{
928 switch (tpg->pattern) {
929 case TPG_PAT_CHECKERS_16X16:
930 return (line >> 4) & 1;
931 case TPG_PAT_CHECKERS_1X1:
Hans Verkuil1a05d312015-03-07 12:49:57 -0300932 case TPG_PAT_COLOR_CHECKERS_1X1:
Hans Verkuil63881df2014-08-25 08:02:14 -0300933 case TPG_PAT_ALTERNATING_HLINES:
934 return line & 1;
Hans Verkuil1a05d312015-03-07 12:49:57 -0300935 case TPG_PAT_CHECKERS_2X2:
936 case TPG_PAT_COLOR_CHECKERS_2X2:
937 return (line & 2) >> 1;
Hans Verkuil63881df2014-08-25 08:02:14 -0300938 case TPG_PAT_100_COLORSQUARES:
939 case TPG_PAT_100_HCOLORBAR:
940 return (line * 8) / tpg->src_height;
941 case TPG_PAT_CROSS_1_PIXEL:
942 return line == tpg->src_height / 2;
943 case TPG_PAT_CROSS_2_PIXELS:
944 return (line + 1) / 2 == tpg->src_height / 4;
945 case TPG_PAT_CROSS_10_PIXELS:
946 return (line + 10) / 20 == tpg->src_height / 40;
947 default:
948 return 0;
949 }
950}
951
952/*
953 * Which color should be used for the given pattern line and X coordinate.
954 * Note: x is in the range 0 to 2 * tpg->src_width.
955 */
Hans Verkuil1a05d312015-03-07 12:49:57 -0300956static enum tpg_color tpg_get_color(const struct tpg_data *tpg,
957 unsigned pat_line, unsigned x)
Hans Verkuil63881df2014-08-25 08:02:14 -0300958{
959 /* Maximum number of bars are TPG_COLOR_MAX - otherwise, the input print code
960 should be modified */
961 static const enum tpg_color bars[3][8] = {
962 /* Standard ITU-R 75% color bar sequence */
963 { TPG_COLOR_CSC_WHITE, TPG_COLOR_75_YELLOW,
964 TPG_COLOR_75_CYAN, TPG_COLOR_75_GREEN,
965 TPG_COLOR_75_MAGENTA, TPG_COLOR_75_RED,
966 TPG_COLOR_75_BLUE, TPG_COLOR_100_BLACK, },
967 /* Standard ITU-R 100% color bar sequence */
968 { TPG_COLOR_100_WHITE, TPG_COLOR_100_YELLOW,
969 TPG_COLOR_100_CYAN, TPG_COLOR_100_GREEN,
970 TPG_COLOR_100_MAGENTA, TPG_COLOR_100_RED,
971 TPG_COLOR_100_BLUE, TPG_COLOR_100_BLACK, },
972 /* Color bar sequence suitable to test CSC */
973 { TPG_COLOR_CSC_WHITE, TPG_COLOR_CSC_YELLOW,
974 TPG_COLOR_CSC_CYAN, TPG_COLOR_CSC_GREEN,
975 TPG_COLOR_CSC_MAGENTA, TPG_COLOR_CSC_RED,
976 TPG_COLOR_CSC_BLUE, TPG_COLOR_CSC_BLACK, },
977 };
978
979 switch (tpg->pattern) {
980 case TPG_PAT_75_COLORBAR:
981 case TPG_PAT_100_COLORBAR:
982 case TPG_PAT_CSC_COLORBAR:
983 return bars[tpg->pattern][((x * 8) / tpg->src_width) % 8];
984 case TPG_PAT_100_COLORSQUARES:
985 return bars[1][(pat_line + (x * 8) / tpg->src_width) % 8];
986 case TPG_PAT_100_HCOLORBAR:
987 return bars[1][pat_line];
988 case TPG_PAT_BLACK:
989 return TPG_COLOR_100_BLACK;
990 case TPG_PAT_WHITE:
991 return TPG_COLOR_100_WHITE;
992 case TPG_PAT_RED:
993 return TPG_COLOR_100_RED;
994 case TPG_PAT_GREEN:
995 return TPG_COLOR_100_GREEN;
996 case TPG_PAT_BLUE:
997 return TPG_COLOR_100_BLUE;
998 case TPG_PAT_CHECKERS_16X16:
999 return (((x >> 4) & 1) ^ (pat_line & 1)) ?
1000 TPG_COLOR_100_BLACK : TPG_COLOR_100_WHITE;
1001 case TPG_PAT_CHECKERS_1X1:
1002 return ((x & 1) ^ (pat_line & 1)) ?
1003 TPG_COLOR_100_WHITE : TPG_COLOR_100_BLACK;
Hans Verkuil1a05d312015-03-07 12:49:57 -03001004 case TPG_PAT_COLOR_CHECKERS_1X1:
1005 return ((x & 1) ^ (pat_line & 1)) ?
1006 TPG_COLOR_100_RED : TPG_COLOR_100_BLUE;
1007 case TPG_PAT_CHECKERS_2X2:
1008 return (((x >> 1) & 1) ^ (pat_line & 1)) ?
1009 TPG_COLOR_100_WHITE : TPG_COLOR_100_BLACK;
1010 case TPG_PAT_COLOR_CHECKERS_2X2:
1011 return (((x >> 1) & 1) ^ (pat_line & 1)) ?
1012 TPG_COLOR_100_RED : TPG_COLOR_100_BLUE;
Hans Verkuil63881df2014-08-25 08:02:14 -03001013 case TPG_PAT_ALTERNATING_HLINES:
1014 return pat_line ? TPG_COLOR_100_WHITE : TPG_COLOR_100_BLACK;
1015 case TPG_PAT_ALTERNATING_VLINES:
1016 return (x & 1) ? TPG_COLOR_100_WHITE : TPG_COLOR_100_BLACK;
1017 case TPG_PAT_CROSS_1_PIXEL:
1018 if (pat_line || (x % tpg->src_width) == tpg->src_width / 2)
1019 return TPG_COLOR_100_BLACK;
1020 return TPG_COLOR_100_WHITE;
1021 case TPG_PAT_CROSS_2_PIXELS:
1022 if (pat_line || ((x % tpg->src_width) + 1) / 2 == tpg->src_width / 4)
1023 return TPG_COLOR_100_BLACK;
1024 return TPG_COLOR_100_WHITE;
1025 case TPG_PAT_CROSS_10_PIXELS:
1026 if (pat_line || ((x % tpg->src_width) + 10) / 20 == tpg->src_width / 40)
1027 return TPG_COLOR_100_BLACK;
1028 return TPG_COLOR_100_WHITE;
1029 case TPG_PAT_GRAY_RAMP:
1030 return TPG_COLOR_RAMP + ((x % tpg->src_width) * 256) / tpg->src_width;
1031 default:
1032 return TPG_COLOR_100_RED;
1033 }
1034}
1035
1036/*
1037 * Given the pixel aspect ratio and video aspect ratio calculate the
1038 * coordinates of a centered square and the coordinates of the border of
1039 * the active video area. The coordinates are relative to the source
1040 * frame rectangle.
1041 */
1042static void tpg_calculate_square_border(struct tpg_data *tpg)
1043{
1044 unsigned w = tpg->src_width;
1045 unsigned h = tpg->src_height;
1046 unsigned sq_w, sq_h;
1047
1048 sq_w = (w * 2 / 5) & ~1;
1049 if (((w - sq_w) / 2) & 1)
1050 sq_w += 2;
1051 sq_h = sq_w;
1052 tpg->square.width = sq_w;
1053 if (tpg->vid_aspect == TPG_VIDEO_ASPECT_16X9_ANAMORPHIC) {
1054 unsigned ana_sq_w = (sq_w / 4) * 3;
1055
1056 if (((w - ana_sq_w) / 2) & 1)
1057 ana_sq_w += 2;
1058 tpg->square.width = ana_sq_w;
1059 }
1060 tpg->square.left = (w - tpg->square.width) / 2;
1061 if (tpg->pix_aspect == TPG_PIXEL_ASPECT_NTSC)
1062 sq_h = sq_w * 10 / 11;
1063 else if (tpg->pix_aspect == TPG_PIXEL_ASPECT_PAL)
1064 sq_h = sq_w * 59 / 54;
1065 tpg->square.height = sq_h;
1066 tpg->square.top = (h - sq_h) / 2;
1067 tpg->border.left = 0;
1068 tpg->border.width = w;
1069 tpg->border.top = 0;
1070 tpg->border.height = h;
1071 switch (tpg->vid_aspect) {
1072 case TPG_VIDEO_ASPECT_4X3:
1073 if (tpg->pix_aspect)
1074 return;
1075 if (3 * w >= 4 * h) {
1076 tpg->border.width = ((4 * h) / 3) & ~1;
1077 if (((w - tpg->border.width) / 2) & ~1)
1078 tpg->border.width -= 2;
1079 tpg->border.left = (w - tpg->border.width) / 2;
1080 break;
1081 }
1082 tpg->border.height = ((3 * w) / 4) & ~1;
1083 tpg->border.top = (h - tpg->border.height) / 2;
1084 break;
1085 case TPG_VIDEO_ASPECT_14X9_CENTRE:
1086 if (tpg->pix_aspect) {
1087 tpg->border.height = tpg->pix_aspect == TPG_PIXEL_ASPECT_NTSC ? 420 : 506;
1088 tpg->border.top = (h - tpg->border.height) / 2;
1089 break;
1090 }
1091 if (9 * w >= 14 * h) {
1092 tpg->border.width = ((14 * h) / 9) & ~1;
1093 if (((w - tpg->border.width) / 2) & ~1)
1094 tpg->border.width -= 2;
1095 tpg->border.left = (w - tpg->border.width) / 2;
1096 break;
1097 }
1098 tpg->border.height = ((9 * w) / 14) & ~1;
1099 tpg->border.top = (h - tpg->border.height) / 2;
1100 break;
1101 case TPG_VIDEO_ASPECT_16X9_CENTRE:
1102 if (tpg->pix_aspect) {
1103 tpg->border.height = tpg->pix_aspect == TPG_PIXEL_ASPECT_NTSC ? 368 : 442;
1104 tpg->border.top = (h - tpg->border.height) / 2;
1105 break;
1106 }
1107 if (9 * w >= 16 * h) {
1108 tpg->border.width = ((16 * h) / 9) & ~1;
1109 if (((w - tpg->border.width) / 2) & ~1)
1110 tpg->border.width -= 2;
1111 tpg->border.left = (w - tpg->border.width) / 2;
1112 break;
1113 }
1114 tpg->border.height = ((9 * w) / 16) & ~1;
1115 tpg->border.top = (h - tpg->border.height) / 2;
1116 break;
1117 default:
1118 break;
1119 }
1120}
1121
1122static void tpg_precalculate_line(struct tpg_data *tpg)
1123{
1124 enum tpg_color contrast;
Hans Verkuil9991def2015-03-08 05:53:10 -03001125 u8 pix[TPG_MAX_PLANES][8];
Hans Verkuil63881df2014-08-25 08:02:14 -03001126 unsigned pat;
1127 unsigned p;
1128 unsigned x;
1129
1130 switch (tpg->pattern) {
1131 case TPG_PAT_GREEN:
1132 contrast = TPG_COLOR_100_RED;
1133 break;
1134 case TPG_PAT_CSC_COLORBAR:
1135 contrast = TPG_COLOR_CSC_GREEN;
1136 break;
1137 default:
1138 contrast = TPG_COLOR_100_GREEN;
1139 break;
1140 }
1141
1142 for (pat = 0; pat < tpg_get_pat_lines(tpg); pat++) {
1143 /* Coarse scaling with Bresenham */
1144 unsigned int_part = tpg->src_width / tpg->scaled_width;
1145 unsigned fract_part = tpg->src_width % tpg->scaled_width;
1146 unsigned src_x = 0;
1147 unsigned error = 0;
1148
1149 for (x = 0; x < tpg->scaled_width * 2; x += 2) {
1150 unsigned real_x = src_x;
1151 enum tpg_color color1, color2;
Hans Verkuil63881df2014-08-25 08:02:14 -03001152
1153 real_x = tpg->hflip ? tpg->src_width * 2 - real_x - 2 : real_x;
1154 color1 = tpg_get_color(tpg, pat, real_x);
1155
1156 src_x += int_part;
1157 error += fract_part;
1158 if (error >= tpg->scaled_width) {
1159 error -= tpg->scaled_width;
1160 src_x++;
1161 }
1162
1163 real_x = src_x;
1164 real_x = tpg->hflip ? tpg->src_width * 2 - real_x - 2 : real_x;
1165 color2 = tpg_get_color(tpg, pat, real_x);
1166
1167 src_x += int_part;
1168 error += fract_part;
1169 if (error >= tpg->scaled_width) {
1170 error -= tpg->scaled_width;
1171 src_x++;
1172 }
1173
1174 gen_twopix(tpg, pix, tpg->hflip ? color2 : color1, 0);
1175 gen_twopix(tpg, pix, tpg->hflip ? color1 : color2, 1);
1176 for (p = 0; p < tpg->planes; p++) {
1177 unsigned twopixsize = tpg->twopixelsize[p];
Hans Verkuil5d7c5392015-03-07 14:06:43 -03001178 unsigned hdiv = tpg->hdownsampling[p];
Hans Verkuil9991def2015-03-08 05:53:10 -03001179 u8 *pos = tpg->lines[pat][p] + tpg_hdiv(tpg, p, x);
Hans Verkuil63881df2014-08-25 08:02:14 -03001180
Hans Verkuil5d7c5392015-03-07 14:06:43 -03001181 memcpy(pos, pix[p], twopixsize / hdiv);
Hans Verkuil63881df2014-08-25 08:02:14 -03001182 }
1183 }
1184 }
Hans Verkuil5d7c5392015-03-07 14:06:43 -03001185
1186 if (tpg->vdownsampling[tpg->planes - 1] > 1) {
1187 unsigned pat_lines = tpg_get_pat_lines(tpg);
1188
1189 for (pat = 0; pat < pat_lines; pat++) {
1190 unsigned next_pat = (pat + 1) % pat_lines;
1191
1192 for (p = 1; p < tpg->planes; p++) {
Hans Verkuil9991def2015-03-08 05:53:10 -03001193 unsigned w = tpg_hdiv(tpg, p, tpg->scaled_width * 2);
1194 u8 *pos1 = tpg->lines[pat][p];
1195 u8 *pos2 = tpg->lines[next_pat][p];
1196 u8 *dest = tpg->downsampled_lines[pat][p];
Hans Verkuil5d7c5392015-03-07 14:06:43 -03001197
Hans Verkuil9991def2015-03-08 05:53:10 -03001198 for (x = 0; x < w; x++, pos1++, pos2++, dest++)
1199 *dest = ((u16)*pos1 + (u16)*pos2) / 2;
Hans Verkuil5d7c5392015-03-07 14:06:43 -03001200 }
1201 }
1202 }
1203
Hans Verkuil9991def2015-03-08 05:53:10 -03001204 gen_twopix(tpg, pix, contrast, 0);
1205 gen_twopix(tpg, pix, contrast, 1);
1206 for (p = 0; p < tpg->planes; p++) {
1207 unsigned twopixsize = tpg->twopixelsize[p];
1208 u8 *pos = tpg->contrast_line[p];
Hans Verkuil63881df2014-08-25 08:02:14 -03001209
Hans Verkuil9991def2015-03-08 05:53:10 -03001210 for (x = 0; x < tpg->scaled_width; x += 2, pos += twopixsize)
Hans Verkuil63881df2014-08-25 08:02:14 -03001211 memcpy(pos, pix[p], twopixsize);
Hans Verkuil63881df2014-08-25 08:02:14 -03001212 }
Hans Verkuil63881df2014-08-25 08:02:14 -03001213
Hans Verkuil9991def2015-03-08 05:53:10 -03001214 gen_twopix(tpg, pix, TPG_COLOR_100_BLACK, 0);
1215 gen_twopix(tpg, pix, TPG_COLOR_100_BLACK, 1);
1216 for (p = 0; p < tpg->planes; p++) {
1217 unsigned twopixsize = tpg->twopixelsize[p];
1218 u8 *pos = tpg->black_line[p];
Hans Verkuil63881df2014-08-25 08:02:14 -03001219
Hans Verkuil9991def2015-03-08 05:53:10 -03001220 for (x = 0; x < tpg->scaled_width; x += 2, pos += twopixsize)
Hans Verkuil63881df2014-08-25 08:02:14 -03001221 memcpy(pos, pix[p], twopixsize);
Hans Verkuil63881df2014-08-25 08:02:14 -03001222 }
Hans Verkuil9991def2015-03-08 05:53:10 -03001223
Hans Verkuil63881df2014-08-25 08:02:14 -03001224 for (x = 0; x < tpg->scaled_width * 2; x += 2) {
Hans Verkuil63881df2014-08-25 08:02:14 -03001225 gen_twopix(tpg, pix, TPG_COLOR_RANDOM, 0);
1226 gen_twopix(tpg, pix, TPG_COLOR_RANDOM, 1);
1227 for (p = 0; p < tpg->planes; p++) {
1228 unsigned twopixsize = tpg->twopixelsize[p];
1229 u8 *pos = tpg->random_line[p] + x * twopixsize / 2;
1230
1231 memcpy(pos, pix[p], twopixsize);
1232 }
1233 }
Hans Verkuil9991def2015-03-08 05:53:10 -03001234
Hans Verkuil63881df2014-08-25 08:02:14 -03001235 gen_twopix(tpg, tpg->textbg, TPG_COLOR_TEXTBG, 0);
1236 gen_twopix(tpg, tpg->textbg, TPG_COLOR_TEXTBG, 1);
1237 gen_twopix(tpg, tpg->textfg, TPG_COLOR_TEXTFG, 0);
1238 gen_twopix(tpg, tpg->textfg, TPG_COLOR_TEXTFG, 1);
1239}
1240
1241/* need this to do rgb24 rendering */
1242typedef struct { u16 __; u8 _; } __packed x24;
1243
Hans Verkuildfff0482015-03-09 11:04:02 -03001244void tpg_gen_text(const struct tpg_data *tpg, u8 *basep[TPG_MAX_PLANES][2],
1245 int y, int x, char *text)
Hans Verkuil63881df2014-08-25 08:02:14 -03001246{
1247 int line;
1248 unsigned step = V4L2_FIELD_HAS_T_OR_B(tpg->field) ? 2 : 1;
1249 unsigned div = step;
1250 unsigned first = 0;
1251 unsigned len = strlen(text);
1252 unsigned p;
1253
1254 if (font8x16 == NULL || basep == NULL)
1255 return;
1256
1257 /* Checks if it is possible to show string */
1258 if (y + 16 >= tpg->compose.height || x + 8 >= tpg->compose.width)
1259 return;
1260
1261 if (len > (tpg->compose.width - x) / 8)
1262 len = (tpg->compose.width - x) / 8;
1263 if (tpg->vflip)
1264 y = tpg->compose.height - y - 16;
1265 if (tpg->hflip)
1266 x = tpg->compose.width - x - 8;
1267 y += tpg->compose.top;
1268 x += tpg->compose.left;
1269 if (tpg->field == V4L2_FIELD_BOTTOM)
1270 first = 1;
1271 else if (tpg->field == V4L2_FIELD_SEQ_TB || tpg->field == V4L2_FIELD_SEQ_BT)
1272 div = 2;
1273
1274 for (p = 0; p < tpg->planes; p++) {
Hans Verkuil3e14e7a82015-03-07 14:23:16 -03001275 unsigned vdiv = tpg->vdownsampling[p];
1276 unsigned hdiv = tpg->hdownsampling[p];
1277
1278 /* Print text */
Hans Verkuil63881df2014-08-25 08:02:14 -03001279#define PRINTSTR(PIXTYPE) do { \
1280 PIXTYPE fg; \
1281 PIXTYPE bg; \
1282 memcpy(&fg, tpg->textfg[p], sizeof(PIXTYPE)); \
1283 memcpy(&bg, tpg->textbg[p], sizeof(PIXTYPE)); \
1284 \
Hans Verkuil3e14e7a82015-03-07 14:23:16 -03001285 for (line = first; line < 16; line += vdiv * step) { \
Hans Verkuil63881df2014-08-25 08:02:14 -03001286 int l = tpg->vflip ? 15 - line : line; \
Hans Verkuil3e14e7a82015-03-07 14:23:16 -03001287 PIXTYPE *pos = (PIXTYPE *)(basep[p][(line / vdiv) & 1] + \
1288 ((y * step + l) / (vdiv * div)) * tpg->bytesperline[p] + \
1289 (x / hdiv) * sizeof(PIXTYPE)); \
Hans Verkuil63881df2014-08-25 08:02:14 -03001290 unsigned s; \
1291 \
1292 for (s = 0; s < len; s++) { \
1293 u8 chr = font8x16[text[s] * 16 + line]; \
1294 \
Hans Verkuil3e14e7a82015-03-07 14:23:16 -03001295 if (hdiv == 2 && tpg->hflip) { \
1296 pos[3] = (chr & (0x01 << 6) ? fg : bg); \
1297 pos[2] = (chr & (0x01 << 4) ? fg : bg); \
1298 pos[1] = (chr & (0x01 << 2) ? fg : bg); \
1299 pos[0] = (chr & (0x01 << 0) ? fg : bg); \
1300 } else if (hdiv == 2) { \
1301 pos[0] = (chr & (0x01 << 7) ? fg : bg); \
1302 pos[1] = (chr & (0x01 << 5) ? fg : bg); \
1303 pos[2] = (chr & (0x01 << 3) ? fg : bg); \
1304 pos[3] = (chr & (0x01 << 1) ? fg : bg); \
1305 } else if (tpg->hflip) { \
Hans Verkuil63881df2014-08-25 08:02:14 -03001306 pos[7] = (chr & (0x01 << 7) ? fg : bg); \
1307 pos[6] = (chr & (0x01 << 6) ? fg : bg); \
1308 pos[5] = (chr & (0x01 << 5) ? fg : bg); \
1309 pos[4] = (chr & (0x01 << 4) ? fg : bg); \
1310 pos[3] = (chr & (0x01 << 3) ? fg : bg); \
1311 pos[2] = (chr & (0x01 << 2) ? fg : bg); \
1312 pos[1] = (chr & (0x01 << 1) ? fg : bg); \
1313 pos[0] = (chr & (0x01 << 0) ? fg : bg); \
1314 } else { \
1315 pos[0] = (chr & (0x01 << 7) ? fg : bg); \
1316 pos[1] = (chr & (0x01 << 6) ? fg : bg); \
1317 pos[2] = (chr & (0x01 << 5) ? fg : bg); \
1318 pos[3] = (chr & (0x01 << 4) ? fg : bg); \
1319 pos[4] = (chr & (0x01 << 3) ? fg : bg); \
1320 pos[5] = (chr & (0x01 << 2) ? fg : bg); \
1321 pos[6] = (chr & (0x01 << 1) ? fg : bg); \
1322 pos[7] = (chr & (0x01 << 0) ? fg : bg); \
1323 } \
1324 \
Hans Verkuil3e14e7a82015-03-07 14:23:16 -03001325 pos += (tpg->hflip ? -8 : 8) / hdiv; \
Hans Verkuil63881df2014-08-25 08:02:14 -03001326 } \
1327 } \
1328} while (0)
1329
1330 switch (tpg->twopixelsize[p]) {
1331 case 2:
1332 PRINTSTR(u8); break;
1333 case 4:
1334 PRINTSTR(u16); break;
1335 case 6:
1336 PRINTSTR(x24); break;
1337 case 8:
1338 PRINTSTR(u32); break;
1339 }
1340 }
1341}
1342
1343void tpg_update_mv_step(struct tpg_data *tpg)
1344{
1345 int factor = tpg->mv_hor_mode > TPG_MOVE_NONE ? -1 : 1;
1346
1347 if (tpg->hflip)
1348 factor = -factor;
1349 switch (tpg->mv_hor_mode) {
1350 case TPG_MOVE_NEG_FAST:
1351 case TPG_MOVE_POS_FAST:
1352 tpg->mv_hor_step = ((tpg->src_width + 319) / 320) * 4;
1353 break;
1354 case TPG_MOVE_NEG:
1355 case TPG_MOVE_POS:
1356 tpg->mv_hor_step = ((tpg->src_width + 639) / 640) * 4;
1357 break;
1358 case TPG_MOVE_NEG_SLOW:
1359 case TPG_MOVE_POS_SLOW:
1360 tpg->mv_hor_step = 2;
1361 break;
1362 case TPG_MOVE_NONE:
1363 tpg->mv_hor_step = 0;
1364 break;
1365 }
1366 if (factor < 0)
1367 tpg->mv_hor_step = tpg->src_width - tpg->mv_hor_step;
1368
1369 factor = tpg->mv_vert_mode > TPG_MOVE_NONE ? -1 : 1;
1370 switch (tpg->mv_vert_mode) {
1371 case TPG_MOVE_NEG_FAST:
1372 case TPG_MOVE_POS_FAST:
1373 tpg->mv_vert_step = ((tpg->src_width + 319) / 320) * 4;
1374 break;
1375 case TPG_MOVE_NEG:
1376 case TPG_MOVE_POS:
1377 tpg->mv_vert_step = ((tpg->src_width + 639) / 640) * 4;
1378 break;
1379 case TPG_MOVE_NEG_SLOW:
1380 case TPG_MOVE_POS_SLOW:
1381 tpg->mv_vert_step = 1;
1382 break;
1383 case TPG_MOVE_NONE:
1384 tpg->mv_vert_step = 0;
1385 break;
1386 }
1387 if (factor < 0)
1388 tpg->mv_vert_step = tpg->src_height - tpg->mv_vert_step;
1389}
1390
1391/* Map the line number relative to the crop rectangle to a frame line number */
Hans Verkuildfff0482015-03-09 11:04:02 -03001392static unsigned tpg_calc_frameline(const struct tpg_data *tpg, unsigned src_y,
Hans Verkuil63881df2014-08-25 08:02:14 -03001393 unsigned field)
1394{
1395 switch (field) {
1396 case V4L2_FIELD_TOP:
1397 return tpg->crop.top + src_y * 2;
1398 case V4L2_FIELD_BOTTOM:
1399 return tpg->crop.top + src_y * 2 + 1;
1400 default:
1401 return src_y + tpg->crop.top;
1402 }
1403}
1404
1405/*
1406 * Map the line number relative to the compose rectangle to a destination
1407 * buffer line number.
1408 */
Hans Verkuildfff0482015-03-09 11:04:02 -03001409static unsigned tpg_calc_buffer_line(const struct tpg_data *tpg, unsigned y,
Hans Verkuil63881df2014-08-25 08:02:14 -03001410 unsigned field)
1411{
1412 y += tpg->compose.top;
1413 switch (field) {
1414 case V4L2_FIELD_SEQ_TB:
1415 if (y & 1)
1416 return tpg->buf_height / 2 + y / 2;
1417 return y / 2;
1418 case V4L2_FIELD_SEQ_BT:
1419 if (y & 1)
1420 return y / 2;
1421 return tpg->buf_height / 2 + y / 2;
1422 default:
1423 return y;
1424 }
1425}
1426
1427static void tpg_recalc(struct tpg_data *tpg)
1428{
1429 if (tpg->recalc_colors) {
1430 tpg->recalc_colors = false;
1431 tpg->recalc_lines = true;
Hans Verkuil481b97a2014-11-17 10:14:32 -03001432 tpg->real_ycbcr_enc = tpg->ycbcr_enc;
1433 tpg->real_quantization = tpg->quantization;
1434 if (tpg->ycbcr_enc == V4L2_YCBCR_ENC_DEFAULT) {
1435 switch (tpg->colorspace) {
1436 case V4L2_COLORSPACE_REC709:
1437 tpg->real_ycbcr_enc = V4L2_YCBCR_ENC_709;
1438 break;
1439 case V4L2_COLORSPACE_SRGB:
1440 tpg->real_ycbcr_enc = V4L2_YCBCR_ENC_SYCC;
1441 break;
1442 case V4L2_COLORSPACE_BT2020:
1443 tpg->real_ycbcr_enc = V4L2_YCBCR_ENC_BT2020;
1444 break;
1445 case V4L2_COLORSPACE_SMPTE240M:
1446 tpg->real_ycbcr_enc = V4L2_YCBCR_ENC_SMPTE240M;
1447 break;
1448 case V4L2_COLORSPACE_SMPTE170M:
1449 case V4L2_COLORSPACE_470_SYSTEM_M:
1450 case V4L2_COLORSPACE_470_SYSTEM_BG:
1451 case V4L2_COLORSPACE_ADOBERGB:
1452 default:
1453 tpg->real_ycbcr_enc = V4L2_YCBCR_ENC_601;
1454 break;
1455 }
1456 }
1457 if (tpg->quantization == V4L2_QUANTIZATION_DEFAULT) {
1458 tpg->real_quantization = V4L2_QUANTIZATION_FULL_RANGE;
1459 if (tpg->is_yuv) {
1460 switch (tpg->real_ycbcr_enc) {
1461 case V4L2_YCBCR_ENC_SYCC:
1462 case V4L2_YCBCR_ENC_XV601:
1463 case V4L2_YCBCR_ENC_XV709:
1464 break;
1465 default:
1466 tpg->real_quantization =
1467 V4L2_QUANTIZATION_LIM_RANGE;
1468 break;
1469 }
Hans Verkuilc0b50d92015-03-08 04:53:33 -03001470 } else if (tpg->colorspace == V4L2_COLORSPACE_BT2020) {
1471 /* R'G'B' BT.2020 is limited range */
1472 tpg->real_quantization =
1473 V4L2_QUANTIZATION_LIM_RANGE;
Hans Verkuil481b97a2014-11-17 10:14:32 -03001474 }
1475 }
Hans Verkuil63881df2014-08-25 08:02:14 -03001476 tpg_precalculate_colors(tpg);
1477 }
1478 if (tpg->recalc_square_border) {
1479 tpg->recalc_square_border = false;
1480 tpg_calculate_square_border(tpg);
1481 }
1482 if (tpg->recalc_lines) {
1483 tpg->recalc_lines = false;
1484 tpg_precalculate_line(tpg);
1485 }
1486}
1487
1488void tpg_calc_text_basep(struct tpg_data *tpg,
1489 u8 *basep[TPG_MAX_PLANES][2], unsigned p, u8 *vbuf)
1490{
1491 unsigned stride = tpg->bytesperline[p];
Hans Verkuil280abe42015-03-07 14:50:41 -03001492 unsigned h = tpg->buf_height;
Hans Verkuil63881df2014-08-25 08:02:14 -03001493
1494 tpg_recalc(tpg);
1495
1496 basep[p][0] = vbuf;
1497 basep[p][1] = vbuf;
Hans Verkuil280abe42015-03-07 14:50:41 -03001498 h /= tpg->vdownsampling[p];
Hans Verkuil63881df2014-08-25 08:02:14 -03001499 if (tpg->field == V4L2_FIELD_SEQ_TB)
Hans Verkuil280abe42015-03-07 14:50:41 -03001500 basep[p][1] += h * stride / 2;
Hans Verkuil63881df2014-08-25 08:02:14 -03001501 else if (tpg->field == V4L2_FIELD_SEQ_BT)
Hans Verkuil280abe42015-03-07 14:50:41 -03001502 basep[p][0] += h * stride / 2;
1503}
1504
1505static int tpg_pattern_avg(const struct tpg_data *tpg,
1506 unsigned pat1, unsigned pat2)
1507{
1508 unsigned pat_lines = tpg_get_pat_lines(tpg);
1509
1510 if (pat1 == (pat2 + 1) % pat_lines)
1511 return pat2;
1512 if (pat2 == (pat1 + 1) % pat_lines)
1513 return pat1;
1514 return -1;
Hans Verkuil63881df2014-08-25 08:02:14 -03001515}
1516
Hans Verkuile76036d2015-03-09 11:07:23 -03001517/*
1518 * This struct contains common parameters used by both the drawing of the
1519 * test pattern and the drawing of the extras (borders, square, etc.)
1520 */
1521struct tpg_draw_params {
1522 /* common data */
1523 bool is_tv;
1524 bool is_60hz;
1525 unsigned twopixsize;
1526 unsigned img_width;
1527 unsigned stride;
1528 unsigned hmax;
1529 unsigned frame_line;
1530 unsigned frame_line_next;
1531
1532 /* test pattern */
1533 unsigned mv_hor_old;
1534 unsigned mv_hor_new;
1535 unsigned mv_vert_old;
1536 unsigned mv_vert_new;
1537
1538 /* extras */
1539 unsigned wss_width;
1540 unsigned wss_random_offset;
1541 unsigned sav_eav_f;
1542 unsigned left_pillar_width;
1543 unsigned right_pillar_start;
1544};
1545
Hans Verkuilf0ce4fd2015-03-09 11:30:05 -03001546static void tpg_fill_params_pattern(const struct tpg_data *tpg, unsigned p,
1547 struct tpg_draw_params *params)
1548{
1549 params->mv_hor_old =
1550 tpg_hscale_div(tpg, p, tpg->mv_hor_count % tpg->src_width);
1551 params->mv_hor_new =
1552 tpg_hscale_div(tpg, p, (tpg->mv_hor_count + tpg->mv_hor_step) %
1553 tpg->src_width);
1554 params->mv_vert_old = tpg->mv_vert_count % tpg->src_height;
1555 params->mv_vert_new =
1556 (tpg->mv_vert_count + tpg->mv_vert_step) % tpg->src_height;
1557}
1558
Hans Verkuil07386b92015-03-09 11:39:19 -03001559static void tpg_fill_params_extras(const struct tpg_data *tpg,
1560 unsigned p,
1561 struct tpg_draw_params *params)
1562{
1563 unsigned left_pillar_width = 0;
1564 unsigned right_pillar_start = params->img_width;
1565
1566 params->wss_width = tpg->crop.left < tpg->src_width / 2 ?
1567 tpg->src_width / 2 - tpg->crop.left : 0;
1568 if (params->wss_width > tpg->crop.width)
1569 params->wss_width = tpg->crop.width;
1570 params->wss_width = tpg_hscale_div(tpg, p, params->wss_width);
1571 params->wss_random_offset =
1572 params->twopixsize * prandom_u32_max(tpg->src_width / 2);
1573
1574 if (tpg->crop.left < tpg->border.left) {
1575 left_pillar_width = tpg->border.left - tpg->crop.left;
1576 if (left_pillar_width > tpg->crop.width)
1577 left_pillar_width = tpg->crop.width;
1578 left_pillar_width = tpg_hscale_div(tpg, p, left_pillar_width);
1579 }
1580 params->left_pillar_width = left_pillar_width;
1581
1582 if (tpg->crop.left + tpg->crop.width >
1583 tpg->border.left + tpg->border.width) {
1584 right_pillar_start =
1585 tpg->border.left + tpg->border.width - tpg->crop.left;
1586 right_pillar_start =
1587 tpg_hscale_div(tpg, p, right_pillar_start);
1588 if (right_pillar_start > params->img_width)
1589 right_pillar_start = params->img_width;
1590 }
1591 params->right_pillar_start = right_pillar_start;
1592
1593 params->sav_eav_f = tpg->field ==
1594 (params->is_60hz ? V4L2_FIELD_TOP : V4L2_FIELD_BOTTOM);
1595}
1596
Hans Verkuil4db22042015-03-07 13:39:01 -03001597void tpg_fill_plane_buffer(struct tpg_data *tpg, v4l2_std_id std, unsigned p, u8 *vbuf)
Hans Verkuil63881df2014-08-25 08:02:14 -03001598{
Hans Verkuil5e729392015-03-09 11:26:43 -03001599 struct tpg_draw_params params;
Hans Verkuilf0ce4fd2015-03-09 11:30:05 -03001600 unsigned mv_hor_old;
1601 unsigned mv_hor_new;
1602 unsigned mv_vert_old;
1603 unsigned mv_vert_new;
Hans Verkuil63881df2014-08-25 08:02:14 -03001604 int h;
Hans Verkuil5e729392015-03-09 11:26:43 -03001605 unsigned twopixsize;
Hans Verkuil280abe42015-03-07 14:50:41 -03001606 unsigned vdiv = tpg->vdownsampling[p];
Hans Verkuil5e729392015-03-09 11:26:43 -03001607 unsigned img_width;
Hans Verkuil63881df2014-08-25 08:02:14 -03001608 unsigned line_offset;
Hans Verkuil5e729392015-03-09 11:26:43 -03001609 unsigned stride;
Hans Verkuil63881df2014-08-25 08:02:14 -03001610 unsigned factor = V4L2_FIELD_HAS_T_OR_B(tpg->field) ? 2 : 1;
1611 u8 *orig_vbuf = vbuf;
1612
1613 /* Coarse scaling with Bresenham */
1614 unsigned int_part = (tpg->crop.height / factor) / tpg->compose.height;
1615 unsigned fract_part = (tpg->crop.height / factor) % tpg->compose.height;
1616 unsigned src_y = 0;
1617 unsigned error = 0;
1618
1619 tpg_recalc(tpg);
1620
Hans Verkuil5e729392015-03-09 11:26:43 -03001621 params.is_tv = std;
1622 params.is_60hz = std & V4L2_STD_525_60;
1623 params.twopixsize = tpg->twopixelsize[p];
1624 params.img_width = tpg_hdiv(tpg, p, tpg->compose.width);
1625 params.stride = tpg->bytesperline[p];
1626 params.hmax = (tpg->compose.height * tpg->perc_fill) / 100;
1627
Hans Verkuilf0ce4fd2015-03-09 11:30:05 -03001628 tpg_fill_params_pattern(tpg, p, &params);
1629
1630 mv_hor_old = params.mv_hor_old;
1631 mv_hor_new = params.mv_hor_new;
1632 mv_vert_old = params.mv_vert_old;
1633 mv_vert_new = params.mv_vert_new;
1634
Hans Verkuil07386b92015-03-09 11:39:19 -03001635 tpg_fill_params_extras(tpg, p, &params);
1636
Hans Verkuil5e729392015-03-09 11:26:43 -03001637 twopixsize = params.twopixsize;
1638 img_width = params.img_width;
1639 stride = params.stride;
1640
Hans Verkuil9991def2015-03-08 05:53:10 -03001641 vbuf += tpg_hdiv(tpg, p, tpg->compose.left);
1642 line_offset = tpg_hscale_div(tpg, p, tpg->crop.left);
Hans Verkuil63881df2014-08-25 08:02:14 -03001643
1644 for (h = 0; h < tpg->compose.height; h++) {
1645 bool even;
1646 bool fill_blank = false;
1647 unsigned frame_line;
1648 unsigned buf_line;
1649 unsigned pat_line_old;
1650 unsigned pat_line_new;
1651 u8 *linestart_older;
1652 u8 *linestart_newer;
1653 u8 *linestart_top;
1654 u8 *linestart_bottom;
1655
1656 frame_line = tpg_calc_frameline(tpg, src_y, tpg->field);
1657 even = !(frame_line & 1);
1658 buf_line = tpg_calc_buffer_line(tpg, h, tpg->field);
1659 src_y += int_part;
1660 error += fract_part;
1661 if (error >= tpg->compose.height) {
1662 error -= tpg->compose.height;
1663 src_y++;
1664 }
1665
Hans Verkuil280abe42015-03-07 14:50:41 -03001666 if (vdiv > 1) {
1667 /*
1668 * When doing vertical downsampling the field setting
1669 * matters: for SEQ_BT/TB we downsample each field
1670 * separately (i.e. lines 0+2 are combined, as are
1671 * lines 1+3), for the other field settings we combine
1672 * odd and even lines. Doing that for SEQ_BT/TB would
1673 * be really weird.
1674 */
1675 if (tpg->field == V4L2_FIELD_SEQ_BT ||
1676 tpg->field == V4L2_FIELD_SEQ_TB) {
1677 if ((h & 3) >= 2)
1678 continue;
1679 } else if (h & 1) {
1680 continue;
1681 }
1682
1683 buf_line /= vdiv;
1684 }
1685
Hans Verkuil5e729392015-03-09 11:26:43 -03001686 if (h >= params.hmax) {
1687 if (params.hmax == tpg->compose.height)
Hans Verkuil63881df2014-08-25 08:02:14 -03001688 continue;
1689 if (!tpg->perc_fill_blank)
1690 continue;
1691 fill_blank = true;
1692 }
1693
1694 if (tpg->vflip)
1695 frame_line = tpg->src_height - frame_line - 1;
1696
1697 if (fill_blank) {
1698 linestart_older = tpg->contrast_line[p];
1699 linestart_newer = tpg->contrast_line[p];
1700 } else if (tpg->qual != TPG_QUAL_NOISE &&
1701 (frame_line < tpg->border.top ||
1702 frame_line >= tpg->border.top + tpg->border.height)) {
1703 linestart_older = tpg->black_line[p];
1704 linestart_newer = tpg->black_line[p];
1705 } else if (tpg->pattern == TPG_PAT_NOISE || tpg->qual == TPG_QUAL_NOISE) {
1706 linestart_older = tpg->random_line[p] +
1707 twopixsize * prandom_u32_max(tpg->src_width / 2);
1708 linestart_newer = tpg->random_line[p] +
1709 twopixsize * prandom_u32_max(tpg->src_width / 2);
1710 } else {
Hans Verkuil280abe42015-03-07 14:50:41 -03001711 unsigned frame_line_old =
1712 (frame_line + mv_vert_old) % tpg->src_height;
1713 unsigned frame_line_new =
1714 (frame_line + mv_vert_new) % tpg->src_height;
1715 unsigned pat_line_next_old;
1716 unsigned pat_line_next_new;
1717
1718 pat_line_old = tpg_get_pat_line(tpg, frame_line_old);
1719 pat_line_new = tpg_get_pat_line(tpg, frame_line_new);
Hans Verkuil9991def2015-03-08 05:53:10 -03001720 linestart_older = tpg->lines[pat_line_old][p] + mv_hor_old;
1721 linestart_newer = tpg->lines[pat_line_new][p] + mv_hor_new;
Hans Verkuil280abe42015-03-07 14:50:41 -03001722
1723 if (vdiv > 1) {
1724 unsigned frame_line_next;
1725 int avg_pat;
1726
1727 /*
1728 * Now decide whether we need to use downsampled_lines[].
1729 * That's necessary if the two lines use different patterns.
1730 */
1731 frame_line_next = tpg_calc_frameline(tpg, src_y, tpg->field);
1732 if (tpg->vflip)
1733 frame_line_next = tpg->src_height - frame_line_next - 1;
1734 pat_line_next_old = tpg_get_pat_line(tpg,
1735 (frame_line_next + mv_vert_old) % tpg->src_height);
1736 pat_line_next_new = tpg_get_pat_line(tpg,
1737 (frame_line_next + mv_vert_new) % tpg->src_height);
1738
1739 switch (tpg->field) {
1740 case V4L2_FIELD_INTERLACED:
1741 case V4L2_FIELD_INTERLACED_BT:
1742 case V4L2_FIELD_INTERLACED_TB:
1743 avg_pat = tpg_pattern_avg(tpg, pat_line_old, pat_line_new);
1744 if (avg_pat < 0)
1745 break;
Hans Verkuil9991def2015-03-08 05:53:10 -03001746 linestart_older = tpg->downsampled_lines[avg_pat][p] + mv_hor_old;
Hans Verkuil280abe42015-03-07 14:50:41 -03001747 linestart_newer = linestart_older;
1748 break;
1749 case V4L2_FIELD_NONE:
1750 case V4L2_FIELD_TOP:
1751 case V4L2_FIELD_BOTTOM:
1752 case V4L2_FIELD_SEQ_BT:
1753 case V4L2_FIELD_SEQ_TB:
1754 avg_pat = tpg_pattern_avg(tpg, pat_line_old, pat_line_next_old);
1755 if (avg_pat >= 0)
1756 linestart_older = tpg->downsampled_lines[avg_pat][p] +
Hans Verkuil9991def2015-03-08 05:53:10 -03001757 mv_hor_old;
Hans Verkuil280abe42015-03-07 14:50:41 -03001758 avg_pat = tpg_pattern_avg(tpg, pat_line_new, pat_line_next_new);
1759 if (avg_pat >= 0)
1760 linestart_newer = tpg->downsampled_lines[avg_pat][p] +
Hans Verkuil9991def2015-03-08 05:53:10 -03001761 mv_hor_new;
Hans Verkuil280abe42015-03-07 14:50:41 -03001762 break;
1763 }
1764 }
Hans Verkuil63881df2014-08-25 08:02:14 -03001765 linestart_older += line_offset;
1766 linestart_newer += line_offset;
1767 }
Hans Verkuil43047f62015-03-07 12:38:42 -03001768 if (tpg->field_alternate) {
1769 linestart_top = linestart_bottom = linestart_older;
Hans Verkuil5e729392015-03-09 11:26:43 -03001770 } else if (params.is_60hz) {
Hans Verkuil63881df2014-08-25 08:02:14 -03001771 linestart_top = linestart_newer;
1772 linestart_bottom = linestart_older;
1773 } else {
1774 linestart_top = linestart_older;
1775 linestart_bottom = linestart_newer;
1776 }
1777
1778 switch (tpg->field) {
1779 case V4L2_FIELD_INTERLACED:
1780 case V4L2_FIELD_INTERLACED_TB:
1781 case V4L2_FIELD_SEQ_TB:
1782 case V4L2_FIELD_SEQ_BT:
1783 if (even)
1784 memcpy(vbuf + buf_line * stride, linestart_top, img_width);
1785 else
1786 memcpy(vbuf + buf_line * stride, linestart_bottom, img_width);
1787 break;
1788 case V4L2_FIELD_INTERLACED_BT:
1789 if (even)
1790 memcpy(vbuf + buf_line * stride, linestart_bottom, img_width);
1791 else
1792 memcpy(vbuf + buf_line * stride, linestart_top, img_width);
1793 break;
1794 case V4L2_FIELD_TOP:
1795 memcpy(vbuf + buf_line * stride, linestart_top, img_width);
1796 break;
1797 case V4L2_FIELD_BOTTOM:
1798 memcpy(vbuf + buf_line * stride, linestart_bottom, img_width);
1799 break;
1800 case V4L2_FIELD_NONE:
1801 default:
1802 memcpy(vbuf + buf_line * stride, linestart_older, img_width);
1803 break;
1804 }
Hans Verkuil63881df2014-08-25 08:02:14 -03001805 }
1806
1807 vbuf = orig_vbuf;
Hans Verkuil9991def2015-03-08 05:53:10 -03001808 vbuf += tpg_hdiv(tpg, p, tpg->compose.left);
Hans Verkuil63881df2014-08-25 08:02:14 -03001809 src_y = 0;
1810 error = 0;
1811 for (h = 0; h < tpg->compose.height; h++) {
1812 unsigned frame_line = tpg_calc_frameline(tpg, src_y, tpg->field);
1813 unsigned buf_line = tpg_calc_buffer_line(tpg, h, tpg->field);
1814 const struct v4l2_rect *sq = &tpg->square;
1815 const struct v4l2_rect *b = &tpg->border;
1816 const struct v4l2_rect *c = &tpg->crop;
1817
1818 src_y += int_part;
1819 error += fract_part;
1820 if (error >= tpg->compose.height) {
1821 error -= tpg->compose.height;
1822 src_y++;
1823 }
1824
Hans Verkuil280abe42015-03-07 14:50:41 -03001825 if (vdiv > 1) {
1826 if (h & 1)
1827 continue;
1828 buf_line /= vdiv;
1829 }
1830
Hans Verkuil07386b92015-03-09 11:39:19 -03001831 if (params.is_tv && !params.is_60hz && frame_line == 0 && params.wss_width) {
Hans Verkuil9991def2015-03-08 05:53:10 -03001832 /*
1833 * Replace the first half of the top line of a 50 Hz frame
1834 * with random data to simulate a WSS signal.
1835 */
Hans Verkuil07386b92015-03-09 11:39:19 -03001836 u8 *wss = tpg->random_line[p] + params.wss_random_offset;
Hans Verkuil9991def2015-03-08 05:53:10 -03001837
Hans Verkuil07386b92015-03-09 11:39:19 -03001838 memcpy(vbuf + buf_line * stride, wss, params.wss_width);
Hans Verkuil9991def2015-03-08 05:53:10 -03001839 }
1840
Hans Verkuil63881df2014-08-25 08:02:14 -03001841 if (tpg->show_border && frame_line >= b->top &&
1842 frame_line < b->top + b->height) {
1843 unsigned bottom = b->top + b->height - 1;
Hans Verkuil07386b92015-03-09 11:39:19 -03001844 unsigned left = params.left_pillar_width;
1845 unsigned right = params.right_pillar_start;
Hans Verkuil63881df2014-08-25 08:02:14 -03001846
1847 if (frame_line == b->top || frame_line == b->top + 1 ||
1848 frame_line == bottom || frame_line == bottom - 1) {
1849 memcpy(vbuf + buf_line * stride + left, tpg->contrast_line[p],
1850 right - left);
1851 } else {
1852 if (b->left >= c->left &&
1853 b->left < c->left + c->width)
1854 memcpy(vbuf + buf_line * stride + left,
1855 tpg->contrast_line[p], twopixsize);
1856 if (b->left + b->width > c->left &&
1857 b->left + b->width <= c->left + c->width)
1858 memcpy(vbuf + buf_line * stride + right - twopixsize,
1859 tpg->contrast_line[p], twopixsize);
1860 }
1861 }
1862 if (tpg->qual != TPG_QUAL_NOISE && frame_line >= b->top &&
1863 frame_line < b->top + b->height) {
Hans Verkuil07386b92015-03-09 11:39:19 -03001864 memcpy(vbuf + buf_line * stride, tpg->black_line[p], params.left_pillar_width);
1865 memcpy(vbuf + buf_line * stride + params.right_pillar_start, tpg->black_line[p],
1866 img_width - params.right_pillar_start);
Hans Verkuil63881df2014-08-25 08:02:14 -03001867 }
1868 if (tpg->show_square && frame_line >= sq->top &&
1869 frame_line < sq->top + sq->height &&
1870 sq->left < c->left + c->width &&
1871 sq->left + sq->width >= c->left) {
1872 unsigned left = sq->left;
1873 unsigned width = sq->width;
1874
1875 if (c->left > left) {
1876 width -= c->left - left;
1877 left = c->left;
1878 }
1879 if (c->left + c->width < left + width)
1880 width -= left + width - c->left - c->width;
1881 left -= c->left;
Hans Verkuil9991def2015-03-08 05:53:10 -03001882 left = tpg_hscale_div(tpg, p, left);
1883 width = tpg_hscale_div(tpg, p, width);
Hans Verkuil63881df2014-08-25 08:02:14 -03001884 memcpy(vbuf + buf_line * stride + left, tpg->contrast_line[p], width);
1885 }
1886 if (tpg->insert_sav) {
Hans Verkuil9991def2015-03-08 05:53:10 -03001887 unsigned offset = tpg_hdiv(tpg, p, tpg->compose.width / 3);
Hans Verkuil63881df2014-08-25 08:02:14 -03001888 u8 *p = vbuf + buf_line * stride + offset;
1889 unsigned vact = 0, hact = 0;
1890
1891 p[0] = 0xff;
1892 p[1] = 0;
1893 p[2] = 0;
Hans Verkuil07386b92015-03-09 11:39:19 -03001894 p[3] = 0x80 | (params.sav_eav_f << 6) |
1895 (vact << 5) | (hact << 4) |
Hans Verkuil63881df2014-08-25 08:02:14 -03001896 ((hact ^ vact) << 3) |
Hans Verkuil07386b92015-03-09 11:39:19 -03001897 ((hact ^ params.sav_eav_f) << 2) |
1898 ((params.sav_eav_f ^ vact) << 1) |
1899 (hact ^ vact ^ params.sav_eav_f);
Hans Verkuil63881df2014-08-25 08:02:14 -03001900 }
1901 if (tpg->insert_eav) {
Hans Verkuil9991def2015-03-08 05:53:10 -03001902 unsigned offset = tpg_hdiv(tpg, p, tpg->compose.width * 2 / 3);
Hans Verkuil63881df2014-08-25 08:02:14 -03001903 u8 *p = vbuf + buf_line * stride + offset;
1904 unsigned vact = 0, hact = 1;
1905
1906 p[0] = 0xff;
1907 p[1] = 0;
1908 p[2] = 0;
Hans Verkuil07386b92015-03-09 11:39:19 -03001909 p[3] = 0x80 | (params.sav_eav_f << 6) |
1910 (vact << 5) | (hact << 4) |
Hans Verkuil63881df2014-08-25 08:02:14 -03001911 ((hact ^ vact) << 3) |
Hans Verkuil07386b92015-03-09 11:39:19 -03001912 ((hact ^ params.sav_eav_f) << 2) |
1913 ((params.sav_eav_f ^ vact) << 1) |
1914 (hact ^ vact ^ params.sav_eav_f);
Hans Verkuil63881df2014-08-25 08:02:14 -03001915 }
1916 }
1917}
Hans Verkuil4db22042015-03-07 13:39:01 -03001918
1919void tpg_fillbuffer(struct tpg_data *tpg, v4l2_std_id std, unsigned p, u8 *vbuf)
1920{
1921 unsigned offset = 0;
1922 unsigned i;
1923
1924 if (tpg->buffers > 1) {
1925 tpg_fill_plane_buffer(tpg, std, p, vbuf);
1926 return;
1927 }
1928
1929 for (i = 0; i < tpg->planes; i++) {
1930 tpg_fill_plane_buffer(tpg, std, i, vbuf + offset);
1931 offset += tpg_calc_plane_size(tpg, i);
1932 }
1933}