blob: b2730bbc96b384107460c2da0a2dd31de07acad4 [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 Verkuil4db22042015-03-07 13:39:01 -03001559void tpg_fill_plane_buffer(struct tpg_data *tpg, v4l2_std_id std, unsigned p, u8 *vbuf)
Hans Verkuil63881df2014-08-25 08:02:14 -03001560{
Hans Verkuil5e729392015-03-09 11:26:43 -03001561 struct tpg_draw_params params;
Hans Verkuilf0ce4fd2015-03-09 11:30:05 -03001562 unsigned mv_hor_old;
1563 unsigned mv_hor_new;
1564 unsigned mv_vert_old;
1565 unsigned mv_vert_new;
Hans Verkuil63881df2014-08-25 08:02:14 -03001566 unsigned wss_width;
1567 unsigned f;
Hans Verkuil63881df2014-08-25 08:02:14 -03001568 int h;
Hans Verkuil5e729392015-03-09 11:26:43 -03001569 unsigned twopixsize;
Hans Verkuil280abe42015-03-07 14:50:41 -03001570 unsigned vdiv = tpg->vdownsampling[p];
Hans Verkuil5e729392015-03-09 11:26:43 -03001571 unsigned img_width;
Hans Verkuil63881df2014-08-25 08:02:14 -03001572 unsigned line_offset;
1573 unsigned left_pillar_width = 0;
Hans Verkuil5e729392015-03-09 11:26:43 -03001574 unsigned right_pillar_start;
1575 unsigned stride;
Hans Verkuil63881df2014-08-25 08:02:14 -03001576 unsigned factor = V4L2_FIELD_HAS_T_OR_B(tpg->field) ? 2 : 1;
1577 u8 *orig_vbuf = vbuf;
1578
1579 /* Coarse scaling with Bresenham */
1580 unsigned int_part = (tpg->crop.height / factor) / tpg->compose.height;
1581 unsigned fract_part = (tpg->crop.height / factor) % tpg->compose.height;
1582 unsigned src_y = 0;
1583 unsigned error = 0;
1584
1585 tpg_recalc(tpg);
1586
Hans Verkuil5e729392015-03-09 11:26:43 -03001587 params.is_tv = std;
1588 params.is_60hz = std & V4L2_STD_525_60;
1589 params.twopixsize = tpg->twopixelsize[p];
1590 params.img_width = tpg_hdiv(tpg, p, tpg->compose.width);
1591 params.stride = tpg->bytesperline[p];
1592 params.hmax = (tpg->compose.height * tpg->perc_fill) / 100;
1593
Hans Verkuilf0ce4fd2015-03-09 11:30:05 -03001594 tpg_fill_params_pattern(tpg, p, &params);
1595
1596 mv_hor_old = params.mv_hor_old;
1597 mv_hor_new = params.mv_hor_new;
1598 mv_vert_old = params.mv_vert_old;
1599 mv_vert_new = params.mv_vert_new;
1600
Hans Verkuil5e729392015-03-09 11:26:43 -03001601 twopixsize = params.twopixsize;
1602 img_width = params.img_width;
1603 stride = params.stride;
1604
Hans Verkuil63881df2014-08-25 08:02:14 -03001605 wss_width = tpg->crop.left < tpg->src_width / 2 ?
1606 tpg->src_width / 2 - tpg->crop.left : 0;
1607 if (wss_width > tpg->crop.width)
1608 wss_width = tpg->crop.width;
Hans Verkuil9991def2015-03-08 05:53:10 -03001609 wss_width = tpg_hscale_div(tpg, p, wss_width);
Hans Verkuil63881df2014-08-25 08:02:14 -03001610
Hans Verkuil9991def2015-03-08 05:53:10 -03001611 vbuf += tpg_hdiv(tpg, p, tpg->compose.left);
1612 line_offset = tpg_hscale_div(tpg, p, tpg->crop.left);
Hans Verkuil63881df2014-08-25 08:02:14 -03001613 if (tpg->crop.left < tpg->border.left) {
1614 left_pillar_width = tpg->border.left - tpg->crop.left;
1615 if (left_pillar_width > tpg->crop.width)
1616 left_pillar_width = tpg->crop.width;
Hans Verkuil9991def2015-03-08 05:53:10 -03001617 left_pillar_width = tpg_hscale_div(tpg, p, left_pillar_width);
Hans Verkuil63881df2014-08-25 08:02:14 -03001618 }
Hans Verkuil5e729392015-03-09 11:26:43 -03001619 right_pillar_start = img_width;
Hans Verkuil63881df2014-08-25 08:02:14 -03001620 if (tpg->crop.left + tpg->crop.width > tpg->border.left + tpg->border.width) {
1621 right_pillar_start = tpg->border.left + tpg->border.width - tpg->crop.left;
Hans Verkuil9991def2015-03-08 05:53:10 -03001622 right_pillar_start = tpg_hscale_div(tpg, p, right_pillar_start);
Hans Verkuil63881df2014-08-25 08:02:14 -03001623 if (right_pillar_start > img_width)
1624 right_pillar_start = img_width;
1625 }
1626
Hans Verkuil5e729392015-03-09 11:26:43 -03001627 f = tpg->field == (params.is_60hz ? V4L2_FIELD_TOP : V4L2_FIELD_BOTTOM);
Hans Verkuil63881df2014-08-25 08:02:14 -03001628
1629 for (h = 0; h < tpg->compose.height; h++) {
1630 bool even;
1631 bool fill_blank = false;
1632 unsigned frame_line;
1633 unsigned buf_line;
1634 unsigned pat_line_old;
1635 unsigned pat_line_new;
1636 u8 *linestart_older;
1637 u8 *linestart_newer;
1638 u8 *linestart_top;
1639 u8 *linestart_bottom;
1640
1641 frame_line = tpg_calc_frameline(tpg, src_y, tpg->field);
1642 even = !(frame_line & 1);
1643 buf_line = tpg_calc_buffer_line(tpg, h, tpg->field);
1644 src_y += int_part;
1645 error += fract_part;
1646 if (error >= tpg->compose.height) {
1647 error -= tpg->compose.height;
1648 src_y++;
1649 }
1650
Hans Verkuil280abe42015-03-07 14:50:41 -03001651 if (vdiv > 1) {
1652 /*
1653 * When doing vertical downsampling the field setting
1654 * matters: for SEQ_BT/TB we downsample each field
1655 * separately (i.e. lines 0+2 are combined, as are
1656 * lines 1+3), for the other field settings we combine
1657 * odd and even lines. Doing that for SEQ_BT/TB would
1658 * be really weird.
1659 */
1660 if (tpg->field == V4L2_FIELD_SEQ_BT ||
1661 tpg->field == V4L2_FIELD_SEQ_TB) {
1662 if ((h & 3) >= 2)
1663 continue;
1664 } else if (h & 1) {
1665 continue;
1666 }
1667
1668 buf_line /= vdiv;
1669 }
1670
Hans Verkuil5e729392015-03-09 11:26:43 -03001671 if (h >= params.hmax) {
1672 if (params.hmax == tpg->compose.height)
Hans Verkuil63881df2014-08-25 08:02:14 -03001673 continue;
1674 if (!tpg->perc_fill_blank)
1675 continue;
1676 fill_blank = true;
1677 }
1678
1679 if (tpg->vflip)
1680 frame_line = tpg->src_height - frame_line - 1;
1681
1682 if (fill_blank) {
1683 linestart_older = tpg->contrast_line[p];
1684 linestart_newer = tpg->contrast_line[p];
1685 } else if (tpg->qual != TPG_QUAL_NOISE &&
1686 (frame_line < tpg->border.top ||
1687 frame_line >= tpg->border.top + tpg->border.height)) {
1688 linestart_older = tpg->black_line[p];
1689 linestart_newer = tpg->black_line[p];
1690 } else if (tpg->pattern == TPG_PAT_NOISE || tpg->qual == TPG_QUAL_NOISE) {
1691 linestart_older = tpg->random_line[p] +
1692 twopixsize * prandom_u32_max(tpg->src_width / 2);
1693 linestart_newer = tpg->random_line[p] +
1694 twopixsize * prandom_u32_max(tpg->src_width / 2);
1695 } else {
Hans Verkuil280abe42015-03-07 14:50:41 -03001696 unsigned frame_line_old =
1697 (frame_line + mv_vert_old) % tpg->src_height;
1698 unsigned frame_line_new =
1699 (frame_line + mv_vert_new) % tpg->src_height;
1700 unsigned pat_line_next_old;
1701 unsigned pat_line_next_new;
1702
1703 pat_line_old = tpg_get_pat_line(tpg, frame_line_old);
1704 pat_line_new = tpg_get_pat_line(tpg, frame_line_new);
Hans Verkuil9991def2015-03-08 05:53:10 -03001705 linestart_older = tpg->lines[pat_line_old][p] + mv_hor_old;
1706 linestart_newer = tpg->lines[pat_line_new][p] + mv_hor_new;
Hans Verkuil280abe42015-03-07 14:50:41 -03001707
1708 if (vdiv > 1) {
1709 unsigned frame_line_next;
1710 int avg_pat;
1711
1712 /*
1713 * Now decide whether we need to use downsampled_lines[].
1714 * That's necessary if the two lines use different patterns.
1715 */
1716 frame_line_next = tpg_calc_frameline(tpg, src_y, tpg->field);
1717 if (tpg->vflip)
1718 frame_line_next = tpg->src_height - frame_line_next - 1;
1719 pat_line_next_old = tpg_get_pat_line(tpg,
1720 (frame_line_next + mv_vert_old) % tpg->src_height);
1721 pat_line_next_new = tpg_get_pat_line(tpg,
1722 (frame_line_next + mv_vert_new) % tpg->src_height);
1723
1724 switch (tpg->field) {
1725 case V4L2_FIELD_INTERLACED:
1726 case V4L2_FIELD_INTERLACED_BT:
1727 case V4L2_FIELD_INTERLACED_TB:
1728 avg_pat = tpg_pattern_avg(tpg, pat_line_old, pat_line_new);
1729 if (avg_pat < 0)
1730 break;
Hans Verkuil9991def2015-03-08 05:53:10 -03001731 linestart_older = tpg->downsampled_lines[avg_pat][p] + mv_hor_old;
Hans Verkuil280abe42015-03-07 14:50:41 -03001732 linestart_newer = linestart_older;
1733 break;
1734 case V4L2_FIELD_NONE:
1735 case V4L2_FIELD_TOP:
1736 case V4L2_FIELD_BOTTOM:
1737 case V4L2_FIELD_SEQ_BT:
1738 case V4L2_FIELD_SEQ_TB:
1739 avg_pat = tpg_pattern_avg(tpg, pat_line_old, pat_line_next_old);
1740 if (avg_pat >= 0)
1741 linestart_older = tpg->downsampled_lines[avg_pat][p] +
Hans Verkuil9991def2015-03-08 05:53:10 -03001742 mv_hor_old;
Hans Verkuil280abe42015-03-07 14:50:41 -03001743 avg_pat = tpg_pattern_avg(tpg, pat_line_new, pat_line_next_new);
1744 if (avg_pat >= 0)
1745 linestart_newer = tpg->downsampled_lines[avg_pat][p] +
Hans Verkuil9991def2015-03-08 05:53:10 -03001746 mv_hor_new;
Hans Verkuil280abe42015-03-07 14:50:41 -03001747 break;
1748 }
1749 }
Hans Verkuil63881df2014-08-25 08:02:14 -03001750 linestart_older += line_offset;
1751 linestart_newer += line_offset;
1752 }
Hans Verkuil43047f62015-03-07 12:38:42 -03001753 if (tpg->field_alternate) {
1754 linestart_top = linestart_bottom = linestart_older;
Hans Verkuil5e729392015-03-09 11:26:43 -03001755 } else if (params.is_60hz) {
Hans Verkuil63881df2014-08-25 08:02:14 -03001756 linestart_top = linestart_newer;
1757 linestart_bottom = linestart_older;
1758 } else {
1759 linestart_top = linestart_older;
1760 linestart_bottom = linestart_newer;
1761 }
1762
1763 switch (tpg->field) {
1764 case V4L2_FIELD_INTERLACED:
1765 case V4L2_FIELD_INTERLACED_TB:
1766 case V4L2_FIELD_SEQ_TB:
1767 case V4L2_FIELD_SEQ_BT:
1768 if (even)
1769 memcpy(vbuf + buf_line * stride, linestart_top, img_width);
1770 else
1771 memcpy(vbuf + buf_line * stride, linestart_bottom, img_width);
1772 break;
1773 case V4L2_FIELD_INTERLACED_BT:
1774 if (even)
1775 memcpy(vbuf + buf_line * stride, linestart_bottom, img_width);
1776 else
1777 memcpy(vbuf + buf_line * stride, linestart_top, img_width);
1778 break;
1779 case V4L2_FIELD_TOP:
1780 memcpy(vbuf + buf_line * stride, linestart_top, img_width);
1781 break;
1782 case V4L2_FIELD_BOTTOM:
1783 memcpy(vbuf + buf_line * stride, linestart_bottom, img_width);
1784 break;
1785 case V4L2_FIELD_NONE:
1786 default:
1787 memcpy(vbuf + buf_line * stride, linestart_older, img_width);
1788 break;
1789 }
Hans Verkuil63881df2014-08-25 08:02:14 -03001790 }
1791
1792 vbuf = orig_vbuf;
Hans Verkuil9991def2015-03-08 05:53:10 -03001793 vbuf += tpg_hdiv(tpg, p, tpg->compose.left);
Hans Verkuil63881df2014-08-25 08:02:14 -03001794 src_y = 0;
1795 error = 0;
1796 for (h = 0; h < tpg->compose.height; h++) {
1797 unsigned frame_line = tpg_calc_frameline(tpg, src_y, tpg->field);
1798 unsigned buf_line = tpg_calc_buffer_line(tpg, h, tpg->field);
1799 const struct v4l2_rect *sq = &tpg->square;
1800 const struct v4l2_rect *b = &tpg->border;
1801 const struct v4l2_rect *c = &tpg->crop;
1802
1803 src_y += int_part;
1804 error += fract_part;
1805 if (error >= tpg->compose.height) {
1806 error -= tpg->compose.height;
1807 src_y++;
1808 }
1809
Hans Verkuil280abe42015-03-07 14:50:41 -03001810 if (vdiv > 1) {
1811 if (h & 1)
1812 continue;
1813 buf_line /= vdiv;
1814 }
1815
Hans Verkuil5e729392015-03-09 11:26:43 -03001816 if (params.is_tv && !params.is_60hz && frame_line == 0 && wss_width) {
Hans Verkuil9991def2015-03-08 05:53:10 -03001817 /*
1818 * Replace the first half of the top line of a 50 Hz frame
1819 * with random data to simulate a WSS signal.
1820 */
1821 u8 *wss = tpg->random_line[p] +
1822 twopixsize * prandom_u32_max(tpg->src_width / 2);
1823
1824 memcpy(vbuf + buf_line * stride, wss, wss_width);
1825 }
1826
Hans Verkuil63881df2014-08-25 08:02:14 -03001827 if (tpg->show_border && frame_line >= b->top &&
1828 frame_line < b->top + b->height) {
1829 unsigned bottom = b->top + b->height - 1;
1830 unsigned left = left_pillar_width;
1831 unsigned right = right_pillar_start;
1832
1833 if (frame_line == b->top || frame_line == b->top + 1 ||
1834 frame_line == bottom || frame_line == bottom - 1) {
1835 memcpy(vbuf + buf_line * stride + left, tpg->contrast_line[p],
1836 right - left);
1837 } else {
1838 if (b->left >= c->left &&
1839 b->left < c->left + c->width)
1840 memcpy(vbuf + buf_line * stride + left,
1841 tpg->contrast_line[p], twopixsize);
1842 if (b->left + b->width > c->left &&
1843 b->left + b->width <= c->left + c->width)
1844 memcpy(vbuf + buf_line * stride + right - twopixsize,
1845 tpg->contrast_line[p], twopixsize);
1846 }
1847 }
1848 if (tpg->qual != TPG_QUAL_NOISE && frame_line >= b->top &&
1849 frame_line < b->top + b->height) {
1850 memcpy(vbuf + buf_line * stride, tpg->black_line[p], left_pillar_width);
1851 memcpy(vbuf + buf_line * stride + right_pillar_start, tpg->black_line[p],
1852 img_width - right_pillar_start);
1853 }
1854 if (tpg->show_square && frame_line >= sq->top &&
1855 frame_line < sq->top + sq->height &&
1856 sq->left < c->left + c->width &&
1857 sq->left + sq->width >= c->left) {
1858 unsigned left = sq->left;
1859 unsigned width = sq->width;
1860
1861 if (c->left > left) {
1862 width -= c->left - left;
1863 left = c->left;
1864 }
1865 if (c->left + c->width < left + width)
1866 width -= left + width - c->left - c->width;
1867 left -= c->left;
Hans Verkuil9991def2015-03-08 05:53:10 -03001868 left = tpg_hscale_div(tpg, p, left);
1869 width = tpg_hscale_div(tpg, p, width);
Hans Verkuil63881df2014-08-25 08:02:14 -03001870 memcpy(vbuf + buf_line * stride + left, tpg->contrast_line[p], width);
1871 }
1872 if (tpg->insert_sav) {
Hans Verkuil9991def2015-03-08 05:53:10 -03001873 unsigned offset = tpg_hdiv(tpg, p, tpg->compose.width / 3);
Hans Verkuil63881df2014-08-25 08:02:14 -03001874 u8 *p = vbuf + buf_line * stride + offset;
1875 unsigned vact = 0, hact = 0;
1876
1877 p[0] = 0xff;
1878 p[1] = 0;
1879 p[2] = 0;
1880 p[3] = 0x80 | (f << 6) | (vact << 5) | (hact << 4) |
1881 ((hact ^ vact) << 3) |
1882 ((hact ^ f) << 2) |
1883 ((f ^ vact) << 1) |
1884 (hact ^ vact ^ f);
1885 }
1886 if (tpg->insert_eav) {
Hans Verkuil9991def2015-03-08 05:53:10 -03001887 unsigned offset = tpg_hdiv(tpg, p, tpg->compose.width * 2 / 3);
Hans Verkuil63881df2014-08-25 08:02:14 -03001888 u8 *p = vbuf + buf_line * stride + offset;
1889 unsigned vact = 0, hact = 1;
1890
1891 p[0] = 0xff;
1892 p[1] = 0;
1893 p[2] = 0;
1894 p[3] = 0x80 | (f << 6) | (vact << 5) | (hact << 4) |
1895 ((hact ^ vact) << 3) |
1896 ((hact ^ f) << 2) |
1897 ((f ^ vact) << 1) |
1898 (hact ^ vact ^ f);
1899 }
1900 }
1901}
Hans Verkuil4db22042015-03-07 13:39:01 -03001902
1903void tpg_fillbuffer(struct tpg_data *tpg, v4l2_std_id std, unsigned p, u8 *vbuf)
1904{
1905 unsigned offset = 0;
1906 unsigned i;
1907
1908 if (tpg->buffers > 1) {
1909 tpg_fill_plane_buffer(tpg, std, p, vbuf);
1910 return;
1911 }
1912
1913 for (i = 0; i < tpg->planes; i++) {
1914 tpg_fill_plane_buffer(tpg, std, i, vbuf + offset);
1915 offset += tpg_calc_plane_size(tpg, i);
1916 }
1917}