blob: 0d31532f7f42faebfedf9e9eebcc76c5e656fa58 [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++) {
Hans Verkuildde72bd2015-03-13 05:51:21 -0300126 unsigned pixelsz = plane ? 2 : 4;
Hans Verkuil63881df2014-08-25 08:02:14 -0300127
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++) {
Hans Verkuildde72bd2015-03-13 05:51:21 -0300139 unsigned pixelsz = plane ? 2 : 4;
Hans Verkuil63881df2014-08-25 08:02:14 -0300140
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:
Hans Verkuil8aca2302015-03-11 08:14:34 -0300193 case V4L2_PIX_FMT_RGB444:
194 case V4L2_PIX_FMT_XRGB444:
195 case V4L2_PIX_FMT_ARGB444:
Hans Verkuil63881df2014-08-25 08:02:14 -0300196 case V4L2_PIX_FMT_RGB555:
197 case V4L2_PIX_FMT_XRGB555:
198 case V4L2_PIX_FMT_ARGB555:
199 case V4L2_PIX_FMT_RGB555X:
Hans Verkuil8f1ff542015-03-12 05:08:01 -0300200 case V4L2_PIX_FMT_XRGB555X:
201 case V4L2_PIX_FMT_ARGB555X:
Hans Verkuil63881df2014-08-25 08:02:14 -0300202 case V4L2_PIX_FMT_RGB24:
203 case V4L2_PIX_FMT_BGR24:
204 case V4L2_PIX_FMT_RGB32:
205 case V4L2_PIX_FMT_BGR32:
206 case V4L2_PIX_FMT_XRGB32:
207 case V4L2_PIX_FMT_XBGR32:
208 case V4L2_PIX_FMT_ARGB32:
209 case V4L2_PIX_FMT_ABGR32:
Hans Verkuil51f30962015-03-07 14:57:50 -0300210 case V4L2_PIX_FMT_GREY:
Mauro Carvalho Chehab6c515a42014-09-03 15:53:45 -0300211 tpg->is_yuv = false;
Hans Verkuil63881df2014-08-25 08:02:14 -0300212 break;
Hans Verkuil68c90d62015-03-07 14:55:09 -0300213 case V4L2_PIX_FMT_YUV420M:
214 case V4L2_PIX_FMT_YVU420M:
215 tpg->buffers = 3;
216 /* fall through */
217 case V4L2_PIX_FMT_YUV420:
218 case V4L2_PIX_FMT_YVU420:
219 tpg->vdownsampling[1] = 2;
220 tpg->vdownsampling[2] = 2;
221 tpg->hdownsampling[1] = 2;
222 tpg->hdownsampling[2] = 2;
223 tpg->planes = 3;
224 tpg->is_yuv = true;
225 break;
226 case V4L2_PIX_FMT_YUV422P:
227 tpg->vdownsampling[1] = 1;
228 tpg->vdownsampling[2] = 1;
229 tpg->hdownsampling[1] = 2;
230 tpg->hdownsampling[2] = 2;
231 tpg->planes = 3;
232 tpg->is_yuv = true;
233 break;
Hans Verkuil63881df2014-08-25 08:02:14 -0300234 case V4L2_PIX_FMT_NV16M:
235 case V4L2_PIX_FMT_NV61M:
Hans Verkuil68c90d62015-03-07 14:55:09 -0300236 tpg->buffers = 2;
237 /* fall through */
238 case V4L2_PIX_FMT_NV16:
239 case V4L2_PIX_FMT_NV61:
Hans Verkuilba01f672015-03-07 13:57:27 -0300240 tpg->vdownsampling[1] = 1;
241 tpg->hdownsampling[1] = 1;
Hans Verkuil9991def2015-03-08 05:53:10 -0300242 tpg->hmask[1] = ~1;
Hans Verkuil63881df2014-08-25 08:02:14 -0300243 tpg->planes = 2;
Hans Verkuil68c90d62015-03-07 14:55:09 -0300244 tpg->is_yuv = true;
245 break;
246 case V4L2_PIX_FMT_NV12M:
247 case V4L2_PIX_FMT_NV21M:
248 tpg->buffers = 2;
249 /* fall through */
250 case V4L2_PIX_FMT_NV12:
251 case V4L2_PIX_FMT_NV21:
252 tpg->vdownsampling[1] = 2;
253 tpg->hdownsampling[1] = 1;
Hans Verkuil9991def2015-03-08 05:53:10 -0300254 tpg->hmask[1] = ~1;
Hans Verkuil68c90d62015-03-07 14:55:09 -0300255 tpg->planes = 2;
256 tpg->is_yuv = true;
257 break;
Hans Verkuildde72bd2015-03-13 05:51:21 -0300258 case V4L2_PIX_FMT_NV24:
259 case V4L2_PIX_FMT_NV42:
260 tpg->vdownsampling[1] = 1;
261 tpg->hdownsampling[1] = 1;
262 tpg->planes = 2;
263 tpg->is_yuv = true;
264 break;
Hans Verkuil63881df2014-08-25 08:02:14 -0300265 case V4L2_PIX_FMT_YUYV:
266 case V4L2_PIX_FMT_UYVY:
267 case V4L2_PIX_FMT_YVYU:
268 case V4L2_PIX_FMT_VYUY:
Hans Verkuil9991def2015-03-08 05:53:10 -0300269 tpg->hmask[0] = ~1;
Mauro Carvalho Chehab6c515a42014-09-03 15:53:45 -0300270 tpg->is_yuv = true;
Hans Verkuil63881df2014-08-25 08:02:14 -0300271 break;
272 default:
273 return false;
274 }
275
276 switch (fourcc) {
277 case V4L2_PIX_FMT_RGB565:
278 case V4L2_PIX_FMT_RGB565X:
Hans Verkuil8aca2302015-03-11 08:14:34 -0300279 case V4L2_PIX_FMT_RGB444:
280 case V4L2_PIX_FMT_XRGB444:
281 case V4L2_PIX_FMT_ARGB444:
Hans Verkuil63881df2014-08-25 08:02:14 -0300282 case V4L2_PIX_FMT_RGB555:
283 case V4L2_PIX_FMT_XRGB555:
284 case V4L2_PIX_FMT_ARGB555:
285 case V4L2_PIX_FMT_RGB555X:
Hans Verkuil8f1ff542015-03-12 05:08:01 -0300286 case V4L2_PIX_FMT_XRGB555X:
287 case V4L2_PIX_FMT_ARGB555X:
Hans Verkuil63881df2014-08-25 08:02:14 -0300288 case V4L2_PIX_FMT_YUYV:
289 case V4L2_PIX_FMT_UYVY:
290 case V4L2_PIX_FMT_YVYU:
291 case V4L2_PIX_FMT_VYUY:
292 tpg->twopixelsize[0] = 2 * 2;
293 break;
294 case V4L2_PIX_FMT_RGB24:
295 case V4L2_PIX_FMT_BGR24:
296 tpg->twopixelsize[0] = 2 * 3;
297 break;
298 case V4L2_PIX_FMT_RGB32:
299 case V4L2_PIX_FMT_BGR32:
300 case V4L2_PIX_FMT_XRGB32:
301 case V4L2_PIX_FMT_XBGR32:
302 case V4L2_PIX_FMT_ARGB32:
303 case V4L2_PIX_FMT_ABGR32:
304 tpg->twopixelsize[0] = 2 * 4;
305 break;
Hans Verkuil51f30962015-03-07 14:57:50 -0300306 case V4L2_PIX_FMT_GREY:
307 tpg->twopixelsize[0] = 2;
308 break;
Hans Verkuil68c90d62015-03-07 14:55:09 -0300309 case V4L2_PIX_FMT_NV12:
310 case V4L2_PIX_FMT_NV21:
311 case V4L2_PIX_FMT_NV12M:
312 case V4L2_PIX_FMT_NV21M:
313 tpg->twopixelsize[0] = 2;
314 tpg->twopixelsize[1] = 2;
315 break;
316 case V4L2_PIX_FMT_NV16:
317 case V4L2_PIX_FMT_NV61:
Hans Verkuil63881df2014-08-25 08:02:14 -0300318 case V4L2_PIX_FMT_NV16M:
319 case V4L2_PIX_FMT_NV61M:
320 tpg->twopixelsize[0] = 2;
321 tpg->twopixelsize[1] = 2;
322 break;
Hans Verkuil68c90d62015-03-07 14:55:09 -0300323 case V4L2_PIX_FMT_YUV422P:
324 case V4L2_PIX_FMT_YUV420:
325 case V4L2_PIX_FMT_YVU420:
326 case V4L2_PIX_FMT_YUV420M:
327 case V4L2_PIX_FMT_YVU420M:
328 tpg->twopixelsize[0] = 2;
329 tpg->twopixelsize[1] = 2;
330 tpg->twopixelsize[2] = 2;
331 break;
Hans Verkuildde72bd2015-03-13 05:51:21 -0300332 case V4L2_PIX_FMT_NV24:
333 case V4L2_PIX_FMT_NV42:
334 tpg->twopixelsize[0] = 2;
335 tpg->twopixelsize[1] = 4;
336 break;
Hans Verkuil63881df2014-08-25 08:02:14 -0300337 }
338 return true;
339}
340
341void tpg_s_crop_compose(struct tpg_data *tpg, const struct v4l2_rect *crop,
342 const struct v4l2_rect *compose)
343{
344 tpg->crop = *crop;
345 tpg->compose = *compose;
346 tpg->scaled_width = (tpg->src_width * tpg->compose.width +
347 tpg->crop.width - 1) / tpg->crop.width;
348 tpg->scaled_width &= ~1;
349 if (tpg->scaled_width > tpg->max_line_width)
350 tpg->scaled_width = tpg->max_line_width;
351 if (tpg->scaled_width < 2)
352 tpg->scaled_width = 2;
353 tpg->recalc_lines = true;
354}
355
356void tpg_reset_source(struct tpg_data *tpg, unsigned width, unsigned height,
Hans Verkuil73d81022014-09-03 10:18:57 -0300357 u32 field)
Hans Verkuil63881df2014-08-25 08:02:14 -0300358{
359 unsigned p;
360
361 tpg->src_width = width;
362 tpg->src_height = height;
363 tpg->field = field;
364 tpg->buf_height = height;
365 if (V4L2_FIELD_HAS_T_OR_B(field))
366 tpg->buf_height /= 2;
367 tpg->scaled_width = width;
368 tpg->crop.top = tpg->crop.left = 0;
369 tpg->crop.width = width;
370 tpg->crop.height = height;
371 tpg->compose.top = tpg->compose.left = 0;
372 tpg->compose.width = width;
373 tpg->compose.height = tpg->buf_height;
374 for (p = 0; p < tpg->planes; p++)
Hans Verkuilba01f672015-03-07 13:57:27 -0300375 tpg->bytesperline[p] = (width * tpg->twopixelsize[p]) /
376 (2 * tpg->hdownsampling[p]);
Hans Verkuil63881df2014-08-25 08:02:14 -0300377 tpg->recalc_square_border = true;
378}
379
380static enum tpg_color tpg_get_textbg_color(struct tpg_data *tpg)
381{
382 switch (tpg->pattern) {
383 case TPG_PAT_BLACK:
384 return TPG_COLOR_100_WHITE;
385 case TPG_PAT_CSC_COLORBAR:
386 return TPG_COLOR_CSC_BLACK;
387 default:
388 return TPG_COLOR_100_BLACK;
389 }
390}
391
392static enum tpg_color tpg_get_textfg_color(struct tpg_data *tpg)
393{
394 switch (tpg->pattern) {
395 case TPG_PAT_75_COLORBAR:
396 case TPG_PAT_CSC_COLORBAR:
397 return TPG_COLOR_CSC_WHITE;
398 case TPG_PAT_BLACK:
399 return TPG_COLOR_100_BLACK;
400 default:
401 return TPG_COLOR_100_WHITE;
402 }
403}
404
Hans Verkuil481b97a2014-11-17 10:14:32 -0300405static inline int rec709_to_linear(int v)
Hans Verkuil63881df2014-08-25 08:02:14 -0300406{
Hans Verkuil481b97a2014-11-17 10:14:32 -0300407 v = clamp(v, 0, 0xff0);
408 return tpg_rec709_to_linear[v];
409}
410
411static inline int linear_to_rec709(int v)
412{
413 v = clamp(v, 0, 0xff0);
414 return tpg_linear_to_rec709[v];
415}
416
417static void rgb2ycbcr(const int m[3][3], int r, int g, int b,
418 int y_offset, int *y, int *cb, int *cr)
419{
420 *y = ((m[0][0] * r + m[0][1] * g + m[0][2] * b) >> 16) + (y_offset << 4);
421 *cb = ((m[1][0] * r + m[1][1] * g + m[1][2] * b) >> 16) + (128 << 4);
422 *cr = ((m[2][0] * r + m[2][1] * g + m[2][2] * b) >> 16) + (128 << 4);
423}
424
425static void color_to_ycbcr(struct tpg_data *tpg, int r, int g, int b,
426 int *y, int *cb, int *cr)
427{
428#define COEFF(v, r) ((int)(0.5 + (v) * (r) * 256.0))
429
430 static const int bt601[3][3] = {
431 { COEFF(0.299, 219), COEFF(0.587, 219), COEFF(0.114, 219) },
432 { COEFF(-0.169, 224), COEFF(-0.331, 224), COEFF(0.5, 224) },
433 { COEFF(0.5, 224), COEFF(-0.419, 224), COEFF(-0.081, 224) },
434 };
435 static const int bt601_full[3][3] = {
436 { COEFF(0.299, 255), COEFF(0.587, 255), COEFF(0.114, 255) },
437 { COEFF(-0.169, 255), COEFF(-0.331, 255), COEFF(0.5, 255) },
438 { COEFF(0.5, 255), COEFF(-0.419, 255), COEFF(-0.081, 255) },
439 };
440 static const int rec709[3][3] = {
441 { COEFF(0.2126, 219), COEFF(0.7152, 219), COEFF(0.0722, 219) },
442 { COEFF(-0.1146, 224), COEFF(-0.3854, 224), COEFF(0.5, 224) },
443 { COEFF(0.5, 224), COEFF(-0.4542, 224), COEFF(-0.0458, 224) },
444 };
445 static const int rec709_full[3][3] = {
446 { COEFF(0.2126, 255), COEFF(0.7152, 255), COEFF(0.0722, 255) },
447 { COEFF(-0.1146, 255), COEFF(-0.3854, 255), COEFF(0.5, 255) },
448 { COEFF(0.5, 255), COEFF(-0.4542, 255), COEFF(-0.0458, 255) },
449 };
450 static const int smpte240m[3][3] = {
451 { COEFF(0.212, 219), COEFF(0.701, 219), COEFF(0.087, 219) },
452 { COEFF(-0.116, 224), COEFF(-0.384, 224), COEFF(0.5, 224) },
453 { COEFF(0.5, 224), COEFF(-0.445, 224), COEFF(-0.055, 224) },
454 };
455 static const int bt2020[3][3] = {
456 { COEFF(0.2726, 219), COEFF(0.6780, 219), COEFF(0.0593, 219) },
457 { COEFF(-0.1396, 224), COEFF(-0.3604, 224), COEFF(0.5, 224) },
458 { COEFF(0.5, 224), COEFF(-0.4629, 224), COEFF(-0.0405, 224) },
459 };
460 bool full = tpg->real_quantization == V4L2_QUANTIZATION_FULL_RANGE;
Hans Verkuilafad4dd2015-01-27 13:46:17 -0300461 unsigned y_offset = full ? 0 : 16;
Hans Verkuil481b97a2014-11-17 10:14:32 -0300462 int lin_y, yc;
463
464 switch (tpg->real_ycbcr_enc) {
465 case V4L2_YCBCR_ENC_601:
466 case V4L2_YCBCR_ENC_XV601:
467 case V4L2_YCBCR_ENC_SYCC:
Hans Verkuilafad4dd2015-01-27 13:46:17 -0300468 rgb2ycbcr(full ? bt601_full : bt601, r, g, b, y_offset, y, cb, cr);
Hans Verkuil481b97a2014-11-17 10:14:32 -0300469 break;
470 case V4L2_YCBCR_ENC_BT2020:
471 rgb2ycbcr(bt2020, r, g, b, 16, y, cb, cr);
472 break;
473 case V4L2_YCBCR_ENC_BT2020_CONST_LUM:
474 lin_y = (COEFF(0.2627, 255) * rec709_to_linear(r) +
475 COEFF(0.6780, 255) * rec709_to_linear(g) +
476 COEFF(0.0593, 255) * rec709_to_linear(b)) >> 16;
477 yc = linear_to_rec709(lin_y);
478 *y = (yc * 219) / 255 + (16 << 4);
479 if (b <= yc)
480 *cb = (((b - yc) * COEFF(1.0 / 1.9404, 224)) >> 16) + (128 << 4);
481 else
482 *cb = (((b - yc) * COEFF(1.0 / 1.5816, 224)) >> 16) + (128 << 4);
483 if (r <= yc)
484 *cr = (((r - yc) * COEFF(1.0 / 1.7184, 224)) >> 16) + (128 << 4);
485 else
486 *cr = (((r - yc) * COEFF(1.0 / 0.9936, 224)) >> 16) + (128 << 4);
487 break;
488 case V4L2_YCBCR_ENC_SMPTE240M:
489 rgb2ycbcr(smpte240m, r, g, b, 16, y, cb, cr);
490 break;
491 case V4L2_YCBCR_ENC_709:
492 case V4L2_YCBCR_ENC_XV709:
Hans Verkuil63881df2014-08-25 08:02:14 -0300493 default:
Hans Verkuilafad4dd2015-01-27 13:46:17 -0300494 rgb2ycbcr(full ? rec709_full : rec709, r, g, b, y_offset, y, cb, cr);
Hans Verkuil481b97a2014-11-17 10:14:32 -0300495 break;
Hans Verkuil63881df2014-08-25 08:02:14 -0300496 }
497}
498
Hans Verkuil481b97a2014-11-17 10:14:32 -0300499static void ycbcr2rgb(const int m[3][3], int y, int cb, int cr,
500 int y_offset, int *r, int *g, int *b)
Hans Verkuil63881df2014-08-25 08:02:14 -0300501{
Hans Verkuil481b97a2014-11-17 10:14:32 -0300502 y -= y_offset << 4;
Hans Verkuil63881df2014-08-25 08:02:14 -0300503 cb -= 128 << 4;
504 cr -= 128 << 4;
Hans Verkuil481b97a2014-11-17 10:14:32 -0300505 *r = m[0][0] * y + m[0][1] * cb + m[0][2] * cr;
506 *g = m[1][0] * y + m[1][1] * cb + m[1][2] * cr;
507 *b = m[2][0] * y + m[2][1] * cb + m[2][2] * cr;
508 *r = clamp(*r >> 12, 0, 0xff0);
509 *g = clamp(*g >> 12, 0, 0xff0);
510 *b = clamp(*b >> 12, 0, 0xff0);
Hans Verkuil63881df2014-08-25 08:02:14 -0300511}
512
Hans Verkuil481b97a2014-11-17 10:14:32 -0300513static void ycbcr_to_color(struct tpg_data *tpg, int y, int cb, int cr,
514 int *r, int *g, int *b)
Hans Verkuil63881df2014-08-25 08:02:14 -0300515{
Hans Verkuil481b97a2014-11-17 10:14:32 -0300516#undef COEFF
517#define COEFF(v, r) ((int)(0.5 + (v) * ((255.0 * 255.0 * 16.0) / (r))))
518 static const int bt601[3][3] = {
519 { COEFF(1, 219), COEFF(0, 224), COEFF(1.4020, 224) },
520 { COEFF(1, 219), COEFF(-0.3441, 224), COEFF(-0.7141, 224) },
521 { COEFF(1, 219), COEFF(1.7720, 224), COEFF(0, 224) },
522 };
523 static const int bt601_full[3][3] = {
524 { COEFF(1, 255), COEFF(0, 255), COEFF(1.4020, 255) },
525 { COEFF(1, 255), COEFF(-0.3441, 255), COEFF(-0.7141, 255) },
526 { COEFF(1, 255), COEFF(1.7720, 255), COEFF(0, 255) },
527 };
528 static const int rec709[3][3] = {
529 { COEFF(1, 219), COEFF(0, 224), COEFF(1.5748, 224) },
530 { COEFF(1, 219), COEFF(-0.1873, 224), COEFF(-0.4681, 224) },
531 { COEFF(1, 219), COEFF(1.8556, 224), COEFF(0, 224) },
532 };
533 static const int rec709_full[3][3] = {
534 { COEFF(1, 255), COEFF(0, 255), COEFF(1.5748, 255) },
535 { COEFF(1, 255), COEFF(-0.1873, 255), COEFF(-0.4681, 255) },
536 { COEFF(1, 255), COEFF(1.8556, 255), COEFF(0, 255) },
537 };
538 static const int smpte240m[3][3] = {
539 { COEFF(1, 219), COEFF(0, 224), COEFF(1.5756, 224) },
540 { COEFF(1, 219), COEFF(-0.2253, 224), COEFF(-0.4767, 224) },
541 { COEFF(1, 219), COEFF(1.8270, 224), COEFF(0, 224) },
542 };
543 static const int bt2020[3][3] = {
544 { COEFF(1, 219), COEFF(0, 224), COEFF(1.4746, 224) },
545 { COEFF(1, 219), COEFF(-0.1646, 224), COEFF(-0.5714, 224) },
546 { COEFF(1, 219), COEFF(1.8814, 224), COEFF(0, 224) },
547 };
548 bool full = tpg->real_quantization == V4L2_QUANTIZATION_FULL_RANGE;
Hans Verkuilafad4dd2015-01-27 13:46:17 -0300549 unsigned y_offset = full ? 0 : 16;
Hans Verkuil481b97a2014-11-17 10:14:32 -0300550 int lin_r, lin_g, lin_b, lin_y;
Hans Verkuil63881df2014-08-25 08:02:14 -0300551
Hans Verkuil481b97a2014-11-17 10:14:32 -0300552 switch (tpg->real_ycbcr_enc) {
553 case V4L2_YCBCR_ENC_601:
554 case V4L2_YCBCR_ENC_XV601:
555 case V4L2_YCBCR_ENC_SYCC:
Hans Verkuilafad4dd2015-01-27 13:46:17 -0300556 ycbcr2rgb(full ? bt601_full : bt601, y, cb, cr, y_offset, r, g, b);
Hans Verkuil63881df2014-08-25 08:02:14 -0300557 break;
Hans Verkuil481b97a2014-11-17 10:14:32 -0300558 case V4L2_YCBCR_ENC_BT2020:
559 ycbcr2rgb(bt2020, y, cb, cr, 16, r, g, b);
Hans Verkuil63881df2014-08-25 08:02:14 -0300560 break;
Hans Verkuil481b97a2014-11-17 10:14:32 -0300561 case V4L2_YCBCR_ENC_BT2020_CONST_LUM:
562 y -= 16 << 4;
563 cb -= 128 << 4;
564 cr -= 128 << 4;
565
566 if (cb <= 0)
567 *b = COEFF(1.0, 219) * y + COEFF(1.9404, 224) * cb;
568 else
569 *b = COEFF(1.0, 219) * y + COEFF(1.5816, 224) * cb;
570 *b = *b >> 12;
571 if (cr <= 0)
572 *r = COEFF(1.0, 219) * y + COEFF(1.7184, 224) * cr;
573 else
574 *r = COEFF(1.0, 219) * y + COEFF(0.9936, 224) * cr;
575 *r = *r >> 12;
576 lin_r = rec709_to_linear(*r);
577 lin_b = rec709_to_linear(*b);
578 lin_y = rec709_to_linear((y * 255) / 219);
579
580 lin_g = COEFF(1.0 / 0.6780, 255) * lin_y -
581 COEFF(0.2627 / 0.6780, 255) * lin_r -
582 COEFF(0.0593 / 0.6780, 255) * lin_b;
583 *g = linear_to_rec709(lin_g >> 12);
584 break;
585 case V4L2_YCBCR_ENC_SMPTE240M:
586 ycbcr2rgb(smpte240m, y, cb, cr, 16, r, g, b);
587 break;
588 case V4L2_YCBCR_ENC_709:
589 case V4L2_YCBCR_ENC_XV709:
Hans Verkuil63881df2014-08-25 08:02:14 -0300590 default:
Hans Verkuilafad4dd2015-01-27 13:46:17 -0300591 ycbcr2rgb(full ? rec709_full : rec709, y, cb, cr, y_offset, r, g, b);
Hans Verkuil63881df2014-08-25 08:02:14 -0300592 break;
593 }
Hans Verkuil63881df2014-08-25 08:02:14 -0300594}
595
596/* precalculate color bar values to speed up rendering */
597static void precalculate_color(struct tpg_data *tpg, int k)
598{
599 int col = k;
600 int r = tpg_colors[col].r;
601 int g = tpg_colors[col].g;
602 int b = tpg_colors[col].b;
603
604 if (k == TPG_COLOR_TEXTBG) {
605 col = tpg_get_textbg_color(tpg);
606
607 r = tpg_colors[col].r;
608 g = tpg_colors[col].g;
609 b = tpg_colors[col].b;
610 } else if (k == TPG_COLOR_TEXTFG) {
611 col = tpg_get_textfg_color(tpg);
612
613 r = tpg_colors[col].r;
614 g = tpg_colors[col].g;
615 b = tpg_colors[col].b;
616 } else if (tpg->pattern == TPG_PAT_NOISE) {
617 r = g = b = prandom_u32_max(256);
618 } else if (k == TPG_COLOR_RANDOM) {
619 r = g = b = tpg->qual_offset + prandom_u32_max(196);
620 } else if (k >= TPG_COLOR_RAMP) {
621 r = g = b = k - TPG_COLOR_RAMP;
622 }
623
624 if (tpg->pattern == TPG_PAT_CSC_COLORBAR && col <= TPG_COLOR_CSC_BLACK) {
625 r = tpg_csc_colors[tpg->colorspace][col].r;
626 g = tpg_csc_colors[tpg->colorspace][col].g;
627 b = tpg_csc_colors[tpg->colorspace][col].b;
628 } else {
629 r <<= 4;
630 g <<= 4;
631 b <<= 4;
632 }
Hans Verkuil51f30962015-03-07 14:57:50 -0300633 if (tpg->qual == TPG_QUAL_GRAY || tpg->fourcc == V4L2_PIX_FMT_GREY) {
Hans Verkuil481b97a2014-11-17 10:14:32 -0300634 /* Rec. 709 Luma function */
635 /* (0.2126, 0.7152, 0.0722) * (255 * 256) */
Hans Verkuil9c35bd42015-03-07 12:53:39 -0300636 r = g = b = (13879 * r + 46688 * g + 4713 * b) >> 16;
Hans Verkuil481b97a2014-11-17 10:14:32 -0300637 }
Hans Verkuil63881df2014-08-25 08:02:14 -0300638
639 /*
640 * The assumption is that the RGB output is always full range,
641 * so only if the rgb_range overrides the 'real' rgb range do
642 * we need to convert the RGB values.
643 *
Hans Verkuil63881df2014-08-25 08:02:14 -0300644 * Remember that r, g and b are still in the 0 - 0xff0 range.
645 */
646 if (tpg->real_rgb_range == V4L2_DV_RGB_RANGE_LIMITED &&
647 tpg->rgb_range == V4L2_DV_RGB_RANGE_FULL) {
648 /*
649 * Convert from full range (which is what r, g and b are)
650 * to limited range (which is the 'real' RGB range), which
651 * is then interpreted as full range.
652 */
653 r = (r * 219) / 255 + (16 << 4);
654 g = (g * 219) / 255 + (16 << 4);
655 b = (b * 219) / 255 + (16 << 4);
656 } else if (tpg->real_rgb_range != V4L2_DV_RGB_RANGE_LIMITED &&
657 tpg->rgb_range == V4L2_DV_RGB_RANGE_LIMITED) {
658 /*
659 * Clamp r, g and b to the limited range and convert to full
660 * range since that's what we deliver.
661 */
662 r = clamp(r, 16 << 4, 235 << 4);
663 g = clamp(g, 16 << 4, 235 << 4);
664 b = clamp(b, 16 << 4, 235 << 4);
665 r = (r - (16 << 4)) * 255 / 219;
666 g = (g - (16 << 4)) * 255 / 219;
667 b = (b - (16 << 4)) * 255 / 219;
668 }
669
670 if (tpg->brightness != 128 || tpg->contrast != 128 ||
671 tpg->saturation != 128 || tpg->hue) {
672 /* Implement these operations */
Hans Verkuil481b97a2014-11-17 10:14:32 -0300673 int y, cb, cr;
674 int tmp_cb, tmp_cr;
Hans Verkuil63881df2014-08-25 08:02:14 -0300675
676 /* First convert to YCbCr */
Hans Verkuil481b97a2014-11-17 10:14:32 -0300677
678 color_to_ycbcr(tpg, r, g, b, &y, &cb, &cr);
Hans Verkuil63881df2014-08-25 08:02:14 -0300679
680 y = (16 << 4) + ((y - (16 << 4)) * tpg->contrast) / 128;
681 y += (tpg->brightness << 4) - (128 << 4);
682
683 cb -= 128 << 4;
684 cr -= 128 << 4;
685 tmp_cb = (cb * cos(128 + tpg->hue)) / 127 + (cr * sin[128 + tpg->hue]) / 127;
686 tmp_cr = (cr * cos(128 + tpg->hue)) / 127 - (cb * sin[128 + tpg->hue]) / 127;
687
688 cb = (128 << 4) + (tmp_cb * tpg->contrast * tpg->saturation) / (128 * 128);
689 cr = (128 << 4) + (tmp_cr * tpg->contrast * tpg->saturation) / (128 * 128);
690 if (tpg->is_yuv) {
691 tpg->colors[k][0] = clamp(y >> 4, 1, 254);
692 tpg->colors[k][1] = clamp(cb >> 4, 1, 254);
693 tpg->colors[k][2] = clamp(cr >> 4, 1, 254);
694 return;
695 }
Hans Verkuil481b97a2014-11-17 10:14:32 -0300696 ycbcr_to_color(tpg, y, cb, cr, &r, &g, &b);
Hans Verkuil63881df2014-08-25 08:02:14 -0300697 }
698
699 if (tpg->is_yuv) {
700 /* Convert to YCbCr */
Hans Verkuil481b97a2014-11-17 10:14:32 -0300701 int y, cb, cr;
Hans Verkuil63881df2014-08-25 08:02:14 -0300702
Hans Verkuil481b97a2014-11-17 10:14:32 -0300703 color_to_ycbcr(tpg, r, g, b, &y, &cb, &cr);
704
705 if (tpg->real_quantization == V4L2_QUANTIZATION_LIM_RANGE) {
706 y = clamp(y, 16 << 4, 235 << 4);
707 cb = clamp(cb, 16 << 4, 240 << 4);
708 cr = clamp(cr, 16 << 4, 240 << 4);
709 }
Hans Verkuil63881df2014-08-25 08:02:14 -0300710 tpg->colors[k][0] = clamp(y >> 4, 1, 254);
711 tpg->colors[k][1] = clamp(cb >> 4, 1, 254);
712 tpg->colors[k][2] = clamp(cr >> 4, 1, 254);
713 } else {
Hans Verkuil481b97a2014-11-17 10:14:32 -0300714 if (tpg->real_quantization == V4L2_QUANTIZATION_LIM_RANGE) {
715 r = (r * 219) / 255 + (16 << 4);
716 g = (g * 219) / 255 + (16 << 4);
717 b = (b * 219) / 255 + (16 << 4);
718 }
Hans Verkuil63881df2014-08-25 08:02:14 -0300719 switch (tpg->fourcc) {
720 case V4L2_PIX_FMT_RGB565:
721 case V4L2_PIX_FMT_RGB565X:
722 r >>= 7;
723 g >>= 6;
724 b >>= 7;
725 break;
Hans Verkuil8aca2302015-03-11 08:14:34 -0300726 case V4L2_PIX_FMT_RGB444:
727 case V4L2_PIX_FMT_XRGB444:
728 case V4L2_PIX_FMT_ARGB444:
729 r >>= 8;
730 g >>= 8;
731 b >>= 8;
732 break;
Hans Verkuil63881df2014-08-25 08:02:14 -0300733 case V4L2_PIX_FMT_RGB555:
734 case V4L2_PIX_FMT_XRGB555:
735 case V4L2_PIX_FMT_ARGB555:
736 case V4L2_PIX_FMT_RGB555X:
Hans Verkuil8f1ff542015-03-12 05:08:01 -0300737 case V4L2_PIX_FMT_XRGB555X:
738 case V4L2_PIX_FMT_ARGB555X:
Hans Verkuil63881df2014-08-25 08:02:14 -0300739 r >>= 7;
740 g >>= 7;
741 b >>= 7;
742 break;
743 default:
744 r >>= 4;
745 g >>= 4;
746 b >>= 4;
747 break;
748 }
749
750 tpg->colors[k][0] = r;
751 tpg->colors[k][1] = g;
752 tpg->colors[k][2] = b;
753 }
754}
755
756static void tpg_precalculate_colors(struct tpg_data *tpg)
757{
758 int k;
759
760 for (k = 0; k < TPG_COLOR_MAX; k++)
761 precalculate_color(tpg, k);
762}
763
764/* 'odd' is true for pixels 1, 3, 5, etc. and false for pixels 0, 2, 4, etc. */
765static void gen_twopix(struct tpg_data *tpg,
766 u8 buf[TPG_MAX_PLANES][8], int color, bool odd)
767{
768 unsigned offset = odd * tpg->twopixelsize[0] / 2;
769 u8 alpha = tpg->alpha_component;
770 u8 r_y, g_u, b_v;
771
772 if (tpg->alpha_red_only && color != TPG_COLOR_CSC_RED &&
773 color != TPG_COLOR_100_RED &&
774 color != TPG_COLOR_75_RED)
775 alpha = 0;
776 if (color == TPG_COLOR_RANDOM)
777 precalculate_color(tpg, color);
778 r_y = tpg->colors[color][0]; /* R or precalculated Y */
779 g_u = tpg->colors[color][1]; /* G or precalculated U */
780 b_v = tpg->colors[color][2]; /* B or precalculated V */
781
782 switch (tpg->fourcc) {
Hans Verkuil51f30962015-03-07 14:57:50 -0300783 case V4L2_PIX_FMT_GREY:
784 buf[0][offset] = r_y;
785 break;
Hans Verkuil68c90d62015-03-07 14:55:09 -0300786 case V4L2_PIX_FMT_YUV422P:
787 case V4L2_PIX_FMT_YUV420:
788 case V4L2_PIX_FMT_YUV420M:
789 buf[0][offset] = r_y;
790 if (odd) {
791 buf[1][0] = (buf[1][0] + g_u) / 2;
792 buf[2][0] = (buf[2][0] + b_v) / 2;
793 buf[1][1] = buf[1][0];
794 buf[2][1] = buf[2][0];
795 break;
796 }
797 buf[1][0] = g_u;
798 buf[2][0] = b_v;
799 break;
800 case V4L2_PIX_FMT_YVU420:
801 case V4L2_PIX_FMT_YVU420M:
802 buf[0][offset] = r_y;
803 if (odd) {
804 buf[1][0] = (buf[1][0] + b_v) / 2;
805 buf[2][0] = (buf[2][0] + g_u) / 2;
806 buf[1][1] = buf[1][0];
807 buf[2][1] = buf[2][0];
808 break;
809 }
810 buf[1][0] = b_v;
811 buf[2][0] = g_u;
812 break;
813
814 case V4L2_PIX_FMT_NV12:
815 case V4L2_PIX_FMT_NV12M:
816 case V4L2_PIX_FMT_NV16:
Hans Verkuil63881df2014-08-25 08:02:14 -0300817 case V4L2_PIX_FMT_NV16M:
818 buf[0][offset] = r_y;
Hans Verkuil1f088dc2015-03-07 14:15:25 -0300819 if (odd) {
820 buf[1][0] = (buf[1][0] + g_u) / 2;
821 buf[1][1] = (buf[1][1] + b_v) / 2;
822 break;
823 }
824 buf[1][0] = g_u;
825 buf[1][1] = b_v;
Hans Verkuil63881df2014-08-25 08:02:14 -0300826 break;
Hans Verkuil68c90d62015-03-07 14:55:09 -0300827 case V4L2_PIX_FMT_NV21:
828 case V4L2_PIX_FMT_NV21M:
829 case V4L2_PIX_FMT_NV61:
Hans Verkuil63881df2014-08-25 08:02:14 -0300830 case V4L2_PIX_FMT_NV61M:
831 buf[0][offset] = r_y;
Hans Verkuil1f088dc2015-03-07 14:15:25 -0300832 if (odd) {
833 buf[1][0] = (buf[1][0] + b_v) / 2;
834 buf[1][1] = (buf[1][1] + g_u) / 2;
835 break;
836 }
837 buf[1][0] = b_v;
838 buf[1][1] = g_u;
Hans Verkuil63881df2014-08-25 08:02:14 -0300839 break;
840
Hans Verkuildde72bd2015-03-13 05:51:21 -0300841 case V4L2_PIX_FMT_NV24:
842 buf[0][offset] = r_y;
843 buf[1][2 * offset] = g_u;
844 buf[1][2 * offset + 1] = b_v;
845 break;
846
847 case V4L2_PIX_FMT_NV42:
848 buf[0][offset] = r_y;
849 buf[1][2 * offset] = b_v;
850 buf[1][2 * offset + 1] = g_u;
851 break;
852
Hans Verkuil63881df2014-08-25 08:02:14 -0300853 case V4L2_PIX_FMT_YUYV:
854 buf[0][offset] = r_y;
Hans Verkuil1f088dc2015-03-07 14:15:25 -0300855 if (odd) {
856 buf[0][1] = (buf[0][1] + g_u) / 2;
857 buf[0][3] = (buf[0][3] + b_v) / 2;
858 break;
859 }
860 buf[0][1] = g_u;
861 buf[0][3] = b_v;
Hans Verkuil63881df2014-08-25 08:02:14 -0300862 break;
863 case V4L2_PIX_FMT_UYVY:
Hans Verkuil63881df2014-08-25 08:02:14 -0300864 buf[0][offset + 1] = r_y;
Hans Verkuil1f088dc2015-03-07 14:15:25 -0300865 if (odd) {
866 buf[0][0] = (buf[0][0] + g_u) / 2;
867 buf[0][2] = (buf[0][2] + b_v) / 2;
868 break;
869 }
870 buf[0][0] = g_u;
871 buf[0][2] = b_v;
Hans Verkuil63881df2014-08-25 08:02:14 -0300872 break;
873 case V4L2_PIX_FMT_YVYU:
874 buf[0][offset] = r_y;
Hans Verkuil1f088dc2015-03-07 14:15:25 -0300875 if (odd) {
876 buf[0][1] = (buf[0][1] + b_v) / 2;
877 buf[0][3] = (buf[0][3] + g_u) / 2;
878 break;
879 }
880 buf[0][1] = b_v;
881 buf[0][3] = g_u;
Hans Verkuil63881df2014-08-25 08:02:14 -0300882 break;
883 case V4L2_PIX_FMT_VYUY:
Hans Verkuil63881df2014-08-25 08:02:14 -0300884 buf[0][offset + 1] = r_y;
Hans Verkuil1f088dc2015-03-07 14:15:25 -0300885 if (odd) {
886 buf[0][0] = (buf[0][0] + b_v) / 2;
887 buf[0][2] = (buf[0][2] + g_u) / 2;
888 break;
889 }
890 buf[0][0] = b_v;
891 buf[0][2] = g_u;
Hans Verkuil63881df2014-08-25 08:02:14 -0300892 break;
893 case V4L2_PIX_FMT_RGB565:
894 buf[0][offset] = (g_u << 5) | b_v;
895 buf[0][offset + 1] = (r_y << 3) | (g_u >> 3);
896 break;
897 case V4L2_PIX_FMT_RGB565X:
898 buf[0][offset] = (r_y << 3) | (g_u >> 3);
899 buf[0][offset + 1] = (g_u << 5) | b_v;
900 break;
Hans Verkuil8aca2302015-03-11 08:14:34 -0300901 case V4L2_PIX_FMT_RGB444:
902 case V4L2_PIX_FMT_XRGB444:
903 alpha = 0;
904 /* fall through */
905 case V4L2_PIX_FMT_ARGB444:
906 buf[0][offset] = (g_u << 4) | b_v;
907 buf[0][offset + 1] = (alpha & 0xf0) | r_y;
908 break;
Hans Verkuil63881df2014-08-25 08:02:14 -0300909 case V4L2_PIX_FMT_RGB555:
910 case V4L2_PIX_FMT_XRGB555:
911 alpha = 0;
912 /* fall through */
913 case V4L2_PIX_FMT_ARGB555:
914 buf[0][offset] = (g_u << 5) | b_v;
915 buf[0][offset + 1] = (alpha & 0x80) | (r_y << 2) | (g_u >> 3);
916 break;
917 case V4L2_PIX_FMT_RGB555X:
Hans Verkuil8f1ff542015-03-12 05:08:01 -0300918 case V4L2_PIX_FMT_XRGB555X:
919 alpha = 0;
920 /* fall through */
921 case V4L2_PIX_FMT_ARGB555X:
Hans Verkuil63881df2014-08-25 08:02:14 -0300922 buf[0][offset] = (alpha & 0x80) | (r_y << 2) | (g_u >> 3);
923 buf[0][offset + 1] = (g_u << 5) | b_v;
924 break;
925 case V4L2_PIX_FMT_RGB24:
926 buf[0][offset] = r_y;
927 buf[0][offset + 1] = g_u;
928 buf[0][offset + 2] = b_v;
929 break;
930 case V4L2_PIX_FMT_BGR24:
931 buf[0][offset] = b_v;
932 buf[0][offset + 1] = g_u;
933 buf[0][offset + 2] = r_y;
934 break;
935 case V4L2_PIX_FMT_RGB32:
936 case V4L2_PIX_FMT_XRGB32:
937 alpha = 0;
938 /* fall through */
939 case V4L2_PIX_FMT_ARGB32:
940 buf[0][offset] = alpha;
941 buf[0][offset + 1] = r_y;
942 buf[0][offset + 2] = g_u;
943 buf[0][offset + 3] = b_v;
944 break;
945 case V4L2_PIX_FMT_BGR32:
946 case V4L2_PIX_FMT_XBGR32:
947 alpha = 0;
948 /* fall through */
949 case V4L2_PIX_FMT_ABGR32:
950 buf[0][offset] = b_v;
951 buf[0][offset + 1] = g_u;
952 buf[0][offset + 2] = r_y;
953 buf[0][offset + 3] = alpha;
954 break;
955 }
956}
957
958/* Return how many pattern lines are used by the current pattern. */
Hans Verkuil1a05d312015-03-07 12:49:57 -0300959static unsigned tpg_get_pat_lines(const struct tpg_data *tpg)
Hans Verkuil63881df2014-08-25 08:02:14 -0300960{
961 switch (tpg->pattern) {
962 case TPG_PAT_CHECKERS_16X16:
Hans Verkuil1a05d312015-03-07 12:49:57 -0300963 case TPG_PAT_CHECKERS_2X2:
Hans Verkuil63881df2014-08-25 08:02:14 -0300964 case TPG_PAT_CHECKERS_1X1:
Hans Verkuil1a05d312015-03-07 12:49:57 -0300965 case TPG_PAT_COLOR_CHECKERS_2X2:
966 case TPG_PAT_COLOR_CHECKERS_1X1:
Hans Verkuil63881df2014-08-25 08:02:14 -0300967 case TPG_PAT_ALTERNATING_HLINES:
968 case TPG_PAT_CROSS_1_PIXEL:
969 case TPG_PAT_CROSS_2_PIXELS:
970 case TPG_PAT_CROSS_10_PIXELS:
971 return 2;
972 case TPG_PAT_100_COLORSQUARES:
973 case TPG_PAT_100_HCOLORBAR:
974 return 8;
975 default:
976 return 1;
977 }
978}
979
980/* Which pattern line should be used for the given frame line. */
Hans Verkuil1a05d312015-03-07 12:49:57 -0300981static unsigned tpg_get_pat_line(const struct tpg_data *tpg, unsigned line)
Hans Verkuil63881df2014-08-25 08:02:14 -0300982{
983 switch (tpg->pattern) {
984 case TPG_PAT_CHECKERS_16X16:
985 return (line >> 4) & 1;
986 case TPG_PAT_CHECKERS_1X1:
Hans Verkuil1a05d312015-03-07 12:49:57 -0300987 case TPG_PAT_COLOR_CHECKERS_1X1:
Hans Verkuil63881df2014-08-25 08:02:14 -0300988 case TPG_PAT_ALTERNATING_HLINES:
989 return line & 1;
Hans Verkuil1a05d312015-03-07 12:49:57 -0300990 case TPG_PAT_CHECKERS_2X2:
991 case TPG_PAT_COLOR_CHECKERS_2X2:
992 return (line & 2) >> 1;
Hans Verkuil63881df2014-08-25 08:02:14 -0300993 case TPG_PAT_100_COLORSQUARES:
994 case TPG_PAT_100_HCOLORBAR:
995 return (line * 8) / tpg->src_height;
996 case TPG_PAT_CROSS_1_PIXEL:
997 return line == tpg->src_height / 2;
998 case TPG_PAT_CROSS_2_PIXELS:
999 return (line + 1) / 2 == tpg->src_height / 4;
1000 case TPG_PAT_CROSS_10_PIXELS:
1001 return (line + 10) / 20 == tpg->src_height / 40;
1002 default:
1003 return 0;
1004 }
1005}
1006
1007/*
1008 * Which color should be used for the given pattern line and X coordinate.
1009 * Note: x is in the range 0 to 2 * tpg->src_width.
1010 */
Hans Verkuil1a05d312015-03-07 12:49:57 -03001011static enum tpg_color tpg_get_color(const struct tpg_data *tpg,
1012 unsigned pat_line, unsigned x)
Hans Verkuil63881df2014-08-25 08:02:14 -03001013{
1014 /* Maximum number of bars are TPG_COLOR_MAX - otherwise, the input print code
1015 should be modified */
1016 static const enum tpg_color bars[3][8] = {
1017 /* Standard ITU-R 75% color bar sequence */
1018 { TPG_COLOR_CSC_WHITE, TPG_COLOR_75_YELLOW,
1019 TPG_COLOR_75_CYAN, TPG_COLOR_75_GREEN,
1020 TPG_COLOR_75_MAGENTA, TPG_COLOR_75_RED,
1021 TPG_COLOR_75_BLUE, TPG_COLOR_100_BLACK, },
1022 /* Standard ITU-R 100% color bar sequence */
1023 { TPG_COLOR_100_WHITE, TPG_COLOR_100_YELLOW,
1024 TPG_COLOR_100_CYAN, TPG_COLOR_100_GREEN,
1025 TPG_COLOR_100_MAGENTA, TPG_COLOR_100_RED,
1026 TPG_COLOR_100_BLUE, TPG_COLOR_100_BLACK, },
1027 /* Color bar sequence suitable to test CSC */
1028 { TPG_COLOR_CSC_WHITE, TPG_COLOR_CSC_YELLOW,
1029 TPG_COLOR_CSC_CYAN, TPG_COLOR_CSC_GREEN,
1030 TPG_COLOR_CSC_MAGENTA, TPG_COLOR_CSC_RED,
1031 TPG_COLOR_CSC_BLUE, TPG_COLOR_CSC_BLACK, },
1032 };
1033
1034 switch (tpg->pattern) {
1035 case TPG_PAT_75_COLORBAR:
1036 case TPG_PAT_100_COLORBAR:
1037 case TPG_PAT_CSC_COLORBAR:
1038 return bars[tpg->pattern][((x * 8) / tpg->src_width) % 8];
1039 case TPG_PAT_100_COLORSQUARES:
1040 return bars[1][(pat_line + (x * 8) / tpg->src_width) % 8];
1041 case TPG_PAT_100_HCOLORBAR:
1042 return bars[1][pat_line];
1043 case TPG_PAT_BLACK:
1044 return TPG_COLOR_100_BLACK;
1045 case TPG_PAT_WHITE:
1046 return TPG_COLOR_100_WHITE;
1047 case TPG_PAT_RED:
1048 return TPG_COLOR_100_RED;
1049 case TPG_PAT_GREEN:
1050 return TPG_COLOR_100_GREEN;
1051 case TPG_PAT_BLUE:
1052 return TPG_COLOR_100_BLUE;
1053 case TPG_PAT_CHECKERS_16X16:
1054 return (((x >> 4) & 1) ^ (pat_line & 1)) ?
1055 TPG_COLOR_100_BLACK : TPG_COLOR_100_WHITE;
1056 case TPG_PAT_CHECKERS_1X1:
1057 return ((x & 1) ^ (pat_line & 1)) ?
1058 TPG_COLOR_100_WHITE : TPG_COLOR_100_BLACK;
Hans Verkuil1a05d312015-03-07 12:49:57 -03001059 case TPG_PAT_COLOR_CHECKERS_1X1:
1060 return ((x & 1) ^ (pat_line & 1)) ?
1061 TPG_COLOR_100_RED : TPG_COLOR_100_BLUE;
1062 case TPG_PAT_CHECKERS_2X2:
1063 return (((x >> 1) & 1) ^ (pat_line & 1)) ?
1064 TPG_COLOR_100_WHITE : TPG_COLOR_100_BLACK;
1065 case TPG_PAT_COLOR_CHECKERS_2X2:
1066 return (((x >> 1) & 1) ^ (pat_line & 1)) ?
1067 TPG_COLOR_100_RED : TPG_COLOR_100_BLUE;
Hans Verkuil63881df2014-08-25 08:02:14 -03001068 case TPG_PAT_ALTERNATING_HLINES:
1069 return pat_line ? TPG_COLOR_100_WHITE : TPG_COLOR_100_BLACK;
1070 case TPG_PAT_ALTERNATING_VLINES:
1071 return (x & 1) ? TPG_COLOR_100_WHITE : TPG_COLOR_100_BLACK;
1072 case TPG_PAT_CROSS_1_PIXEL:
1073 if (pat_line || (x % tpg->src_width) == tpg->src_width / 2)
1074 return TPG_COLOR_100_BLACK;
1075 return TPG_COLOR_100_WHITE;
1076 case TPG_PAT_CROSS_2_PIXELS:
1077 if (pat_line || ((x % tpg->src_width) + 1) / 2 == tpg->src_width / 4)
1078 return TPG_COLOR_100_BLACK;
1079 return TPG_COLOR_100_WHITE;
1080 case TPG_PAT_CROSS_10_PIXELS:
1081 if (pat_line || ((x % tpg->src_width) + 10) / 20 == tpg->src_width / 40)
1082 return TPG_COLOR_100_BLACK;
1083 return TPG_COLOR_100_WHITE;
1084 case TPG_PAT_GRAY_RAMP:
1085 return TPG_COLOR_RAMP + ((x % tpg->src_width) * 256) / tpg->src_width;
1086 default:
1087 return TPG_COLOR_100_RED;
1088 }
1089}
1090
1091/*
1092 * Given the pixel aspect ratio and video aspect ratio calculate the
1093 * coordinates of a centered square and the coordinates of the border of
1094 * the active video area. The coordinates are relative to the source
1095 * frame rectangle.
1096 */
1097static void tpg_calculate_square_border(struct tpg_data *tpg)
1098{
1099 unsigned w = tpg->src_width;
1100 unsigned h = tpg->src_height;
1101 unsigned sq_w, sq_h;
1102
1103 sq_w = (w * 2 / 5) & ~1;
1104 if (((w - sq_w) / 2) & 1)
1105 sq_w += 2;
1106 sq_h = sq_w;
1107 tpg->square.width = sq_w;
1108 if (tpg->vid_aspect == TPG_VIDEO_ASPECT_16X9_ANAMORPHIC) {
1109 unsigned ana_sq_w = (sq_w / 4) * 3;
1110
1111 if (((w - ana_sq_w) / 2) & 1)
1112 ana_sq_w += 2;
1113 tpg->square.width = ana_sq_w;
1114 }
1115 tpg->square.left = (w - tpg->square.width) / 2;
1116 if (tpg->pix_aspect == TPG_PIXEL_ASPECT_NTSC)
1117 sq_h = sq_w * 10 / 11;
1118 else if (tpg->pix_aspect == TPG_PIXEL_ASPECT_PAL)
1119 sq_h = sq_w * 59 / 54;
1120 tpg->square.height = sq_h;
1121 tpg->square.top = (h - sq_h) / 2;
1122 tpg->border.left = 0;
1123 tpg->border.width = w;
1124 tpg->border.top = 0;
1125 tpg->border.height = h;
1126 switch (tpg->vid_aspect) {
1127 case TPG_VIDEO_ASPECT_4X3:
1128 if (tpg->pix_aspect)
1129 return;
1130 if (3 * w >= 4 * h) {
1131 tpg->border.width = ((4 * h) / 3) & ~1;
1132 if (((w - tpg->border.width) / 2) & ~1)
1133 tpg->border.width -= 2;
1134 tpg->border.left = (w - tpg->border.width) / 2;
1135 break;
1136 }
1137 tpg->border.height = ((3 * w) / 4) & ~1;
1138 tpg->border.top = (h - tpg->border.height) / 2;
1139 break;
1140 case TPG_VIDEO_ASPECT_14X9_CENTRE:
1141 if (tpg->pix_aspect) {
1142 tpg->border.height = tpg->pix_aspect == TPG_PIXEL_ASPECT_NTSC ? 420 : 506;
1143 tpg->border.top = (h - tpg->border.height) / 2;
1144 break;
1145 }
1146 if (9 * w >= 14 * h) {
1147 tpg->border.width = ((14 * h) / 9) & ~1;
1148 if (((w - tpg->border.width) / 2) & ~1)
1149 tpg->border.width -= 2;
1150 tpg->border.left = (w - tpg->border.width) / 2;
1151 break;
1152 }
1153 tpg->border.height = ((9 * w) / 14) & ~1;
1154 tpg->border.top = (h - tpg->border.height) / 2;
1155 break;
1156 case TPG_VIDEO_ASPECT_16X9_CENTRE:
1157 if (tpg->pix_aspect) {
1158 tpg->border.height = tpg->pix_aspect == TPG_PIXEL_ASPECT_NTSC ? 368 : 442;
1159 tpg->border.top = (h - tpg->border.height) / 2;
1160 break;
1161 }
1162 if (9 * w >= 16 * h) {
1163 tpg->border.width = ((16 * h) / 9) & ~1;
1164 if (((w - tpg->border.width) / 2) & ~1)
1165 tpg->border.width -= 2;
1166 tpg->border.left = (w - tpg->border.width) / 2;
1167 break;
1168 }
1169 tpg->border.height = ((9 * w) / 16) & ~1;
1170 tpg->border.top = (h - tpg->border.height) / 2;
1171 break;
1172 default:
1173 break;
1174 }
1175}
1176
1177static void tpg_precalculate_line(struct tpg_data *tpg)
1178{
1179 enum tpg_color contrast;
Hans Verkuil9991def2015-03-08 05:53:10 -03001180 u8 pix[TPG_MAX_PLANES][8];
Hans Verkuil63881df2014-08-25 08:02:14 -03001181 unsigned pat;
1182 unsigned p;
1183 unsigned x;
1184
1185 switch (tpg->pattern) {
1186 case TPG_PAT_GREEN:
1187 contrast = TPG_COLOR_100_RED;
1188 break;
1189 case TPG_PAT_CSC_COLORBAR:
1190 contrast = TPG_COLOR_CSC_GREEN;
1191 break;
1192 default:
1193 contrast = TPG_COLOR_100_GREEN;
1194 break;
1195 }
1196
1197 for (pat = 0; pat < tpg_get_pat_lines(tpg); pat++) {
1198 /* Coarse scaling with Bresenham */
1199 unsigned int_part = tpg->src_width / tpg->scaled_width;
1200 unsigned fract_part = tpg->src_width % tpg->scaled_width;
1201 unsigned src_x = 0;
1202 unsigned error = 0;
1203
1204 for (x = 0; x < tpg->scaled_width * 2; x += 2) {
1205 unsigned real_x = src_x;
1206 enum tpg_color color1, color2;
Hans Verkuil63881df2014-08-25 08:02:14 -03001207
1208 real_x = tpg->hflip ? tpg->src_width * 2 - real_x - 2 : real_x;
1209 color1 = tpg_get_color(tpg, pat, real_x);
1210
1211 src_x += int_part;
1212 error += fract_part;
1213 if (error >= tpg->scaled_width) {
1214 error -= tpg->scaled_width;
1215 src_x++;
1216 }
1217
1218 real_x = src_x;
1219 real_x = tpg->hflip ? tpg->src_width * 2 - real_x - 2 : real_x;
1220 color2 = tpg_get_color(tpg, pat, real_x);
1221
1222 src_x += int_part;
1223 error += fract_part;
1224 if (error >= tpg->scaled_width) {
1225 error -= tpg->scaled_width;
1226 src_x++;
1227 }
1228
1229 gen_twopix(tpg, pix, tpg->hflip ? color2 : color1, 0);
1230 gen_twopix(tpg, pix, tpg->hflip ? color1 : color2, 1);
1231 for (p = 0; p < tpg->planes; p++) {
1232 unsigned twopixsize = tpg->twopixelsize[p];
Hans Verkuil5d7c5392015-03-07 14:06:43 -03001233 unsigned hdiv = tpg->hdownsampling[p];
Hans Verkuil9991def2015-03-08 05:53:10 -03001234 u8 *pos = tpg->lines[pat][p] + tpg_hdiv(tpg, p, x);
Hans Verkuil63881df2014-08-25 08:02:14 -03001235
Hans Verkuil5d7c5392015-03-07 14:06:43 -03001236 memcpy(pos, pix[p], twopixsize / hdiv);
Hans Verkuil63881df2014-08-25 08:02:14 -03001237 }
1238 }
1239 }
Hans Verkuil5d7c5392015-03-07 14:06:43 -03001240
1241 if (tpg->vdownsampling[tpg->planes - 1] > 1) {
1242 unsigned pat_lines = tpg_get_pat_lines(tpg);
1243
1244 for (pat = 0; pat < pat_lines; pat++) {
1245 unsigned next_pat = (pat + 1) % pat_lines;
1246
1247 for (p = 1; p < tpg->planes; p++) {
Hans Verkuil9991def2015-03-08 05:53:10 -03001248 unsigned w = tpg_hdiv(tpg, p, tpg->scaled_width * 2);
1249 u8 *pos1 = tpg->lines[pat][p];
1250 u8 *pos2 = tpg->lines[next_pat][p];
1251 u8 *dest = tpg->downsampled_lines[pat][p];
Hans Verkuil5d7c5392015-03-07 14:06:43 -03001252
Hans Verkuil9991def2015-03-08 05:53:10 -03001253 for (x = 0; x < w; x++, pos1++, pos2++, dest++)
1254 *dest = ((u16)*pos1 + (u16)*pos2) / 2;
Hans Verkuil5d7c5392015-03-07 14:06:43 -03001255 }
1256 }
1257 }
1258
Hans Verkuil9991def2015-03-08 05:53:10 -03001259 gen_twopix(tpg, pix, contrast, 0);
1260 gen_twopix(tpg, pix, contrast, 1);
1261 for (p = 0; p < tpg->planes; p++) {
1262 unsigned twopixsize = tpg->twopixelsize[p];
1263 u8 *pos = tpg->contrast_line[p];
Hans Verkuil63881df2014-08-25 08:02:14 -03001264
Hans Verkuil9991def2015-03-08 05:53:10 -03001265 for (x = 0; x < tpg->scaled_width; x += 2, pos += twopixsize)
Hans Verkuil63881df2014-08-25 08:02:14 -03001266 memcpy(pos, pix[p], twopixsize);
Hans Verkuil63881df2014-08-25 08:02:14 -03001267 }
Hans Verkuil63881df2014-08-25 08:02:14 -03001268
Hans Verkuil9991def2015-03-08 05:53:10 -03001269 gen_twopix(tpg, pix, TPG_COLOR_100_BLACK, 0);
1270 gen_twopix(tpg, pix, TPG_COLOR_100_BLACK, 1);
1271 for (p = 0; p < tpg->planes; p++) {
1272 unsigned twopixsize = tpg->twopixelsize[p];
1273 u8 *pos = tpg->black_line[p];
Hans Verkuil63881df2014-08-25 08:02:14 -03001274
Hans Verkuil9991def2015-03-08 05:53:10 -03001275 for (x = 0; x < tpg->scaled_width; x += 2, pos += twopixsize)
Hans Verkuil63881df2014-08-25 08:02:14 -03001276 memcpy(pos, pix[p], twopixsize);
Hans Verkuil63881df2014-08-25 08:02:14 -03001277 }
Hans Verkuil9991def2015-03-08 05:53:10 -03001278
Hans Verkuil63881df2014-08-25 08:02:14 -03001279 for (x = 0; x < tpg->scaled_width * 2; x += 2) {
Hans Verkuil63881df2014-08-25 08:02:14 -03001280 gen_twopix(tpg, pix, TPG_COLOR_RANDOM, 0);
1281 gen_twopix(tpg, pix, TPG_COLOR_RANDOM, 1);
1282 for (p = 0; p < tpg->planes; p++) {
1283 unsigned twopixsize = tpg->twopixelsize[p];
1284 u8 *pos = tpg->random_line[p] + x * twopixsize / 2;
1285
1286 memcpy(pos, pix[p], twopixsize);
1287 }
1288 }
Hans Verkuil9991def2015-03-08 05:53:10 -03001289
Hans Verkuil63881df2014-08-25 08:02:14 -03001290 gen_twopix(tpg, tpg->textbg, TPG_COLOR_TEXTBG, 0);
1291 gen_twopix(tpg, tpg->textbg, TPG_COLOR_TEXTBG, 1);
1292 gen_twopix(tpg, tpg->textfg, TPG_COLOR_TEXTFG, 0);
1293 gen_twopix(tpg, tpg->textfg, TPG_COLOR_TEXTFG, 1);
1294}
1295
1296/* need this to do rgb24 rendering */
1297typedef struct { u16 __; u8 _; } __packed x24;
1298
Hans Verkuildfff0482015-03-09 11:04:02 -03001299void tpg_gen_text(const struct tpg_data *tpg, u8 *basep[TPG_MAX_PLANES][2],
1300 int y, int x, char *text)
Hans Verkuil63881df2014-08-25 08:02:14 -03001301{
1302 int line;
1303 unsigned step = V4L2_FIELD_HAS_T_OR_B(tpg->field) ? 2 : 1;
1304 unsigned div = step;
1305 unsigned first = 0;
1306 unsigned len = strlen(text);
1307 unsigned p;
1308
1309 if (font8x16 == NULL || basep == NULL)
1310 return;
1311
1312 /* Checks if it is possible to show string */
1313 if (y + 16 >= tpg->compose.height || x + 8 >= tpg->compose.width)
1314 return;
1315
1316 if (len > (tpg->compose.width - x) / 8)
1317 len = (tpg->compose.width - x) / 8;
1318 if (tpg->vflip)
1319 y = tpg->compose.height - y - 16;
1320 if (tpg->hflip)
1321 x = tpg->compose.width - x - 8;
1322 y += tpg->compose.top;
1323 x += tpg->compose.left;
1324 if (tpg->field == V4L2_FIELD_BOTTOM)
1325 first = 1;
1326 else if (tpg->field == V4L2_FIELD_SEQ_TB || tpg->field == V4L2_FIELD_SEQ_BT)
1327 div = 2;
1328
1329 for (p = 0; p < tpg->planes; p++) {
Hans Verkuil3e14e7a82015-03-07 14:23:16 -03001330 unsigned vdiv = tpg->vdownsampling[p];
1331 unsigned hdiv = tpg->hdownsampling[p];
1332
1333 /* Print text */
Hans Verkuil63881df2014-08-25 08:02:14 -03001334#define PRINTSTR(PIXTYPE) do { \
1335 PIXTYPE fg; \
1336 PIXTYPE bg; \
1337 memcpy(&fg, tpg->textfg[p], sizeof(PIXTYPE)); \
1338 memcpy(&bg, tpg->textbg[p], sizeof(PIXTYPE)); \
1339 \
Hans Verkuil3e14e7a82015-03-07 14:23:16 -03001340 for (line = first; line < 16; line += vdiv * step) { \
Hans Verkuil63881df2014-08-25 08:02:14 -03001341 int l = tpg->vflip ? 15 - line : line; \
Hans Verkuil3e14e7a82015-03-07 14:23:16 -03001342 PIXTYPE *pos = (PIXTYPE *)(basep[p][(line / vdiv) & 1] + \
1343 ((y * step + l) / (vdiv * div)) * tpg->bytesperline[p] + \
1344 (x / hdiv) * sizeof(PIXTYPE)); \
Hans Verkuil63881df2014-08-25 08:02:14 -03001345 unsigned s; \
1346 \
1347 for (s = 0; s < len; s++) { \
1348 u8 chr = font8x16[text[s] * 16 + line]; \
1349 \
Hans Verkuil3e14e7a82015-03-07 14:23:16 -03001350 if (hdiv == 2 && tpg->hflip) { \
1351 pos[3] = (chr & (0x01 << 6) ? fg : bg); \
1352 pos[2] = (chr & (0x01 << 4) ? fg : bg); \
1353 pos[1] = (chr & (0x01 << 2) ? fg : bg); \
1354 pos[0] = (chr & (0x01 << 0) ? fg : bg); \
1355 } else if (hdiv == 2) { \
1356 pos[0] = (chr & (0x01 << 7) ? fg : bg); \
1357 pos[1] = (chr & (0x01 << 5) ? fg : bg); \
1358 pos[2] = (chr & (0x01 << 3) ? fg : bg); \
1359 pos[3] = (chr & (0x01 << 1) ? fg : bg); \
1360 } else if (tpg->hflip) { \
Hans Verkuil63881df2014-08-25 08:02:14 -03001361 pos[7] = (chr & (0x01 << 7) ? fg : bg); \
1362 pos[6] = (chr & (0x01 << 6) ? fg : bg); \
1363 pos[5] = (chr & (0x01 << 5) ? fg : bg); \
1364 pos[4] = (chr & (0x01 << 4) ? fg : bg); \
1365 pos[3] = (chr & (0x01 << 3) ? fg : bg); \
1366 pos[2] = (chr & (0x01 << 2) ? fg : bg); \
1367 pos[1] = (chr & (0x01 << 1) ? fg : bg); \
1368 pos[0] = (chr & (0x01 << 0) ? fg : bg); \
1369 } else { \
1370 pos[0] = (chr & (0x01 << 7) ? fg : bg); \
1371 pos[1] = (chr & (0x01 << 6) ? fg : bg); \
1372 pos[2] = (chr & (0x01 << 5) ? fg : bg); \
1373 pos[3] = (chr & (0x01 << 4) ? fg : bg); \
1374 pos[4] = (chr & (0x01 << 3) ? fg : bg); \
1375 pos[5] = (chr & (0x01 << 2) ? fg : bg); \
1376 pos[6] = (chr & (0x01 << 1) ? fg : bg); \
1377 pos[7] = (chr & (0x01 << 0) ? fg : bg); \
1378 } \
1379 \
Hans Verkuil3e14e7a82015-03-07 14:23:16 -03001380 pos += (tpg->hflip ? -8 : 8) / hdiv; \
Hans Verkuil63881df2014-08-25 08:02:14 -03001381 } \
1382 } \
1383} while (0)
1384
1385 switch (tpg->twopixelsize[p]) {
1386 case 2:
1387 PRINTSTR(u8); break;
1388 case 4:
1389 PRINTSTR(u16); break;
1390 case 6:
1391 PRINTSTR(x24); break;
1392 case 8:
1393 PRINTSTR(u32); break;
1394 }
1395 }
1396}
1397
1398void tpg_update_mv_step(struct tpg_data *tpg)
1399{
1400 int factor = tpg->mv_hor_mode > TPG_MOVE_NONE ? -1 : 1;
1401
1402 if (tpg->hflip)
1403 factor = -factor;
1404 switch (tpg->mv_hor_mode) {
1405 case TPG_MOVE_NEG_FAST:
1406 case TPG_MOVE_POS_FAST:
1407 tpg->mv_hor_step = ((tpg->src_width + 319) / 320) * 4;
1408 break;
1409 case TPG_MOVE_NEG:
1410 case TPG_MOVE_POS:
1411 tpg->mv_hor_step = ((tpg->src_width + 639) / 640) * 4;
1412 break;
1413 case TPG_MOVE_NEG_SLOW:
1414 case TPG_MOVE_POS_SLOW:
1415 tpg->mv_hor_step = 2;
1416 break;
1417 case TPG_MOVE_NONE:
1418 tpg->mv_hor_step = 0;
1419 break;
1420 }
1421 if (factor < 0)
1422 tpg->mv_hor_step = tpg->src_width - tpg->mv_hor_step;
1423
1424 factor = tpg->mv_vert_mode > TPG_MOVE_NONE ? -1 : 1;
1425 switch (tpg->mv_vert_mode) {
1426 case TPG_MOVE_NEG_FAST:
1427 case TPG_MOVE_POS_FAST:
1428 tpg->mv_vert_step = ((tpg->src_width + 319) / 320) * 4;
1429 break;
1430 case TPG_MOVE_NEG:
1431 case TPG_MOVE_POS:
1432 tpg->mv_vert_step = ((tpg->src_width + 639) / 640) * 4;
1433 break;
1434 case TPG_MOVE_NEG_SLOW:
1435 case TPG_MOVE_POS_SLOW:
1436 tpg->mv_vert_step = 1;
1437 break;
1438 case TPG_MOVE_NONE:
1439 tpg->mv_vert_step = 0;
1440 break;
1441 }
1442 if (factor < 0)
1443 tpg->mv_vert_step = tpg->src_height - tpg->mv_vert_step;
1444}
1445
1446/* Map the line number relative to the crop rectangle to a frame line number */
Hans Verkuildfff0482015-03-09 11:04:02 -03001447static unsigned tpg_calc_frameline(const struct tpg_data *tpg, unsigned src_y,
Hans Verkuil63881df2014-08-25 08:02:14 -03001448 unsigned field)
1449{
1450 switch (field) {
1451 case V4L2_FIELD_TOP:
1452 return tpg->crop.top + src_y * 2;
1453 case V4L2_FIELD_BOTTOM:
1454 return tpg->crop.top + src_y * 2 + 1;
1455 default:
1456 return src_y + tpg->crop.top;
1457 }
1458}
1459
1460/*
1461 * Map the line number relative to the compose rectangle to a destination
1462 * buffer line number.
1463 */
Hans Verkuildfff0482015-03-09 11:04:02 -03001464static unsigned tpg_calc_buffer_line(const struct tpg_data *tpg, unsigned y,
Hans Verkuil63881df2014-08-25 08:02:14 -03001465 unsigned field)
1466{
1467 y += tpg->compose.top;
1468 switch (field) {
1469 case V4L2_FIELD_SEQ_TB:
1470 if (y & 1)
1471 return tpg->buf_height / 2 + y / 2;
1472 return y / 2;
1473 case V4L2_FIELD_SEQ_BT:
1474 if (y & 1)
1475 return y / 2;
1476 return tpg->buf_height / 2 + y / 2;
1477 default:
1478 return y;
1479 }
1480}
1481
1482static void tpg_recalc(struct tpg_data *tpg)
1483{
1484 if (tpg->recalc_colors) {
1485 tpg->recalc_colors = false;
1486 tpg->recalc_lines = true;
Hans Verkuil481b97a2014-11-17 10:14:32 -03001487 tpg->real_ycbcr_enc = tpg->ycbcr_enc;
1488 tpg->real_quantization = tpg->quantization;
1489 if (tpg->ycbcr_enc == V4L2_YCBCR_ENC_DEFAULT) {
1490 switch (tpg->colorspace) {
1491 case V4L2_COLORSPACE_REC709:
1492 tpg->real_ycbcr_enc = V4L2_YCBCR_ENC_709;
1493 break;
1494 case V4L2_COLORSPACE_SRGB:
1495 tpg->real_ycbcr_enc = V4L2_YCBCR_ENC_SYCC;
1496 break;
1497 case V4L2_COLORSPACE_BT2020:
1498 tpg->real_ycbcr_enc = V4L2_YCBCR_ENC_BT2020;
1499 break;
1500 case V4L2_COLORSPACE_SMPTE240M:
1501 tpg->real_ycbcr_enc = V4L2_YCBCR_ENC_SMPTE240M;
1502 break;
1503 case V4L2_COLORSPACE_SMPTE170M:
1504 case V4L2_COLORSPACE_470_SYSTEM_M:
1505 case V4L2_COLORSPACE_470_SYSTEM_BG:
1506 case V4L2_COLORSPACE_ADOBERGB:
1507 default:
1508 tpg->real_ycbcr_enc = V4L2_YCBCR_ENC_601;
1509 break;
1510 }
1511 }
1512 if (tpg->quantization == V4L2_QUANTIZATION_DEFAULT) {
1513 tpg->real_quantization = V4L2_QUANTIZATION_FULL_RANGE;
1514 if (tpg->is_yuv) {
1515 switch (tpg->real_ycbcr_enc) {
1516 case V4L2_YCBCR_ENC_SYCC:
1517 case V4L2_YCBCR_ENC_XV601:
1518 case V4L2_YCBCR_ENC_XV709:
1519 break;
1520 default:
1521 tpg->real_quantization =
1522 V4L2_QUANTIZATION_LIM_RANGE;
1523 break;
1524 }
Hans Verkuilc0b50d92015-03-08 04:53:33 -03001525 } else if (tpg->colorspace == V4L2_COLORSPACE_BT2020) {
1526 /* R'G'B' BT.2020 is limited range */
1527 tpg->real_quantization =
1528 V4L2_QUANTIZATION_LIM_RANGE;
Hans Verkuil481b97a2014-11-17 10:14:32 -03001529 }
1530 }
Hans Verkuil63881df2014-08-25 08:02:14 -03001531 tpg_precalculate_colors(tpg);
1532 }
1533 if (tpg->recalc_square_border) {
1534 tpg->recalc_square_border = false;
1535 tpg_calculate_square_border(tpg);
1536 }
1537 if (tpg->recalc_lines) {
1538 tpg->recalc_lines = false;
1539 tpg_precalculate_line(tpg);
1540 }
1541}
1542
1543void tpg_calc_text_basep(struct tpg_data *tpg,
1544 u8 *basep[TPG_MAX_PLANES][2], unsigned p, u8 *vbuf)
1545{
1546 unsigned stride = tpg->bytesperline[p];
Hans Verkuil280abe42015-03-07 14:50:41 -03001547 unsigned h = tpg->buf_height;
Hans Verkuil63881df2014-08-25 08:02:14 -03001548
1549 tpg_recalc(tpg);
1550
1551 basep[p][0] = vbuf;
1552 basep[p][1] = vbuf;
Hans Verkuil280abe42015-03-07 14:50:41 -03001553 h /= tpg->vdownsampling[p];
Hans Verkuil63881df2014-08-25 08:02:14 -03001554 if (tpg->field == V4L2_FIELD_SEQ_TB)
Hans Verkuil280abe42015-03-07 14:50:41 -03001555 basep[p][1] += h * stride / 2;
Hans Verkuil63881df2014-08-25 08:02:14 -03001556 else if (tpg->field == V4L2_FIELD_SEQ_BT)
Hans Verkuil280abe42015-03-07 14:50:41 -03001557 basep[p][0] += h * stride / 2;
1558}
1559
1560static int tpg_pattern_avg(const struct tpg_data *tpg,
1561 unsigned pat1, unsigned pat2)
1562{
1563 unsigned pat_lines = tpg_get_pat_lines(tpg);
1564
1565 if (pat1 == (pat2 + 1) % pat_lines)
1566 return pat2;
1567 if (pat2 == (pat1 + 1) % pat_lines)
1568 return pat1;
1569 return -1;
Hans Verkuil63881df2014-08-25 08:02:14 -03001570}
1571
Hans Verkuile76036d2015-03-09 11:07:23 -03001572/*
1573 * This struct contains common parameters used by both the drawing of the
1574 * test pattern and the drawing of the extras (borders, square, etc.)
1575 */
1576struct tpg_draw_params {
1577 /* common data */
1578 bool is_tv;
1579 bool is_60hz;
1580 unsigned twopixsize;
1581 unsigned img_width;
1582 unsigned stride;
1583 unsigned hmax;
1584 unsigned frame_line;
1585 unsigned frame_line_next;
1586
1587 /* test pattern */
1588 unsigned mv_hor_old;
1589 unsigned mv_hor_new;
1590 unsigned mv_vert_old;
1591 unsigned mv_vert_new;
1592
1593 /* extras */
1594 unsigned wss_width;
1595 unsigned wss_random_offset;
1596 unsigned sav_eav_f;
1597 unsigned left_pillar_width;
1598 unsigned right_pillar_start;
1599};
1600
Hans Verkuilf0ce4fd2015-03-09 11:30:05 -03001601static void tpg_fill_params_pattern(const struct tpg_data *tpg, unsigned p,
1602 struct tpg_draw_params *params)
1603{
1604 params->mv_hor_old =
1605 tpg_hscale_div(tpg, p, tpg->mv_hor_count % tpg->src_width);
1606 params->mv_hor_new =
1607 tpg_hscale_div(tpg, p, (tpg->mv_hor_count + tpg->mv_hor_step) %
1608 tpg->src_width);
1609 params->mv_vert_old = tpg->mv_vert_count % tpg->src_height;
1610 params->mv_vert_new =
1611 (tpg->mv_vert_count + tpg->mv_vert_step) % tpg->src_height;
1612}
1613
Hans Verkuil07386b92015-03-09 11:39:19 -03001614static void tpg_fill_params_extras(const struct tpg_data *tpg,
1615 unsigned p,
1616 struct tpg_draw_params *params)
1617{
1618 unsigned left_pillar_width = 0;
1619 unsigned right_pillar_start = params->img_width;
1620
1621 params->wss_width = tpg->crop.left < tpg->src_width / 2 ?
1622 tpg->src_width / 2 - tpg->crop.left : 0;
1623 if (params->wss_width > tpg->crop.width)
1624 params->wss_width = tpg->crop.width;
1625 params->wss_width = tpg_hscale_div(tpg, p, params->wss_width);
1626 params->wss_random_offset =
1627 params->twopixsize * prandom_u32_max(tpg->src_width / 2);
1628
1629 if (tpg->crop.left < tpg->border.left) {
1630 left_pillar_width = tpg->border.left - tpg->crop.left;
1631 if (left_pillar_width > tpg->crop.width)
1632 left_pillar_width = tpg->crop.width;
1633 left_pillar_width = tpg_hscale_div(tpg, p, left_pillar_width);
1634 }
1635 params->left_pillar_width = left_pillar_width;
1636
1637 if (tpg->crop.left + tpg->crop.width >
1638 tpg->border.left + tpg->border.width) {
1639 right_pillar_start =
1640 tpg->border.left + tpg->border.width - tpg->crop.left;
1641 right_pillar_start =
1642 tpg_hscale_div(tpg, p, right_pillar_start);
1643 if (right_pillar_start > params->img_width)
1644 right_pillar_start = params->img_width;
1645 }
1646 params->right_pillar_start = right_pillar_start;
1647
1648 params->sav_eav_f = tpg->field ==
1649 (params->is_60hz ? V4L2_FIELD_TOP : V4L2_FIELD_BOTTOM);
1650}
1651
Hans Verkuilc6ff1c12015-03-09 11:47:48 -03001652static void tpg_fill_plane_extras(const struct tpg_data *tpg,
1653 const struct tpg_draw_params *params,
1654 unsigned p, unsigned h, u8 *vbuf)
1655{
1656 unsigned twopixsize = params->twopixsize;
1657 unsigned img_width = params->img_width;
1658 unsigned frame_line = params->frame_line;
1659 const struct v4l2_rect *sq = &tpg->square;
1660 const struct v4l2_rect *b = &tpg->border;
1661 const struct v4l2_rect *c = &tpg->crop;
1662
1663 if (params->is_tv && !params->is_60hz &&
1664 frame_line == 0 && params->wss_width) {
1665 /*
1666 * Replace the first half of the top line of a 50 Hz frame
1667 * with random data to simulate a WSS signal.
1668 */
1669 u8 *wss = tpg->random_line[p] + params->wss_random_offset;
1670
1671 memcpy(vbuf, wss, params->wss_width);
1672 }
1673
1674 if (tpg->show_border && frame_line >= b->top &&
1675 frame_line < b->top + b->height) {
1676 unsigned bottom = b->top + b->height - 1;
1677 unsigned left = params->left_pillar_width;
1678 unsigned right = params->right_pillar_start;
1679
1680 if (frame_line == b->top || frame_line == b->top + 1 ||
1681 frame_line == bottom || frame_line == bottom - 1) {
1682 memcpy(vbuf + left, tpg->contrast_line[p],
1683 right - left);
1684 } else {
1685 if (b->left >= c->left &&
1686 b->left < c->left + c->width)
1687 memcpy(vbuf + left,
1688 tpg->contrast_line[p], twopixsize);
1689 if (b->left + b->width > c->left &&
1690 b->left + b->width <= c->left + c->width)
1691 memcpy(vbuf + right - twopixsize,
1692 tpg->contrast_line[p], twopixsize);
1693 }
1694 }
1695 if (tpg->qual != TPG_QUAL_NOISE && frame_line >= b->top &&
1696 frame_line < b->top + b->height) {
1697 memcpy(vbuf, tpg->black_line[p], params->left_pillar_width);
1698 memcpy(vbuf + params->right_pillar_start, tpg->black_line[p],
1699 img_width - params->right_pillar_start);
1700 }
1701 if (tpg->show_square && frame_line >= sq->top &&
1702 frame_line < sq->top + sq->height &&
1703 sq->left < c->left + c->width &&
1704 sq->left + sq->width >= c->left) {
1705 unsigned left = sq->left;
1706 unsigned width = sq->width;
1707
1708 if (c->left > left) {
1709 width -= c->left - left;
1710 left = c->left;
1711 }
1712 if (c->left + c->width < left + width)
1713 width -= left + width - c->left - c->width;
1714 left -= c->left;
1715 left = tpg_hscale_div(tpg, p, left);
1716 width = tpg_hscale_div(tpg, p, width);
1717 memcpy(vbuf + left, tpg->contrast_line[p], width);
1718 }
1719 if (tpg->insert_sav) {
1720 unsigned offset = tpg_hdiv(tpg, p, tpg->compose.width / 3);
1721 u8 *p = vbuf + offset;
1722 unsigned vact = 0, hact = 0;
1723
1724 p[0] = 0xff;
1725 p[1] = 0;
1726 p[2] = 0;
1727 p[3] = 0x80 | (params->sav_eav_f << 6) |
1728 (vact << 5) | (hact << 4) |
1729 ((hact ^ vact) << 3) |
1730 ((hact ^ params->sav_eav_f) << 2) |
1731 ((params->sav_eav_f ^ vact) << 1) |
1732 (hact ^ vact ^ params->sav_eav_f);
1733 }
1734 if (tpg->insert_eav) {
1735 unsigned offset = tpg_hdiv(tpg, p, tpg->compose.width * 2 / 3);
1736 u8 *p = vbuf + offset;
1737 unsigned vact = 0, hact = 1;
1738
1739 p[0] = 0xff;
1740 p[1] = 0;
1741 p[2] = 0;
1742 p[3] = 0x80 | (params->sav_eav_f << 6) |
1743 (vact << 5) | (hact << 4) |
1744 ((hact ^ vact) << 3) |
1745 ((hact ^ params->sav_eav_f) << 2) |
1746 ((params->sav_eav_f ^ vact) << 1) |
1747 (hact ^ vact ^ params->sav_eav_f);
1748 }
1749}
1750
Hans Verkuilecb9e912015-03-09 11:52:43 -03001751static void tpg_fill_plane_pattern(const struct tpg_data *tpg,
1752 const struct tpg_draw_params *params,
1753 unsigned p, unsigned h, u8 *vbuf)
1754{
1755 unsigned twopixsize = params->twopixsize;
1756 unsigned img_width = params->img_width;
1757 unsigned mv_hor_old = params->mv_hor_old;
1758 unsigned mv_hor_new = params->mv_hor_new;
1759 unsigned mv_vert_old = params->mv_vert_old;
1760 unsigned mv_vert_new = params->mv_vert_new;
1761 unsigned frame_line = params->frame_line;
1762 unsigned frame_line_next = params->frame_line_next;
1763 unsigned line_offset = tpg_hscale_div(tpg, p, tpg->crop.left);
1764 bool even;
1765 bool fill_blank = false;
1766 unsigned pat_line_old;
1767 unsigned pat_line_new;
1768 u8 *linestart_older;
1769 u8 *linestart_newer;
1770 u8 *linestart_top;
1771 u8 *linestart_bottom;
1772
1773 even = !(frame_line & 1);
1774
1775 if (h >= params->hmax) {
1776 if (params->hmax == tpg->compose.height)
1777 return;
1778 if (!tpg->perc_fill_blank)
1779 return;
1780 fill_blank = true;
1781 }
1782
1783 if (tpg->vflip) {
1784 frame_line = tpg->src_height - frame_line - 1;
1785 frame_line_next = tpg->src_height - frame_line_next - 1;
1786 }
1787
1788 if (fill_blank) {
1789 linestart_older = tpg->contrast_line[p];
1790 linestart_newer = tpg->contrast_line[p];
1791 } else if (tpg->qual != TPG_QUAL_NOISE &&
1792 (frame_line < tpg->border.top ||
1793 frame_line >= tpg->border.top + tpg->border.height)) {
1794 linestart_older = tpg->black_line[p];
1795 linestart_newer = tpg->black_line[p];
1796 } else if (tpg->pattern == TPG_PAT_NOISE || tpg->qual == TPG_QUAL_NOISE) {
1797 linestart_older = tpg->random_line[p] +
1798 twopixsize * prandom_u32_max(tpg->src_width / 2);
1799 linestart_newer = tpg->random_line[p] +
1800 twopixsize * prandom_u32_max(tpg->src_width / 2);
1801 } else {
1802 unsigned frame_line_old =
1803 (frame_line + mv_vert_old) % tpg->src_height;
1804 unsigned frame_line_new =
1805 (frame_line + mv_vert_new) % tpg->src_height;
1806 unsigned pat_line_next_old;
1807 unsigned pat_line_next_new;
1808
1809 pat_line_old = tpg_get_pat_line(tpg, frame_line_old);
1810 pat_line_new = tpg_get_pat_line(tpg, frame_line_new);
1811 linestart_older = tpg->lines[pat_line_old][p] + mv_hor_old;
1812 linestart_newer = tpg->lines[pat_line_new][p] + mv_hor_new;
1813
1814 if (tpg->vdownsampling[p] > 1 && frame_line != frame_line_next) {
1815 int avg_pat;
1816
1817 /*
1818 * Now decide whether we need to use downsampled_lines[].
1819 * That's necessary if the two lines use different patterns.
1820 */
1821 pat_line_next_old = tpg_get_pat_line(tpg,
1822 (frame_line_next + mv_vert_old) % tpg->src_height);
1823 pat_line_next_new = tpg_get_pat_line(tpg,
1824 (frame_line_next + mv_vert_new) % tpg->src_height);
1825
1826 switch (tpg->field) {
1827 case V4L2_FIELD_INTERLACED:
1828 case V4L2_FIELD_INTERLACED_BT:
1829 case V4L2_FIELD_INTERLACED_TB:
1830 avg_pat = tpg_pattern_avg(tpg, pat_line_old, pat_line_new);
1831 if (avg_pat < 0)
1832 break;
1833 linestart_older = tpg->downsampled_lines[avg_pat][p] + mv_hor_old;
1834 linestart_newer = linestart_older;
1835 break;
1836 case V4L2_FIELD_NONE:
1837 case V4L2_FIELD_TOP:
1838 case V4L2_FIELD_BOTTOM:
1839 case V4L2_FIELD_SEQ_BT:
1840 case V4L2_FIELD_SEQ_TB:
1841 avg_pat = tpg_pattern_avg(tpg, pat_line_old, pat_line_next_old);
1842 if (avg_pat >= 0)
1843 linestart_older = tpg->downsampled_lines[avg_pat][p] +
1844 mv_hor_old;
1845 avg_pat = tpg_pattern_avg(tpg, pat_line_new, pat_line_next_new);
1846 if (avg_pat >= 0)
1847 linestart_newer = tpg->downsampled_lines[avg_pat][p] +
1848 mv_hor_new;
1849 break;
1850 }
1851 }
1852 linestart_older += line_offset;
1853 linestart_newer += line_offset;
1854 }
1855 if (tpg->field_alternate) {
1856 linestart_top = linestart_bottom = linestart_older;
1857 } else if (params->is_60hz) {
1858 linestart_top = linestart_newer;
1859 linestart_bottom = linestart_older;
1860 } else {
1861 linestart_top = linestart_older;
1862 linestart_bottom = linestart_newer;
1863 }
1864
1865 switch (tpg->field) {
1866 case V4L2_FIELD_INTERLACED:
1867 case V4L2_FIELD_INTERLACED_TB:
1868 case V4L2_FIELD_SEQ_TB:
1869 case V4L2_FIELD_SEQ_BT:
1870 if (even)
1871 memcpy(vbuf, linestart_top, img_width);
1872 else
1873 memcpy(vbuf, linestart_bottom, img_width);
1874 break;
1875 case V4L2_FIELD_INTERLACED_BT:
1876 if (even)
1877 memcpy(vbuf, linestart_bottom, img_width);
1878 else
1879 memcpy(vbuf, linestart_top, img_width);
1880 break;
1881 case V4L2_FIELD_TOP:
1882 memcpy(vbuf, linestart_top, img_width);
1883 break;
1884 case V4L2_FIELD_BOTTOM:
1885 memcpy(vbuf, linestart_bottom, img_width);
1886 break;
1887 case V4L2_FIELD_NONE:
1888 default:
1889 memcpy(vbuf, linestart_older, img_width);
1890 break;
1891 }
1892}
1893
1894void tpg_fill_plane_buffer(struct tpg_data *tpg, v4l2_std_id std,
1895 unsigned p, u8 *vbuf)
Hans Verkuil63881df2014-08-25 08:02:14 -03001896{
Hans Verkuil5e729392015-03-09 11:26:43 -03001897 struct tpg_draw_params params;
Hans Verkuil63881df2014-08-25 08:02:14 -03001898 unsigned factor = V4L2_FIELD_HAS_T_OR_B(tpg->field) ? 2 : 1;
Hans Verkuil63881df2014-08-25 08:02:14 -03001899
1900 /* Coarse scaling with Bresenham */
1901 unsigned int_part = (tpg->crop.height / factor) / tpg->compose.height;
1902 unsigned fract_part = (tpg->crop.height / factor) % tpg->compose.height;
1903 unsigned src_y = 0;
1904 unsigned error = 0;
Hans Verkuilecb9e912015-03-09 11:52:43 -03001905 unsigned h;
Hans Verkuil63881df2014-08-25 08:02:14 -03001906
1907 tpg_recalc(tpg);
1908
Hans Verkuil5e729392015-03-09 11:26:43 -03001909 params.is_tv = std;
1910 params.is_60hz = std & V4L2_STD_525_60;
1911 params.twopixsize = tpg->twopixelsize[p];
1912 params.img_width = tpg_hdiv(tpg, p, tpg->compose.width);
1913 params.stride = tpg->bytesperline[p];
1914 params.hmax = (tpg->compose.height * tpg->perc_fill) / 100;
1915
Hans Verkuilf0ce4fd2015-03-09 11:30:05 -03001916 tpg_fill_params_pattern(tpg, p, &params);
Hans Verkuil07386b92015-03-09 11:39:19 -03001917 tpg_fill_params_extras(tpg, p, &params);
1918
Hans Verkuil9991def2015-03-08 05:53:10 -03001919 vbuf += tpg_hdiv(tpg, p, tpg->compose.left);
Hans Verkuil63881df2014-08-25 08:02:14 -03001920
1921 for (h = 0; h < tpg->compose.height; h++) {
Hans Verkuil63881df2014-08-25 08:02:14 -03001922 unsigned buf_line;
Hans Verkuil63881df2014-08-25 08:02:14 -03001923
Hans Verkuilc6ff1c12015-03-09 11:47:48 -03001924 params.frame_line = tpg_calc_frameline(tpg, src_y, tpg->field);
1925 params.frame_line_next = params.frame_line;
Hans Verkuil63881df2014-08-25 08:02:14 -03001926 buf_line = tpg_calc_buffer_line(tpg, h, tpg->field);
1927 src_y += int_part;
1928 error += fract_part;
1929 if (error >= tpg->compose.height) {
1930 error -= tpg->compose.height;
1931 src_y++;
1932 }
1933
Hans Verkuilecb9e912015-03-09 11:52:43 -03001934 if (tpg->vdownsampling[p] > 1) {
Hans Verkuil280abe42015-03-07 14:50:41 -03001935 /*
1936 * When doing vertical downsampling the field setting
1937 * matters: for SEQ_BT/TB we downsample each field
1938 * separately (i.e. lines 0+2 are combined, as are
1939 * lines 1+3), for the other field settings we combine
1940 * odd and even lines. Doing that for SEQ_BT/TB would
1941 * be really weird.
1942 */
1943 if (tpg->field == V4L2_FIELD_SEQ_BT ||
1944 tpg->field == V4L2_FIELD_SEQ_TB) {
Hans Verkuilecb9e912015-03-09 11:52:43 -03001945 unsigned next_src_y = src_y;
1946
Hans Verkuil280abe42015-03-07 14:50:41 -03001947 if ((h & 3) >= 2)
1948 continue;
Hans Verkuilecb9e912015-03-09 11:52:43 -03001949 next_src_y += int_part;
1950 if (error + fract_part >= tpg->compose.height)
1951 next_src_y++;
1952 params.frame_line_next =
1953 tpg_calc_frameline(tpg, next_src_y, tpg->field);
1954 } else {
1955 if (h & 1)
1956 continue;
1957 params.frame_line_next =
1958 tpg_calc_frameline(tpg, src_y, tpg->field);
Hans Verkuil280abe42015-03-07 14:50:41 -03001959 }
1960
Hans Verkuilecb9e912015-03-09 11:52:43 -03001961 buf_line /= tpg->vdownsampling[p];
Hans Verkuil280abe42015-03-07 14:50:41 -03001962 }
Hans Verkuilecb9e912015-03-09 11:52:43 -03001963 tpg_fill_plane_pattern(tpg, &params, p, h,
1964 vbuf + buf_line * params.stride);
Hans Verkuilc6ff1c12015-03-09 11:47:48 -03001965 tpg_fill_plane_extras(tpg, &params, p, h,
1966 vbuf + buf_line * params.stride);
Hans Verkuil63881df2014-08-25 08:02:14 -03001967 }
1968}
Hans Verkuil4db22042015-03-07 13:39:01 -03001969
1970void tpg_fillbuffer(struct tpg_data *tpg, v4l2_std_id std, unsigned p, u8 *vbuf)
1971{
1972 unsigned offset = 0;
1973 unsigned i;
1974
1975 if (tpg->buffers > 1) {
1976 tpg_fill_plane_buffer(tpg, std, p, vbuf);
1977 return;
1978 }
1979
1980 for (i = 0; i < tpg->planes; i++) {
1981 tpg_fill_plane_buffer(tpg, std, i, vbuf + offset);
1982 offset += tpg_calc_plane_size(tpg, i);
1983 }
1984}