blob: 0e2b8d4b886474c411d8d0d2c17462b707c88b90 [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) {
Hans Verkuil71491062015-03-12 15:40:36 -0300191 case V4L2_PIX_FMT_RGB332:
Hans Verkuil63881df2014-08-25 08:02:14 -0300192 case V4L2_PIX_FMT_RGB565:
193 case V4L2_PIX_FMT_RGB565X:
Hans Verkuil8aca2302015-03-11 08:14:34 -0300194 case V4L2_PIX_FMT_RGB444:
195 case V4L2_PIX_FMT_XRGB444:
196 case V4L2_PIX_FMT_ARGB444:
Hans Verkuil63881df2014-08-25 08:02:14 -0300197 case V4L2_PIX_FMT_RGB555:
198 case V4L2_PIX_FMT_XRGB555:
199 case V4L2_PIX_FMT_ARGB555:
200 case V4L2_PIX_FMT_RGB555X:
Hans Verkuil8f1ff542015-03-12 05:08:01 -0300201 case V4L2_PIX_FMT_XRGB555X:
202 case V4L2_PIX_FMT_ARGB555X:
Hans Verkuil68cd4e92015-03-13 05:36:08 -0300203 case V4L2_PIX_FMT_BGR666:
Hans Verkuil63881df2014-08-25 08:02:14 -0300204 case V4L2_PIX_FMT_RGB24:
205 case V4L2_PIX_FMT_BGR24:
206 case V4L2_PIX_FMT_RGB32:
207 case V4L2_PIX_FMT_BGR32:
208 case V4L2_PIX_FMT_XRGB32:
209 case V4L2_PIX_FMT_XBGR32:
210 case V4L2_PIX_FMT_ARGB32:
211 case V4L2_PIX_FMT_ABGR32:
Hans Verkuil51f30962015-03-07 14:57:50 -0300212 case V4L2_PIX_FMT_GREY:
Mauro Carvalho Chehab6c515a42014-09-03 15:53:45 -0300213 tpg->is_yuv = false;
Hans Verkuil63881df2014-08-25 08:02:14 -0300214 break;
Hans Verkuil68c90d62015-03-07 14:55:09 -0300215 case V4L2_PIX_FMT_YUV420M:
216 case V4L2_PIX_FMT_YVU420M:
217 tpg->buffers = 3;
218 /* fall through */
219 case V4L2_PIX_FMT_YUV420:
220 case V4L2_PIX_FMT_YVU420:
221 tpg->vdownsampling[1] = 2;
222 tpg->vdownsampling[2] = 2;
223 tpg->hdownsampling[1] = 2;
224 tpg->hdownsampling[2] = 2;
225 tpg->planes = 3;
226 tpg->is_yuv = true;
227 break;
228 case V4L2_PIX_FMT_YUV422P:
229 tpg->vdownsampling[1] = 1;
230 tpg->vdownsampling[2] = 1;
231 tpg->hdownsampling[1] = 2;
232 tpg->hdownsampling[2] = 2;
233 tpg->planes = 3;
234 tpg->is_yuv = true;
235 break;
Hans Verkuil63881df2014-08-25 08:02:14 -0300236 case V4L2_PIX_FMT_NV16M:
237 case V4L2_PIX_FMT_NV61M:
Hans Verkuil68c90d62015-03-07 14:55:09 -0300238 tpg->buffers = 2;
239 /* fall through */
240 case V4L2_PIX_FMT_NV16:
241 case V4L2_PIX_FMT_NV61:
Hans Verkuilba01f672015-03-07 13:57:27 -0300242 tpg->vdownsampling[1] = 1;
243 tpg->hdownsampling[1] = 1;
Hans Verkuil9991def2015-03-08 05:53:10 -0300244 tpg->hmask[1] = ~1;
Hans Verkuil63881df2014-08-25 08:02:14 -0300245 tpg->planes = 2;
Hans Verkuil68c90d62015-03-07 14:55:09 -0300246 tpg->is_yuv = true;
247 break;
248 case V4L2_PIX_FMT_NV12M:
249 case V4L2_PIX_FMT_NV21M:
250 tpg->buffers = 2;
251 /* fall through */
252 case V4L2_PIX_FMT_NV12:
253 case V4L2_PIX_FMT_NV21:
254 tpg->vdownsampling[1] = 2;
255 tpg->hdownsampling[1] = 1;
Hans Verkuil9991def2015-03-08 05:53:10 -0300256 tpg->hmask[1] = ~1;
Hans Verkuil68c90d62015-03-07 14:55:09 -0300257 tpg->planes = 2;
258 tpg->is_yuv = true;
259 break;
Hans Verkuildde72bd2015-03-13 05:51:21 -0300260 case V4L2_PIX_FMT_NV24:
261 case V4L2_PIX_FMT_NV42:
262 tpg->vdownsampling[1] = 1;
263 tpg->hdownsampling[1] = 1;
264 tpg->planes = 2;
265 tpg->is_yuv = true;
266 break;
Hans Verkuil63881df2014-08-25 08:02:14 -0300267 case V4L2_PIX_FMT_YUYV:
268 case V4L2_PIX_FMT_UYVY:
269 case V4L2_PIX_FMT_YVYU:
270 case V4L2_PIX_FMT_VYUY:
Hans Verkuil9991def2015-03-08 05:53:10 -0300271 tpg->hmask[0] = ~1;
Mauro Carvalho Chehab6c515a42014-09-03 15:53:45 -0300272 tpg->is_yuv = true;
Hans Verkuil63881df2014-08-25 08:02:14 -0300273 break;
274 default:
275 return false;
276 }
277
278 switch (fourcc) {
Hans Verkuil71491062015-03-12 15:40:36 -0300279 case V4L2_PIX_FMT_RGB332:
280 tpg->twopixelsize[0] = 2;
281 break;
Hans Verkuil63881df2014-08-25 08:02:14 -0300282 case V4L2_PIX_FMT_RGB565:
283 case V4L2_PIX_FMT_RGB565X:
Hans Verkuil8aca2302015-03-11 08:14:34 -0300284 case V4L2_PIX_FMT_RGB444:
285 case V4L2_PIX_FMT_XRGB444:
286 case V4L2_PIX_FMT_ARGB444:
Hans Verkuil63881df2014-08-25 08:02:14 -0300287 case V4L2_PIX_FMT_RGB555:
288 case V4L2_PIX_FMT_XRGB555:
289 case V4L2_PIX_FMT_ARGB555:
290 case V4L2_PIX_FMT_RGB555X:
Hans Verkuil8f1ff542015-03-12 05:08:01 -0300291 case V4L2_PIX_FMT_XRGB555X:
292 case V4L2_PIX_FMT_ARGB555X:
Hans Verkuil63881df2014-08-25 08:02:14 -0300293 case V4L2_PIX_FMT_YUYV:
294 case V4L2_PIX_FMT_UYVY:
295 case V4L2_PIX_FMT_YVYU:
296 case V4L2_PIX_FMT_VYUY:
297 tpg->twopixelsize[0] = 2 * 2;
298 break;
299 case V4L2_PIX_FMT_RGB24:
300 case V4L2_PIX_FMT_BGR24:
301 tpg->twopixelsize[0] = 2 * 3;
302 break;
Hans Verkuil68cd4e92015-03-13 05:36:08 -0300303 case V4L2_PIX_FMT_BGR666:
Hans Verkuil63881df2014-08-25 08:02:14 -0300304 case V4L2_PIX_FMT_RGB32:
305 case V4L2_PIX_FMT_BGR32:
306 case V4L2_PIX_FMT_XRGB32:
307 case V4L2_PIX_FMT_XBGR32:
308 case V4L2_PIX_FMT_ARGB32:
309 case V4L2_PIX_FMT_ABGR32:
310 tpg->twopixelsize[0] = 2 * 4;
311 break;
Hans Verkuil51f30962015-03-07 14:57:50 -0300312 case V4L2_PIX_FMT_GREY:
313 tpg->twopixelsize[0] = 2;
314 break;
Hans Verkuil68c90d62015-03-07 14:55:09 -0300315 case V4L2_PIX_FMT_NV12:
316 case V4L2_PIX_FMT_NV21:
317 case V4L2_PIX_FMT_NV12M:
318 case V4L2_PIX_FMT_NV21M:
319 tpg->twopixelsize[0] = 2;
320 tpg->twopixelsize[1] = 2;
321 break;
322 case V4L2_PIX_FMT_NV16:
323 case V4L2_PIX_FMT_NV61:
Hans Verkuil63881df2014-08-25 08:02:14 -0300324 case V4L2_PIX_FMT_NV16M:
325 case V4L2_PIX_FMT_NV61M:
326 tpg->twopixelsize[0] = 2;
327 tpg->twopixelsize[1] = 2;
328 break;
Hans Verkuil68c90d62015-03-07 14:55:09 -0300329 case V4L2_PIX_FMT_YUV422P:
330 case V4L2_PIX_FMT_YUV420:
331 case V4L2_PIX_FMT_YVU420:
332 case V4L2_PIX_FMT_YUV420M:
333 case V4L2_PIX_FMT_YVU420M:
334 tpg->twopixelsize[0] = 2;
335 tpg->twopixelsize[1] = 2;
336 tpg->twopixelsize[2] = 2;
337 break;
Hans Verkuildde72bd2015-03-13 05:51:21 -0300338 case V4L2_PIX_FMT_NV24:
339 case V4L2_PIX_FMT_NV42:
340 tpg->twopixelsize[0] = 2;
341 tpg->twopixelsize[1] = 4;
342 break;
Hans Verkuil63881df2014-08-25 08:02:14 -0300343 }
344 return true;
345}
346
347void tpg_s_crop_compose(struct tpg_data *tpg, const struct v4l2_rect *crop,
348 const struct v4l2_rect *compose)
349{
350 tpg->crop = *crop;
351 tpg->compose = *compose;
352 tpg->scaled_width = (tpg->src_width * tpg->compose.width +
353 tpg->crop.width - 1) / tpg->crop.width;
354 tpg->scaled_width &= ~1;
355 if (tpg->scaled_width > tpg->max_line_width)
356 tpg->scaled_width = tpg->max_line_width;
357 if (tpg->scaled_width < 2)
358 tpg->scaled_width = 2;
359 tpg->recalc_lines = true;
360}
361
362void tpg_reset_source(struct tpg_data *tpg, unsigned width, unsigned height,
Hans Verkuil73d81022014-09-03 10:18:57 -0300363 u32 field)
Hans Verkuil63881df2014-08-25 08:02:14 -0300364{
365 unsigned p;
366
367 tpg->src_width = width;
368 tpg->src_height = height;
369 tpg->field = field;
370 tpg->buf_height = height;
371 if (V4L2_FIELD_HAS_T_OR_B(field))
372 tpg->buf_height /= 2;
373 tpg->scaled_width = width;
374 tpg->crop.top = tpg->crop.left = 0;
375 tpg->crop.width = width;
376 tpg->crop.height = height;
377 tpg->compose.top = tpg->compose.left = 0;
378 tpg->compose.width = width;
379 tpg->compose.height = tpg->buf_height;
380 for (p = 0; p < tpg->planes; p++)
Hans Verkuilba01f672015-03-07 13:57:27 -0300381 tpg->bytesperline[p] = (width * tpg->twopixelsize[p]) /
382 (2 * tpg->hdownsampling[p]);
Hans Verkuil63881df2014-08-25 08:02:14 -0300383 tpg->recalc_square_border = true;
384}
385
386static enum tpg_color tpg_get_textbg_color(struct tpg_data *tpg)
387{
388 switch (tpg->pattern) {
389 case TPG_PAT_BLACK:
390 return TPG_COLOR_100_WHITE;
391 case TPG_PAT_CSC_COLORBAR:
392 return TPG_COLOR_CSC_BLACK;
393 default:
394 return TPG_COLOR_100_BLACK;
395 }
396}
397
398static enum tpg_color tpg_get_textfg_color(struct tpg_data *tpg)
399{
400 switch (tpg->pattern) {
401 case TPG_PAT_75_COLORBAR:
402 case TPG_PAT_CSC_COLORBAR:
403 return TPG_COLOR_CSC_WHITE;
404 case TPG_PAT_BLACK:
405 return TPG_COLOR_100_BLACK;
406 default:
407 return TPG_COLOR_100_WHITE;
408 }
409}
410
Hans Verkuil481b97a2014-11-17 10:14:32 -0300411static inline int rec709_to_linear(int v)
Hans Verkuil63881df2014-08-25 08:02:14 -0300412{
Hans Verkuil481b97a2014-11-17 10:14:32 -0300413 v = clamp(v, 0, 0xff0);
414 return tpg_rec709_to_linear[v];
415}
416
417static inline int linear_to_rec709(int v)
418{
419 v = clamp(v, 0, 0xff0);
420 return tpg_linear_to_rec709[v];
421}
422
423static void rgb2ycbcr(const int m[3][3], int r, int g, int b,
424 int y_offset, int *y, int *cb, int *cr)
425{
426 *y = ((m[0][0] * r + m[0][1] * g + m[0][2] * b) >> 16) + (y_offset << 4);
427 *cb = ((m[1][0] * r + m[1][1] * g + m[1][2] * b) >> 16) + (128 << 4);
428 *cr = ((m[2][0] * r + m[2][1] * g + m[2][2] * b) >> 16) + (128 << 4);
429}
430
431static void color_to_ycbcr(struct tpg_data *tpg, int r, int g, int b,
432 int *y, int *cb, int *cr)
433{
434#define COEFF(v, r) ((int)(0.5 + (v) * (r) * 256.0))
435
436 static const int bt601[3][3] = {
437 { COEFF(0.299, 219), COEFF(0.587, 219), COEFF(0.114, 219) },
438 { COEFF(-0.169, 224), COEFF(-0.331, 224), COEFF(0.5, 224) },
439 { COEFF(0.5, 224), COEFF(-0.419, 224), COEFF(-0.081, 224) },
440 };
441 static const int bt601_full[3][3] = {
442 { COEFF(0.299, 255), COEFF(0.587, 255), COEFF(0.114, 255) },
443 { COEFF(-0.169, 255), COEFF(-0.331, 255), COEFF(0.5, 255) },
444 { COEFF(0.5, 255), COEFF(-0.419, 255), COEFF(-0.081, 255) },
445 };
446 static const int rec709[3][3] = {
447 { COEFF(0.2126, 219), COEFF(0.7152, 219), COEFF(0.0722, 219) },
448 { COEFF(-0.1146, 224), COEFF(-0.3854, 224), COEFF(0.5, 224) },
449 { COEFF(0.5, 224), COEFF(-0.4542, 224), COEFF(-0.0458, 224) },
450 };
451 static const int rec709_full[3][3] = {
452 { COEFF(0.2126, 255), COEFF(0.7152, 255), COEFF(0.0722, 255) },
453 { COEFF(-0.1146, 255), COEFF(-0.3854, 255), COEFF(0.5, 255) },
454 { COEFF(0.5, 255), COEFF(-0.4542, 255), COEFF(-0.0458, 255) },
455 };
456 static const int smpte240m[3][3] = {
457 { COEFF(0.212, 219), COEFF(0.701, 219), COEFF(0.087, 219) },
458 { COEFF(-0.116, 224), COEFF(-0.384, 224), COEFF(0.5, 224) },
459 { COEFF(0.5, 224), COEFF(-0.445, 224), COEFF(-0.055, 224) },
460 };
461 static const int bt2020[3][3] = {
462 { COEFF(0.2726, 219), COEFF(0.6780, 219), COEFF(0.0593, 219) },
463 { COEFF(-0.1396, 224), COEFF(-0.3604, 224), COEFF(0.5, 224) },
464 { COEFF(0.5, 224), COEFF(-0.4629, 224), COEFF(-0.0405, 224) },
465 };
466 bool full = tpg->real_quantization == V4L2_QUANTIZATION_FULL_RANGE;
Hans Verkuilafad4dd2015-01-27 13:46:17 -0300467 unsigned y_offset = full ? 0 : 16;
Hans Verkuil481b97a2014-11-17 10:14:32 -0300468 int lin_y, yc;
469
470 switch (tpg->real_ycbcr_enc) {
471 case V4L2_YCBCR_ENC_601:
472 case V4L2_YCBCR_ENC_XV601:
473 case V4L2_YCBCR_ENC_SYCC:
Hans Verkuilafad4dd2015-01-27 13:46:17 -0300474 rgb2ycbcr(full ? bt601_full : bt601, r, g, b, y_offset, y, cb, cr);
Hans Verkuil481b97a2014-11-17 10:14:32 -0300475 break;
476 case V4L2_YCBCR_ENC_BT2020:
477 rgb2ycbcr(bt2020, r, g, b, 16, y, cb, cr);
478 break;
479 case V4L2_YCBCR_ENC_BT2020_CONST_LUM:
480 lin_y = (COEFF(0.2627, 255) * rec709_to_linear(r) +
481 COEFF(0.6780, 255) * rec709_to_linear(g) +
482 COEFF(0.0593, 255) * rec709_to_linear(b)) >> 16;
483 yc = linear_to_rec709(lin_y);
484 *y = (yc * 219) / 255 + (16 << 4);
485 if (b <= yc)
486 *cb = (((b - yc) * COEFF(1.0 / 1.9404, 224)) >> 16) + (128 << 4);
487 else
488 *cb = (((b - yc) * COEFF(1.0 / 1.5816, 224)) >> 16) + (128 << 4);
489 if (r <= yc)
490 *cr = (((r - yc) * COEFF(1.0 / 1.7184, 224)) >> 16) + (128 << 4);
491 else
492 *cr = (((r - yc) * COEFF(1.0 / 0.9936, 224)) >> 16) + (128 << 4);
493 break;
494 case V4L2_YCBCR_ENC_SMPTE240M:
495 rgb2ycbcr(smpte240m, r, g, b, 16, y, cb, cr);
496 break;
497 case V4L2_YCBCR_ENC_709:
498 case V4L2_YCBCR_ENC_XV709:
Hans Verkuil63881df2014-08-25 08:02:14 -0300499 default:
Hans Verkuilafad4dd2015-01-27 13:46:17 -0300500 rgb2ycbcr(full ? rec709_full : rec709, r, g, b, y_offset, y, cb, cr);
Hans Verkuil481b97a2014-11-17 10:14:32 -0300501 break;
Hans Verkuil63881df2014-08-25 08:02:14 -0300502 }
503}
504
Hans Verkuil481b97a2014-11-17 10:14:32 -0300505static void ycbcr2rgb(const int m[3][3], int y, int cb, int cr,
506 int y_offset, int *r, int *g, int *b)
Hans Verkuil63881df2014-08-25 08:02:14 -0300507{
Hans Verkuil481b97a2014-11-17 10:14:32 -0300508 y -= y_offset << 4;
Hans Verkuil63881df2014-08-25 08:02:14 -0300509 cb -= 128 << 4;
510 cr -= 128 << 4;
Hans Verkuil481b97a2014-11-17 10:14:32 -0300511 *r = m[0][0] * y + m[0][1] * cb + m[0][2] * cr;
512 *g = m[1][0] * y + m[1][1] * cb + m[1][2] * cr;
513 *b = m[2][0] * y + m[2][1] * cb + m[2][2] * cr;
514 *r = clamp(*r >> 12, 0, 0xff0);
515 *g = clamp(*g >> 12, 0, 0xff0);
516 *b = clamp(*b >> 12, 0, 0xff0);
Hans Verkuil63881df2014-08-25 08:02:14 -0300517}
518
Hans Verkuil481b97a2014-11-17 10:14:32 -0300519static void ycbcr_to_color(struct tpg_data *tpg, int y, int cb, int cr,
520 int *r, int *g, int *b)
Hans Verkuil63881df2014-08-25 08:02:14 -0300521{
Hans Verkuil481b97a2014-11-17 10:14:32 -0300522#undef COEFF
523#define COEFF(v, r) ((int)(0.5 + (v) * ((255.0 * 255.0 * 16.0) / (r))))
524 static const int bt601[3][3] = {
525 { COEFF(1, 219), COEFF(0, 224), COEFF(1.4020, 224) },
526 { COEFF(1, 219), COEFF(-0.3441, 224), COEFF(-0.7141, 224) },
527 { COEFF(1, 219), COEFF(1.7720, 224), COEFF(0, 224) },
528 };
529 static const int bt601_full[3][3] = {
530 { COEFF(1, 255), COEFF(0, 255), COEFF(1.4020, 255) },
531 { COEFF(1, 255), COEFF(-0.3441, 255), COEFF(-0.7141, 255) },
532 { COEFF(1, 255), COEFF(1.7720, 255), COEFF(0, 255) },
533 };
534 static const int rec709[3][3] = {
535 { COEFF(1, 219), COEFF(0, 224), COEFF(1.5748, 224) },
536 { COEFF(1, 219), COEFF(-0.1873, 224), COEFF(-0.4681, 224) },
537 { COEFF(1, 219), COEFF(1.8556, 224), COEFF(0, 224) },
538 };
539 static const int rec709_full[3][3] = {
540 { COEFF(1, 255), COEFF(0, 255), COEFF(1.5748, 255) },
541 { COEFF(1, 255), COEFF(-0.1873, 255), COEFF(-0.4681, 255) },
542 { COEFF(1, 255), COEFF(1.8556, 255), COEFF(0, 255) },
543 };
544 static const int smpte240m[3][3] = {
545 { COEFF(1, 219), COEFF(0, 224), COEFF(1.5756, 224) },
546 { COEFF(1, 219), COEFF(-0.2253, 224), COEFF(-0.4767, 224) },
547 { COEFF(1, 219), COEFF(1.8270, 224), COEFF(0, 224) },
548 };
549 static const int bt2020[3][3] = {
550 { COEFF(1, 219), COEFF(0, 224), COEFF(1.4746, 224) },
551 { COEFF(1, 219), COEFF(-0.1646, 224), COEFF(-0.5714, 224) },
552 { COEFF(1, 219), COEFF(1.8814, 224), COEFF(0, 224) },
553 };
554 bool full = tpg->real_quantization == V4L2_QUANTIZATION_FULL_RANGE;
Hans Verkuilafad4dd2015-01-27 13:46:17 -0300555 unsigned y_offset = full ? 0 : 16;
Hans Verkuil481b97a2014-11-17 10:14:32 -0300556 int lin_r, lin_g, lin_b, lin_y;
Hans Verkuil63881df2014-08-25 08:02:14 -0300557
Hans Verkuil481b97a2014-11-17 10:14:32 -0300558 switch (tpg->real_ycbcr_enc) {
559 case V4L2_YCBCR_ENC_601:
560 case V4L2_YCBCR_ENC_XV601:
561 case V4L2_YCBCR_ENC_SYCC:
Hans Verkuilafad4dd2015-01-27 13:46:17 -0300562 ycbcr2rgb(full ? bt601_full : bt601, y, cb, cr, y_offset, r, g, b);
Hans Verkuil63881df2014-08-25 08:02:14 -0300563 break;
Hans Verkuil481b97a2014-11-17 10:14:32 -0300564 case V4L2_YCBCR_ENC_BT2020:
565 ycbcr2rgb(bt2020, y, cb, cr, 16, r, g, b);
Hans Verkuil63881df2014-08-25 08:02:14 -0300566 break;
Hans Verkuil481b97a2014-11-17 10:14:32 -0300567 case V4L2_YCBCR_ENC_BT2020_CONST_LUM:
568 y -= 16 << 4;
569 cb -= 128 << 4;
570 cr -= 128 << 4;
571
572 if (cb <= 0)
573 *b = COEFF(1.0, 219) * y + COEFF(1.9404, 224) * cb;
574 else
575 *b = COEFF(1.0, 219) * y + COEFF(1.5816, 224) * cb;
576 *b = *b >> 12;
577 if (cr <= 0)
578 *r = COEFF(1.0, 219) * y + COEFF(1.7184, 224) * cr;
579 else
580 *r = COEFF(1.0, 219) * y + COEFF(0.9936, 224) * cr;
581 *r = *r >> 12;
582 lin_r = rec709_to_linear(*r);
583 lin_b = rec709_to_linear(*b);
584 lin_y = rec709_to_linear((y * 255) / 219);
585
586 lin_g = COEFF(1.0 / 0.6780, 255) * lin_y -
587 COEFF(0.2627 / 0.6780, 255) * lin_r -
588 COEFF(0.0593 / 0.6780, 255) * lin_b;
589 *g = linear_to_rec709(lin_g >> 12);
590 break;
591 case V4L2_YCBCR_ENC_SMPTE240M:
592 ycbcr2rgb(smpte240m, y, cb, cr, 16, r, g, b);
593 break;
594 case V4L2_YCBCR_ENC_709:
595 case V4L2_YCBCR_ENC_XV709:
Hans Verkuil63881df2014-08-25 08:02:14 -0300596 default:
Hans Verkuilafad4dd2015-01-27 13:46:17 -0300597 ycbcr2rgb(full ? rec709_full : rec709, y, cb, cr, y_offset, r, g, b);
Hans Verkuil63881df2014-08-25 08:02:14 -0300598 break;
599 }
Hans Verkuil63881df2014-08-25 08:02:14 -0300600}
601
602/* precalculate color bar values to speed up rendering */
603static void precalculate_color(struct tpg_data *tpg, int k)
604{
605 int col = k;
606 int r = tpg_colors[col].r;
607 int g = tpg_colors[col].g;
608 int b = tpg_colors[col].b;
609
610 if (k == TPG_COLOR_TEXTBG) {
611 col = tpg_get_textbg_color(tpg);
612
613 r = tpg_colors[col].r;
614 g = tpg_colors[col].g;
615 b = tpg_colors[col].b;
616 } else if (k == TPG_COLOR_TEXTFG) {
617 col = tpg_get_textfg_color(tpg);
618
619 r = tpg_colors[col].r;
620 g = tpg_colors[col].g;
621 b = tpg_colors[col].b;
622 } else if (tpg->pattern == TPG_PAT_NOISE) {
623 r = g = b = prandom_u32_max(256);
624 } else if (k == TPG_COLOR_RANDOM) {
625 r = g = b = tpg->qual_offset + prandom_u32_max(196);
626 } else if (k >= TPG_COLOR_RAMP) {
627 r = g = b = k - TPG_COLOR_RAMP;
628 }
629
630 if (tpg->pattern == TPG_PAT_CSC_COLORBAR && col <= TPG_COLOR_CSC_BLACK) {
631 r = tpg_csc_colors[tpg->colorspace][col].r;
632 g = tpg_csc_colors[tpg->colorspace][col].g;
633 b = tpg_csc_colors[tpg->colorspace][col].b;
634 } else {
635 r <<= 4;
636 g <<= 4;
637 b <<= 4;
638 }
Hans Verkuil51f30962015-03-07 14:57:50 -0300639 if (tpg->qual == TPG_QUAL_GRAY || tpg->fourcc == V4L2_PIX_FMT_GREY) {
Hans Verkuil481b97a2014-11-17 10:14:32 -0300640 /* Rec. 709 Luma function */
641 /* (0.2126, 0.7152, 0.0722) * (255 * 256) */
Hans Verkuil9c35bd42015-03-07 12:53:39 -0300642 r = g = b = (13879 * r + 46688 * g + 4713 * b) >> 16;
Hans Verkuil481b97a2014-11-17 10:14:32 -0300643 }
Hans Verkuil63881df2014-08-25 08:02:14 -0300644
645 /*
646 * The assumption is that the RGB output is always full range,
647 * so only if the rgb_range overrides the 'real' rgb range do
648 * we need to convert the RGB values.
649 *
Hans Verkuil63881df2014-08-25 08:02:14 -0300650 * Remember that r, g and b are still in the 0 - 0xff0 range.
651 */
652 if (tpg->real_rgb_range == V4L2_DV_RGB_RANGE_LIMITED &&
653 tpg->rgb_range == V4L2_DV_RGB_RANGE_FULL) {
654 /*
655 * Convert from full range (which is what r, g and b are)
656 * to limited range (which is the 'real' RGB range), which
657 * is then interpreted as full range.
658 */
659 r = (r * 219) / 255 + (16 << 4);
660 g = (g * 219) / 255 + (16 << 4);
661 b = (b * 219) / 255 + (16 << 4);
662 } else if (tpg->real_rgb_range != V4L2_DV_RGB_RANGE_LIMITED &&
663 tpg->rgb_range == V4L2_DV_RGB_RANGE_LIMITED) {
664 /*
665 * Clamp r, g and b to the limited range and convert to full
666 * range since that's what we deliver.
667 */
668 r = clamp(r, 16 << 4, 235 << 4);
669 g = clamp(g, 16 << 4, 235 << 4);
670 b = clamp(b, 16 << 4, 235 << 4);
671 r = (r - (16 << 4)) * 255 / 219;
672 g = (g - (16 << 4)) * 255 / 219;
673 b = (b - (16 << 4)) * 255 / 219;
674 }
675
676 if (tpg->brightness != 128 || tpg->contrast != 128 ||
677 tpg->saturation != 128 || tpg->hue) {
678 /* Implement these operations */
Hans Verkuil481b97a2014-11-17 10:14:32 -0300679 int y, cb, cr;
680 int tmp_cb, tmp_cr;
Hans Verkuil63881df2014-08-25 08:02:14 -0300681
682 /* First convert to YCbCr */
Hans Verkuil481b97a2014-11-17 10:14:32 -0300683
684 color_to_ycbcr(tpg, r, g, b, &y, &cb, &cr);
Hans Verkuil63881df2014-08-25 08:02:14 -0300685
686 y = (16 << 4) + ((y - (16 << 4)) * tpg->contrast) / 128;
687 y += (tpg->brightness << 4) - (128 << 4);
688
689 cb -= 128 << 4;
690 cr -= 128 << 4;
691 tmp_cb = (cb * cos(128 + tpg->hue)) / 127 + (cr * sin[128 + tpg->hue]) / 127;
692 tmp_cr = (cr * cos(128 + tpg->hue)) / 127 - (cb * sin[128 + tpg->hue]) / 127;
693
694 cb = (128 << 4) + (tmp_cb * tpg->contrast * tpg->saturation) / (128 * 128);
695 cr = (128 << 4) + (tmp_cr * tpg->contrast * tpg->saturation) / (128 * 128);
696 if (tpg->is_yuv) {
697 tpg->colors[k][0] = clamp(y >> 4, 1, 254);
698 tpg->colors[k][1] = clamp(cb >> 4, 1, 254);
699 tpg->colors[k][2] = clamp(cr >> 4, 1, 254);
700 return;
701 }
Hans Verkuil481b97a2014-11-17 10:14:32 -0300702 ycbcr_to_color(tpg, y, cb, cr, &r, &g, &b);
Hans Verkuil63881df2014-08-25 08:02:14 -0300703 }
704
705 if (tpg->is_yuv) {
706 /* Convert to YCbCr */
Hans Verkuil481b97a2014-11-17 10:14:32 -0300707 int y, cb, cr;
Hans Verkuil63881df2014-08-25 08:02:14 -0300708
Hans Verkuil481b97a2014-11-17 10:14:32 -0300709 color_to_ycbcr(tpg, r, g, b, &y, &cb, &cr);
710
711 if (tpg->real_quantization == V4L2_QUANTIZATION_LIM_RANGE) {
712 y = clamp(y, 16 << 4, 235 << 4);
713 cb = clamp(cb, 16 << 4, 240 << 4);
714 cr = clamp(cr, 16 << 4, 240 << 4);
715 }
Hans Verkuil63881df2014-08-25 08:02:14 -0300716 tpg->colors[k][0] = clamp(y >> 4, 1, 254);
717 tpg->colors[k][1] = clamp(cb >> 4, 1, 254);
718 tpg->colors[k][2] = clamp(cr >> 4, 1, 254);
719 } else {
Hans Verkuil481b97a2014-11-17 10:14:32 -0300720 if (tpg->real_quantization == V4L2_QUANTIZATION_LIM_RANGE) {
721 r = (r * 219) / 255 + (16 << 4);
722 g = (g * 219) / 255 + (16 << 4);
723 b = (b * 219) / 255 + (16 << 4);
724 }
Hans Verkuil63881df2014-08-25 08:02:14 -0300725 switch (tpg->fourcc) {
Hans Verkuil71491062015-03-12 15:40:36 -0300726 case V4L2_PIX_FMT_RGB332:
727 r >>= 9;
728 g >>= 9;
729 b >>= 10;
730 break;
Hans Verkuil63881df2014-08-25 08:02:14 -0300731 case V4L2_PIX_FMT_RGB565:
732 case V4L2_PIX_FMT_RGB565X:
733 r >>= 7;
734 g >>= 6;
735 b >>= 7;
736 break;
Hans Verkuil8aca2302015-03-11 08:14:34 -0300737 case V4L2_PIX_FMT_RGB444:
738 case V4L2_PIX_FMT_XRGB444:
739 case V4L2_PIX_FMT_ARGB444:
740 r >>= 8;
741 g >>= 8;
742 b >>= 8;
743 break;
Hans Verkuil63881df2014-08-25 08:02:14 -0300744 case V4L2_PIX_FMT_RGB555:
745 case V4L2_PIX_FMT_XRGB555:
746 case V4L2_PIX_FMT_ARGB555:
747 case V4L2_PIX_FMT_RGB555X:
Hans Verkuil8f1ff542015-03-12 05:08:01 -0300748 case V4L2_PIX_FMT_XRGB555X:
749 case V4L2_PIX_FMT_ARGB555X:
Hans Verkuil63881df2014-08-25 08:02:14 -0300750 r >>= 7;
751 g >>= 7;
752 b >>= 7;
753 break;
Hans Verkuil68cd4e92015-03-13 05:36:08 -0300754 case V4L2_PIX_FMT_BGR666:
755 r >>= 6;
756 g >>= 6;
757 b >>= 6;
758 break;
Hans Verkuil63881df2014-08-25 08:02:14 -0300759 default:
760 r >>= 4;
761 g >>= 4;
762 b >>= 4;
763 break;
764 }
765
766 tpg->colors[k][0] = r;
767 tpg->colors[k][1] = g;
768 tpg->colors[k][2] = b;
769 }
770}
771
772static void tpg_precalculate_colors(struct tpg_data *tpg)
773{
774 int k;
775
776 for (k = 0; k < TPG_COLOR_MAX; k++)
777 precalculate_color(tpg, k);
778}
779
780/* 'odd' is true for pixels 1, 3, 5, etc. and false for pixels 0, 2, 4, etc. */
781static void gen_twopix(struct tpg_data *tpg,
782 u8 buf[TPG_MAX_PLANES][8], int color, bool odd)
783{
784 unsigned offset = odd * tpg->twopixelsize[0] / 2;
785 u8 alpha = tpg->alpha_component;
786 u8 r_y, g_u, b_v;
787
788 if (tpg->alpha_red_only && color != TPG_COLOR_CSC_RED &&
789 color != TPG_COLOR_100_RED &&
790 color != TPG_COLOR_75_RED)
791 alpha = 0;
792 if (color == TPG_COLOR_RANDOM)
793 precalculate_color(tpg, color);
794 r_y = tpg->colors[color][0]; /* R or precalculated Y */
795 g_u = tpg->colors[color][1]; /* G or precalculated U */
796 b_v = tpg->colors[color][2]; /* B or precalculated V */
797
798 switch (tpg->fourcc) {
Hans Verkuil51f30962015-03-07 14:57:50 -0300799 case V4L2_PIX_FMT_GREY:
800 buf[0][offset] = r_y;
801 break;
Hans Verkuil68c90d62015-03-07 14:55:09 -0300802 case V4L2_PIX_FMT_YUV422P:
803 case V4L2_PIX_FMT_YUV420:
804 case V4L2_PIX_FMT_YUV420M:
805 buf[0][offset] = r_y;
806 if (odd) {
807 buf[1][0] = (buf[1][0] + g_u) / 2;
808 buf[2][0] = (buf[2][0] + b_v) / 2;
809 buf[1][1] = buf[1][0];
810 buf[2][1] = buf[2][0];
811 break;
812 }
813 buf[1][0] = g_u;
814 buf[2][0] = b_v;
815 break;
816 case V4L2_PIX_FMT_YVU420:
817 case V4L2_PIX_FMT_YVU420M:
818 buf[0][offset] = r_y;
819 if (odd) {
820 buf[1][0] = (buf[1][0] + b_v) / 2;
821 buf[2][0] = (buf[2][0] + g_u) / 2;
822 buf[1][1] = buf[1][0];
823 buf[2][1] = buf[2][0];
824 break;
825 }
826 buf[1][0] = b_v;
827 buf[2][0] = g_u;
828 break;
829
830 case V4L2_PIX_FMT_NV12:
831 case V4L2_PIX_FMT_NV12M:
832 case V4L2_PIX_FMT_NV16:
Hans Verkuil63881df2014-08-25 08:02:14 -0300833 case V4L2_PIX_FMT_NV16M:
834 buf[0][offset] = r_y;
Hans Verkuil1f088dc2015-03-07 14:15:25 -0300835 if (odd) {
836 buf[1][0] = (buf[1][0] + g_u) / 2;
837 buf[1][1] = (buf[1][1] + b_v) / 2;
838 break;
839 }
840 buf[1][0] = g_u;
841 buf[1][1] = b_v;
Hans Verkuil63881df2014-08-25 08:02:14 -0300842 break;
Hans Verkuil68c90d62015-03-07 14:55:09 -0300843 case V4L2_PIX_FMT_NV21:
844 case V4L2_PIX_FMT_NV21M:
845 case V4L2_PIX_FMT_NV61:
Hans Verkuil63881df2014-08-25 08:02:14 -0300846 case V4L2_PIX_FMT_NV61M:
847 buf[0][offset] = r_y;
Hans Verkuil1f088dc2015-03-07 14:15:25 -0300848 if (odd) {
849 buf[1][0] = (buf[1][0] + b_v) / 2;
850 buf[1][1] = (buf[1][1] + g_u) / 2;
851 break;
852 }
853 buf[1][0] = b_v;
854 buf[1][1] = g_u;
Hans Verkuil63881df2014-08-25 08:02:14 -0300855 break;
856
Hans Verkuildde72bd2015-03-13 05:51:21 -0300857 case V4L2_PIX_FMT_NV24:
858 buf[0][offset] = r_y;
859 buf[1][2 * offset] = g_u;
860 buf[1][2 * offset + 1] = b_v;
861 break;
862
863 case V4L2_PIX_FMT_NV42:
864 buf[0][offset] = r_y;
865 buf[1][2 * offset] = b_v;
866 buf[1][2 * offset + 1] = g_u;
867 break;
868
Hans Verkuil63881df2014-08-25 08:02:14 -0300869 case V4L2_PIX_FMT_YUYV:
870 buf[0][offset] = r_y;
Hans Verkuil1f088dc2015-03-07 14:15:25 -0300871 if (odd) {
872 buf[0][1] = (buf[0][1] + g_u) / 2;
873 buf[0][3] = (buf[0][3] + b_v) / 2;
874 break;
875 }
876 buf[0][1] = g_u;
877 buf[0][3] = b_v;
Hans Verkuil63881df2014-08-25 08:02:14 -0300878 break;
879 case V4L2_PIX_FMT_UYVY:
Hans Verkuil63881df2014-08-25 08:02:14 -0300880 buf[0][offset + 1] = r_y;
Hans Verkuil1f088dc2015-03-07 14:15:25 -0300881 if (odd) {
882 buf[0][0] = (buf[0][0] + g_u) / 2;
883 buf[0][2] = (buf[0][2] + b_v) / 2;
884 break;
885 }
886 buf[0][0] = g_u;
887 buf[0][2] = b_v;
Hans Verkuil63881df2014-08-25 08:02:14 -0300888 break;
889 case V4L2_PIX_FMT_YVYU:
890 buf[0][offset] = r_y;
Hans Verkuil1f088dc2015-03-07 14:15:25 -0300891 if (odd) {
892 buf[0][1] = (buf[0][1] + b_v) / 2;
893 buf[0][3] = (buf[0][3] + g_u) / 2;
894 break;
895 }
896 buf[0][1] = b_v;
897 buf[0][3] = g_u;
Hans Verkuil63881df2014-08-25 08:02:14 -0300898 break;
899 case V4L2_PIX_FMT_VYUY:
Hans Verkuil63881df2014-08-25 08:02:14 -0300900 buf[0][offset + 1] = r_y;
Hans Verkuil1f088dc2015-03-07 14:15:25 -0300901 if (odd) {
902 buf[0][0] = (buf[0][0] + b_v) / 2;
903 buf[0][2] = (buf[0][2] + g_u) / 2;
904 break;
905 }
906 buf[0][0] = b_v;
907 buf[0][2] = g_u;
Hans Verkuil63881df2014-08-25 08:02:14 -0300908 break;
Hans Verkuil71491062015-03-12 15:40:36 -0300909 case V4L2_PIX_FMT_RGB332:
910 buf[0][offset] = (r_y << 5) | (g_u << 2) | b_v;
911 break;
Hans Verkuil63881df2014-08-25 08:02:14 -0300912 case V4L2_PIX_FMT_RGB565:
913 buf[0][offset] = (g_u << 5) | b_v;
914 buf[0][offset + 1] = (r_y << 3) | (g_u >> 3);
915 break;
916 case V4L2_PIX_FMT_RGB565X:
917 buf[0][offset] = (r_y << 3) | (g_u >> 3);
918 buf[0][offset + 1] = (g_u << 5) | b_v;
919 break;
Hans Verkuil8aca2302015-03-11 08:14:34 -0300920 case V4L2_PIX_FMT_RGB444:
921 case V4L2_PIX_FMT_XRGB444:
922 alpha = 0;
923 /* fall through */
924 case V4L2_PIX_FMT_ARGB444:
925 buf[0][offset] = (g_u << 4) | b_v;
926 buf[0][offset + 1] = (alpha & 0xf0) | r_y;
927 break;
Hans Verkuil63881df2014-08-25 08:02:14 -0300928 case V4L2_PIX_FMT_RGB555:
929 case V4L2_PIX_FMT_XRGB555:
930 alpha = 0;
931 /* fall through */
932 case V4L2_PIX_FMT_ARGB555:
933 buf[0][offset] = (g_u << 5) | b_v;
934 buf[0][offset + 1] = (alpha & 0x80) | (r_y << 2) | (g_u >> 3);
935 break;
936 case V4L2_PIX_FMT_RGB555X:
Hans Verkuil8f1ff542015-03-12 05:08:01 -0300937 case V4L2_PIX_FMT_XRGB555X:
938 alpha = 0;
939 /* fall through */
940 case V4L2_PIX_FMT_ARGB555X:
Hans Verkuil63881df2014-08-25 08:02:14 -0300941 buf[0][offset] = (alpha & 0x80) | (r_y << 2) | (g_u >> 3);
942 buf[0][offset + 1] = (g_u << 5) | b_v;
943 break;
944 case V4L2_PIX_FMT_RGB24:
945 buf[0][offset] = r_y;
946 buf[0][offset + 1] = g_u;
947 buf[0][offset + 2] = b_v;
948 break;
949 case V4L2_PIX_FMT_BGR24:
950 buf[0][offset] = b_v;
951 buf[0][offset + 1] = g_u;
952 buf[0][offset + 2] = r_y;
953 break;
Hans Verkuil68cd4e92015-03-13 05:36:08 -0300954 case V4L2_PIX_FMT_BGR666:
955 buf[0][offset] = (b_v << 2) | (g_u >> 4);
956 buf[0][offset + 1] = (g_u << 4) | (r_y >> 2);
957 buf[0][offset + 2] = r_y << 6;
958 buf[0][offset + 3] = 0;
959 break;
Hans Verkuil63881df2014-08-25 08:02:14 -0300960 case V4L2_PIX_FMT_RGB32:
961 case V4L2_PIX_FMT_XRGB32:
962 alpha = 0;
963 /* fall through */
964 case V4L2_PIX_FMT_ARGB32:
965 buf[0][offset] = alpha;
966 buf[0][offset + 1] = r_y;
967 buf[0][offset + 2] = g_u;
968 buf[0][offset + 3] = b_v;
969 break;
970 case V4L2_PIX_FMT_BGR32:
971 case V4L2_PIX_FMT_XBGR32:
972 alpha = 0;
973 /* fall through */
974 case V4L2_PIX_FMT_ABGR32:
975 buf[0][offset] = b_v;
976 buf[0][offset + 1] = g_u;
977 buf[0][offset + 2] = r_y;
978 buf[0][offset + 3] = alpha;
979 break;
980 }
981}
982
983/* Return how many pattern lines are used by the current pattern. */
Hans Verkuil1a05d312015-03-07 12:49:57 -0300984static unsigned tpg_get_pat_lines(const struct tpg_data *tpg)
Hans Verkuil63881df2014-08-25 08:02:14 -0300985{
986 switch (tpg->pattern) {
987 case TPG_PAT_CHECKERS_16X16:
Hans Verkuil1a05d312015-03-07 12:49:57 -0300988 case TPG_PAT_CHECKERS_2X2:
Hans Verkuil63881df2014-08-25 08:02:14 -0300989 case TPG_PAT_CHECKERS_1X1:
Hans Verkuil1a05d312015-03-07 12:49:57 -0300990 case TPG_PAT_COLOR_CHECKERS_2X2:
991 case TPG_PAT_COLOR_CHECKERS_1X1:
Hans Verkuil63881df2014-08-25 08:02:14 -0300992 case TPG_PAT_ALTERNATING_HLINES:
993 case TPG_PAT_CROSS_1_PIXEL:
994 case TPG_PAT_CROSS_2_PIXELS:
995 case TPG_PAT_CROSS_10_PIXELS:
996 return 2;
997 case TPG_PAT_100_COLORSQUARES:
998 case TPG_PAT_100_HCOLORBAR:
999 return 8;
1000 default:
1001 return 1;
1002 }
1003}
1004
1005/* Which pattern line should be used for the given frame line. */
Hans Verkuil1a05d312015-03-07 12:49:57 -03001006static unsigned tpg_get_pat_line(const struct tpg_data *tpg, unsigned line)
Hans Verkuil63881df2014-08-25 08:02:14 -03001007{
1008 switch (tpg->pattern) {
1009 case TPG_PAT_CHECKERS_16X16:
1010 return (line >> 4) & 1;
1011 case TPG_PAT_CHECKERS_1X1:
Hans Verkuil1a05d312015-03-07 12:49:57 -03001012 case TPG_PAT_COLOR_CHECKERS_1X1:
Hans Verkuil63881df2014-08-25 08:02:14 -03001013 case TPG_PAT_ALTERNATING_HLINES:
1014 return line & 1;
Hans Verkuil1a05d312015-03-07 12:49:57 -03001015 case TPG_PAT_CHECKERS_2X2:
1016 case TPG_PAT_COLOR_CHECKERS_2X2:
1017 return (line & 2) >> 1;
Hans Verkuil63881df2014-08-25 08:02:14 -03001018 case TPG_PAT_100_COLORSQUARES:
1019 case TPG_PAT_100_HCOLORBAR:
1020 return (line * 8) / tpg->src_height;
1021 case TPG_PAT_CROSS_1_PIXEL:
1022 return line == tpg->src_height / 2;
1023 case TPG_PAT_CROSS_2_PIXELS:
1024 return (line + 1) / 2 == tpg->src_height / 4;
1025 case TPG_PAT_CROSS_10_PIXELS:
1026 return (line + 10) / 20 == tpg->src_height / 40;
1027 default:
1028 return 0;
1029 }
1030}
1031
1032/*
1033 * Which color should be used for the given pattern line and X coordinate.
1034 * Note: x is in the range 0 to 2 * tpg->src_width.
1035 */
Hans Verkuil1a05d312015-03-07 12:49:57 -03001036static enum tpg_color tpg_get_color(const struct tpg_data *tpg,
1037 unsigned pat_line, unsigned x)
Hans Verkuil63881df2014-08-25 08:02:14 -03001038{
1039 /* Maximum number of bars are TPG_COLOR_MAX - otherwise, the input print code
1040 should be modified */
1041 static const enum tpg_color bars[3][8] = {
1042 /* Standard ITU-R 75% color bar sequence */
1043 { TPG_COLOR_CSC_WHITE, TPG_COLOR_75_YELLOW,
1044 TPG_COLOR_75_CYAN, TPG_COLOR_75_GREEN,
1045 TPG_COLOR_75_MAGENTA, TPG_COLOR_75_RED,
1046 TPG_COLOR_75_BLUE, TPG_COLOR_100_BLACK, },
1047 /* Standard ITU-R 100% color bar sequence */
1048 { TPG_COLOR_100_WHITE, TPG_COLOR_100_YELLOW,
1049 TPG_COLOR_100_CYAN, TPG_COLOR_100_GREEN,
1050 TPG_COLOR_100_MAGENTA, TPG_COLOR_100_RED,
1051 TPG_COLOR_100_BLUE, TPG_COLOR_100_BLACK, },
1052 /* Color bar sequence suitable to test CSC */
1053 { TPG_COLOR_CSC_WHITE, TPG_COLOR_CSC_YELLOW,
1054 TPG_COLOR_CSC_CYAN, TPG_COLOR_CSC_GREEN,
1055 TPG_COLOR_CSC_MAGENTA, TPG_COLOR_CSC_RED,
1056 TPG_COLOR_CSC_BLUE, TPG_COLOR_CSC_BLACK, },
1057 };
1058
1059 switch (tpg->pattern) {
1060 case TPG_PAT_75_COLORBAR:
1061 case TPG_PAT_100_COLORBAR:
1062 case TPG_PAT_CSC_COLORBAR:
1063 return bars[tpg->pattern][((x * 8) / tpg->src_width) % 8];
1064 case TPG_PAT_100_COLORSQUARES:
1065 return bars[1][(pat_line + (x * 8) / tpg->src_width) % 8];
1066 case TPG_PAT_100_HCOLORBAR:
1067 return bars[1][pat_line];
1068 case TPG_PAT_BLACK:
1069 return TPG_COLOR_100_BLACK;
1070 case TPG_PAT_WHITE:
1071 return TPG_COLOR_100_WHITE;
1072 case TPG_PAT_RED:
1073 return TPG_COLOR_100_RED;
1074 case TPG_PAT_GREEN:
1075 return TPG_COLOR_100_GREEN;
1076 case TPG_PAT_BLUE:
1077 return TPG_COLOR_100_BLUE;
1078 case TPG_PAT_CHECKERS_16X16:
1079 return (((x >> 4) & 1) ^ (pat_line & 1)) ?
1080 TPG_COLOR_100_BLACK : TPG_COLOR_100_WHITE;
1081 case TPG_PAT_CHECKERS_1X1:
1082 return ((x & 1) ^ (pat_line & 1)) ?
1083 TPG_COLOR_100_WHITE : TPG_COLOR_100_BLACK;
Hans Verkuil1a05d312015-03-07 12:49:57 -03001084 case TPG_PAT_COLOR_CHECKERS_1X1:
1085 return ((x & 1) ^ (pat_line & 1)) ?
1086 TPG_COLOR_100_RED : TPG_COLOR_100_BLUE;
1087 case TPG_PAT_CHECKERS_2X2:
1088 return (((x >> 1) & 1) ^ (pat_line & 1)) ?
1089 TPG_COLOR_100_WHITE : TPG_COLOR_100_BLACK;
1090 case TPG_PAT_COLOR_CHECKERS_2X2:
1091 return (((x >> 1) & 1) ^ (pat_line & 1)) ?
1092 TPG_COLOR_100_RED : TPG_COLOR_100_BLUE;
Hans Verkuil63881df2014-08-25 08:02:14 -03001093 case TPG_PAT_ALTERNATING_HLINES:
1094 return pat_line ? TPG_COLOR_100_WHITE : TPG_COLOR_100_BLACK;
1095 case TPG_PAT_ALTERNATING_VLINES:
1096 return (x & 1) ? TPG_COLOR_100_WHITE : TPG_COLOR_100_BLACK;
1097 case TPG_PAT_CROSS_1_PIXEL:
1098 if (pat_line || (x % tpg->src_width) == tpg->src_width / 2)
1099 return TPG_COLOR_100_BLACK;
1100 return TPG_COLOR_100_WHITE;
1101 case TPG_PAT_CROSS_2_PIXELS:
1102 if (pat_line || ((x % tpg->src_width) + 1) / 2 == tpg->src_width / 4)
1103 return TPG_COLOR_100_BLACK;
1104 return TPG_COLOR_100_WHITE;
1105 case TPG_PAT_CROSS_10_PIXELS:
1106 if (pat_line || ((x % tpg->src_width) + 10) / 20 == tpg->src_width / 40)
1107 return TPG_COLOR_100_BLACK;
1108 return TPG_COLOR_100_WHITE;
1109 case TPG_PAT_GRAY_RAMP:
1110 return TPG_COLOR_RAMP + ((x % tpg->src_width) * 256) / tpg->src_width;
1111 default:
1112 return TPG_COLOR_100_RED;
1113 }
1114}
1115
1116/*
1117 * Given the pixel aspect ratio and video aspect ratio calculate the
1118 * coordinates of a centered square and the coordinates of the border of
1119 * the active video area. The coordinates are relative to the source
1120 * frame rectangle.
1121 */
1122static void tpg_calculate_square_border(struct tpg_data *tpg)
1123{
1124 unsigned w = tpg->src_width;
1125 unsigned h = tpg->src_height;
1126 unsigned sq_w, sq_h;
1127
1128 sq_w = (w * 2 / 5) & ~1;
1129 if (((w - sq_w) / 2) & 1)
1130 sq_w += 2;
1131 sq_h = sq_w;
1132 tpg->square.width = sq_w;
1133 if (tpg->vid_aspect == TPG_VIDEO_ASPECT_16X9_ANAMORPHIC) {
1134 unsigned ana_sq_w = (sq_w / 4) * 3;
1135
1136 if (((w - ana_sq_w) / 2) & 1)
1137 ana_sq_w += 2;
1138 tpg->square.width = ana_sq_w;
1139 }
1140 tpg->square.left = (w - tpg->square.width) / 2;
1141 if (tpg->pix_aspect == TPG_PIXEL_ASPECT_NTSC)
1142 sq_h = sq_w * 10 / 11;
1143 else if (tpg->pix_aspect == TPG_PIXEL_ASPECT_PAL)
1144 sq_h = sq_w * 59 / 54;
1145 tpg->square.height = sq_h;
1146 tpg->square.top = (h - sq_h) / 2;
1147 tpg->border.left = 0;
1148 tpg->border.width = w;
1149 tpg->border.top = 0;
1150 tpg->border.height = h;
1151 switch (tpg->vid_aspect) {
1152 case TPG_VIDEO_ASPECT_4X3:
1153 if (tpg->pix_aspect)
1154 return;
1155 if (3 * w >= 4 * h) {
1156 tpg->border.width = ((4 * h) / 3) & ~1;
1157 if (((w - tpg->border.width) / 2) & ~1)
1158 tpg->border.width -= 2;
1159 tpg->border.left = (w - tpg->border.width) / 2;
1160 break;
1161 }
1162 tpg->border.height = ((3 * w) / 4) & ~1;
1163 tpg->border.top = (h - tpg->border.height) / 2;
1164 break;
1165 case TPG_VIDEO_ASPECT_14X9_CENTRE:
1166 if (tpg->pix_aspect) {
1167 tpg->border.height = tpg->pix_aspect == TPG_PIXEL_ASPECT_NTSC ? 420 : 506;
1168 tpg->border.top = (h - tpg->border.height) / 2;
1169 break;
1170 }
1171 if (9 * w >= 14 * h) {
1172 tpg->border.width = ((14 * h) / 9) & ~1;
1173 if (((w - tpg->border.width) / 2) & ~1)
1174 tpg->border.width -= 2;
1175 tpg->border.left = (w - tpg->border.width) / 2;
1176 break;
1177 }
1178 tpg->border.height = ((9 * w) / 14) & ~1;
1179 tpg->border.top = (h - tpg->border.height) / 2;
1180 break;
1181 case TPG_VIDEO_ASPECT_16X9_CENTRE:
1182 if (tpg->pix_aspect) {
1183 tpg->border.height = tpg->pix_aspect == TPG_PIXEL_ASPECT_NTSC ? 368 : 442;
1184 tpg->border.top = (h - tpg->border.height) / 2;
1185 break;
1186 }
1187 if (9 * w >= 16 * h) {
1188 tpg->border.width = ((16 * h) / 9) & ~1;
1189 if (((w - tpg->border.width) / 2) & ~1)
1190 tpg->border.width -= 2;
1191 tpg->border.left = (w - tpg->border.width) / 2;
1192 break;
1193 }
1194 tpg->border.height = ((9 * w) / 16) & ~1;
1195 tpg->border.top = (h - tpg->border.height) / 2;
1196 break;
1197 default:
1198 break;
1199 }
1200}
1201
1202static void tpg_precalculate_line(struct tpg_data *tpg)
1203{
1204 enum tpg_color contrast;
Hans Verkuil9991def2015-03-08 05:53:10 -03001205 u8 pix[TPG_MAX_PLANES][8];
Hans Verkuil63881df2014-08-25 08:02:14 -03001206 unsigned pat;
1207 unsigned p;
1208 unsigned x;
1209
1210 switch (tpg->pattern) {
1211 case TPG_PAT_GREEN:
1212 contrast = TPG_COLOR_100_RED;
1213 break;
1214 case TPG_PAT_CSC_COLORBAR:
1215 contrast = TPG_COLOR_CSC_GREEN;
1216 break;
1217 default:
1218 contrast = TPG_COLOR_100_GREEN;
1219 break;
1220 }
1221
1222 for (pat = 0; pat < tpg_get_pat_lines(tpg); pat++) {
1223 /* Coarse scaling with Bresenham */
1224 unsigned int_part = tpg->src_width / tpg->scaled_width;
1225 unsigned fract_part = tpg->src_width % tpg->scaled_width;
1226 unsigned src_x = 0;
1227 unsigned error = 0;
1228
1229 for (x = 0; x < tpg->scaled_width * 2; x += 2) {
1230 unsigned real_x = src_x;
1231 enum tpg_color color1, color2;
Hans Verkuil63881df2014-08-25 08:02:14 -03001232
1233 real_x = tpg->hflip ? tpg->src_width * 2 - real_x - 2 : real_x;
1234 color1 = tpg_get_color(tpg, pat, real_x);
1235
1236 src_x += int_part;
1237 error += fract_part;
1238 if (error >= tpg->scaled_width) {
1239 error -= tpg->scaled_width;
1240 src_x++;
1241 }
1242
1243 real_x = src_x;
1244 real_x = tpg->hflip ? tpg->src_width * 2 - real_x - 2 : real_x;
1245 color2 = tpg_get_color(tpg, pat, real_x);
1246
1247 src_x += int_part;
1248 error += fract_part;
1249 if (error >= tpg->scaled_width) {
1250 error -= tpg->scaled_width;
1251 src_x++;
1252 }
1253
1254 gen_twopix(tpg, pix, tpg->hflip ? color2 : color1, 0);
1255 gen_twopix(tpg, pix, tpg->hflip ? color1 : color2, 1);
1256 for (p = 0; p < tpg->planes; p++) {
1257 unsigned twopixsize = tpg->twopixelsize[p];
Hans Verkuil5d7c5392015-03-07 14:06:43 -03001258 unsigned hdiv = tpg->hdownsampling[p];
Hans Verkuil9991def2015-03-08 05:53:10 -03001259 u8 *pos = tpg->lines[pat][p] + tpg_hdiv(tpg, p, x);
Hans Verkuil63881df2014-08-25 08:02:14 -03001260
Hans Verkuil5d7c5392015-03-07 14:06:43 -03001261 memcpy(pos, pix[p], twopixsize / hdiv);
Hans Verkuil63881df2014-08-25 08:02:14 -03001262 }
1263 }
1264 }
Hans Verkuil5d7c5392015-03-07 14:06:43 -03001265
1266 if (tpg->vdownsampling[tpg->planes - 1] > 1) {
1267 unsigned pat_lines = tpg_get_pat_lines(tpg);
1268
1269 for (pat = 0; pat < pat_lines; pat++) {
1270 unsigned next_pat = (pat + 1) % pat_lines;
1271
1272 for (p = 1; p < tpg->planes; p++) {
Hans Verkuil9991def2015-03-08 05:53:10 -03001273 unsigned w = tpg_hdiv(tpg, p, tpg->scaled_width * 2);
1274 u8 *pos1 = tpg->lines[pat][p];
1275 u8 *pos2 = tpg->lines[next_pat][p];
1276 u8 *dest = tpg->downsampled_lines[pat][p];
Hans Verkuil5d7c5392015-03-07 14:06:43 -03001277
Hans Verkuil9991def2015-03-08 05:53:10 -03001278 for (x = 0; x < w; x++, pos1++, pos2++, dest++)
1279 *dest = ((u16)*pos1 + (u16)*pos2) / 2;
Hans Verkuil5d7c5392015-03-07 14:06:43 -03001280 }
1281 }
1282 }
1283
Hans Verkuil9991def2015-03-08 05:53:10 -03001284 gen_twopix(tpg, pix, contrast, 0);
1285 gen_twopix(tpg, pix, contrast, 1);
1286 for (p = 0; p < tpg->planes; p++) {
1287 unsigned twopixsize = tpg->twopixelsize[p];
1288 u8 *pos = tpg->contrast_line[p];
Hans Verkuil63881df2014-08-25 08:02:14 -03001289
Hans Verkuil9991def2015-03-08 05:53:10 -03001290 for (x = 0; x < tpg->scaled_width; x += 2, pos += twopixsize)
Hans Verkuil63881df2014-08-25 08:02:14 -03001291 memcpy(pos, pix[p], twopixsize);
Hans Verkuil63881df2014-08-25 08:02:14 -03001292 }
Hans Verkuil63881df2014-08-25 08:02:14 -03001293
Hans Verkuil9991def2015-03-08 05:53:10 -03001294 gen_twopix(tpg, pix, TPG_COLOR_100_BLACK, 0);
1295 gen_twopix(tpg, pix, TPG_COLOR_100_BLACK, 1);
1296 for (p = 0; p < tpg->planes; p++) {
1297 unsigned twopixsize = tpg->twopixelsize[p];
1298 u8 *pos = tpg->black_line[p];
Hans Verkuil63881df2014-08-25 08:02:14 -03001299
Hans Verkuil9991def2015-03-08 05:53:10 -03001300 for (x = 0; x < tpg->scaled_width; x += 2, pos += twopixsize)
Hans Verkuil63881df2014-08-25 08:02:14 -03001301 memcpy(pos, pix[p], twopixsize);
Hans Verkuil63881df2014-08-25 08:02:14 -03001302 }
Hans Verkuil9991def2015-03-08 05:53:10 -03001303
Hans Verkuil63881df2014-08-25 08:02:14 -03001304 for (x = 0; x < tpg->scaled_width * 2; x += 2) {
Hans Verkuil63881df2014-08-25 08:02:14 -03001305 gen_twopix(tpg, pix, TPG_COLOR_RANDOM, 0);
1306 gen_twopix(tpg, pix, TPG_COLOR_RANDOM, 1);
1307 for (p = 0; p < tpg->planes; p++) {
1308 unsigned twopixsize = tpg->twopixelsize[p];
1309 u8 *pos = tpg->random_line[p] + x * twopixsize / 2;
1310
1311 memcpy(pos, pix[p], twopixsize);
1312 }
1313 }
Hans Verkuil9991def2015-03-08 05:53:10 -03001314
Hans Verkuil63881df2014-08-25 08:02:14 -03001315 gen_twopix(tpg, tpg->textbg, TPG_COLOR_TEXTBG, 0);
1316 gen_twopix(tpg, tpg->textbg, TPG_COLOR_TEXTBG, 1);
1317 gen_twopix(tpg, tpg->textfg, TPG_COLOR_TEXTFG, 0);
1318 gen_twopix(tpg, tpg->textfg, TPG_COLOR_TEXTFG, 1);
1319}
1320
1321/* need this to do rgb24 rendering */
1322typedef struct { u16 __; u8 _; } __packed x24;
1323
Hans Verkuildfff0482015-03-09 11:04:02 -03001324void tpg_gen_text(const struct tpg_data *tpg, u8 *basep[TPG_MAX_PLANES][2],
1325 int y, int x, char *text)
Hans Verkuil63881df2014-08-25 08:02:14 -03001326{
1327 int line;
1328 unsigned step = V4L2_FIELD_HAS_T_OR_B(tpg->field) ? 2 : 1;
1329 unsigned div = step;
1330 unsigned first = 0;
1331 unsigned len = strlen(text);
1332 unsigned p;
1333
1334 if (font8x16 == NULL || basep == NULL)
1335 return;
1336
1337 /* Checks if it is possible to show string */
1338 if (y + 16 >= tpg->compose.height || x + 8 >= tpg->compose.width)
1339 return;
1340
1341 if (len > (tpg->compose.width - x) / 8)
1342 len = (tpg->compose.width - x) / 8;
1343 if (tpg->vflip)
1344 y = tpg->compose.height - y - 16;
1345 if (tpg->hflip)
1346 x = tpg->compose.width - x - 8;
1347 y += tpg->compose.top;
1348 x += tpg->compose.left;
1349 if (tpg->field == V4L2_FIELD_BOTTOM)
1350 first = 1;
1351 else if (tpg->field == V4L2_FIELD_SEQ_TB || tpg->field == V4L2_FIELD_SEQ_BT)
1352 div = 2;
1353
1354 for (p = 0; p < tpg->planes; p++) {
Hans Verkuil3e14e7a82015-03-07 14:23:16 -03001355 unsigned vdiv = tpg->vdownsampling[p];
1356 unsigned hdiv = tpg->hdownsampling[p];
1357
1358 /* Print text */
Hans Verkuil63881df2014-08-25 08:02:14 -03001359#define PRINTSTR(PIXTYPE) do { \
1360 PIXTYPE fg; \
1361 PIXTYPE bg; \
1362 memcpy(&fg, tpg->textfg[p], sizeof(PIXTYPE)); \
1363 memcpy(&bg, tpg->textbg[p], sizeof(PIXTYPE)); \
1364 \
Hans Verkuil3e14e7a82015-03-07 14:23:16 -03001365 for (line = first; line < 16; line += vdiv * step) { \
Hans Verkuil63881df2014-08-25 08:02:14 -03001366 int l = tpg->vflip ? 15 - line : line; \
Hans Verkuil3e14e7a82015-03-07 14:23:16 -03001367 PIXTYPE *pos = (PIXTYPE *)(basep[p][(line / vdiv) & 1] + \
1368 ((y * step + l) / (vdiv * div)) * tpg->bytesperline[p] + \
1369 (x / hdiv) * sizeof(PIXTYPE)); \
Hans Verkuil63881df2014-08-25 08:02:14 -03001370 unsigned s; \
1371 \
1372 for (s = 0; s < len; s++) { \
1373 u8 chr = font8x16[text[s] * 16 + line]; \
1374 \
Hans Verkuil3e14e7a82015-03-07 14:23:16 -03001375 if (hdiv == 2 && tpg->hflip) { \
1376 pos[3] = (chr & (0x01 << 6) ? fg : bg); \
1377 pos[2] = (chr & (0x01 << 4) ? fg : bg); \
1378 pos[1] = (chr & (0x01 << 2) ? fg : bg); \
1379 pos[0] = (chr & (0x01 << 0) ? fg : bg); \
1380 } else if (hdiv == 2) { \
1381 pos[0] = (chr & (0x01 << 7) ? fg : bg); \
1382 pos[1] = (chr & (0x01 << 5) ? fg : bg); \
1383 pos[2] = (chr & (0x01 << 3) ? fg : bg); \
1384 pos[3] = (chr & (0x01 << 1) ? fg : bg); \
1385 } else if (tpg->hflip) { \
Hans Verkuil63881df2014-08-25 08:02:14 -03001386 pos[7] = (chr & (0x01 << 7) ? fg : bg); \
1387 pos[6] = (chr & (0x01 << 6) ? fg : bg); \
1388 pos[5] = (chr & (0x01 << 5) ? fg : bg); \
1389 pos[4] = (chr & (0x01 << 4) ? fg : bg); \
1390 pos[3] = (chr & (0x01 << 3) ? fg : bg); \
1391 pos[2] = (chr & (0x01 << 2) ? fg : bg); \
1392 pos[1] = (chr & (0x01 << 1) ? fg : bg); \
1393 pos[0] = (chr & (0x01 << 0) ? fg : bg); \
1394 } else { \
1395 pos[0] = (chr & (0x01 << 7) ? fg : bg); \
1396 pos[1] = (chr & (0x01 << 6) ? fg : bg); \
1397 pos[2] = (chr & (0x01 << 5) ? fg : bg); \
1398 pos[3] = (chr & (0x01 << 4) ? fg : bg); \
1399 pos[4] = (chr & (0x01 << 3) ? fg : bg); \
1400 pos[5] = (chr & (0x01 << 2) ? fg : bg); \
1401 pos[6] = (chr & (0x01 << 1) ? fg : bg); \
1402 pos[7] = (chr & (0x01 << 0) ? fg : bg); \
1403 } \
1404 \
Hans Verkuil3e14e7a82015-03-07 14:23:16 -03001405 pos += (tpg->hflip ? -8 : 8) / hdiv; \
Hans Verkuil63881df2014-08-25 08:02:14 -03001406 } \
1407 } \
1408} while (0)
1409
1410 switch (tpg->twopixelsize[p]) {
1411 case 2:
1412 PRINTSTR(u8); break;
1413 case 4:
1414 PRINTSTR(u16); break;
1415 case 6:
1416 PRINTSTR(x24); break;
1417 case 8:
1418 PRINTSTR(u32); break;
1419 }
1420 }
1421}
1422
1423void tpg_update_mv_step(struct tpg_data *tpg)
1424{
1425 int factor = tpg->mv_hor_mode > TPG_MOVE_NONE ? -1 : 1;
1426
1427 if (tpg->hflip)
1428 factor = -factor;
1429 switch (tpg->mv_hor_mode) {
1430 case TPG_MOVE_NEG_FAST:
1431 case TPG_MOVE_POS_FAST:
1432 tpg->mv_hor_step = ((tpg->src_width + 319) / 320) * 4;
1433 break;
1434 case TPG_MOVE_NEG:
1435 case TPG_MOVE_POS:
1436 tpg->mv_hor_step = ((tpg->src_width + 639) / 640) * 4;
1437 break;
1438 case TPG_MOVE_NEG_SLOW:
1439 case TPG_MOVE_POS_SLOW:
1440 tpg->mv_hor_step = 2;
1441 break;
1442 case TPG_MOVE_NONE:
1443 tpg->mv_hor_step = 0;
1444 break;
1445 }
1446 if (factor < 0)
1447 tpg->mv_hor_step = tpg->src_width - tpg->mv_hor_step;
1448
1449 factor = tpg->mv_vert_mode > TPG_MOVE_NONE ? -1 : 1;
1450 switch (tpg->mv_vert_mode) {
1451 case TPG_MOVE_NEG_FAST:
1452 case TPG_MOVE_POS_FAST:
1453 tpg->mv_vert_step = ((tpg->src_width + 319) / 320) * 4;
1454 break;
1455 case TPG_MOVE_NEG:
1456 case TPG_MOVE_POS:
1457 tpg->mv_vert_step = ((tpg->src_width + 639) / 640) * 4;
1458 break;
1459 case TPG_MOVE_NEG_SLOW:
1460 case TPG_MOVE_POS_SLOW:
1461 tpg->mv_vert_step = 1;
1462 break;
1463 case TPG_MOVE_NONE:
1464 tpg->mv_vert_step = 0;
1465 break;
1466 }
1467 if (factor < 0)
1468 tpg->mv_vert_step = tpg->src_height - tpg->mv_vert_step;
1469}
1470
1471/* Map the line number relative to the crop rectangle to a frame line number */
Hans Verkuildfff0482015-03-09 11:04:02 -03001472static unsigned tpg_calc_frameline(const struct tpg_data *tpg, unsigned src_y,
Hans Verkuil63881df2014-08-25 08:02:14 -03001473 unsigned field)
1474{
1475 switch (field) {
1476 case V4L2_FIELD_TOP:
1477 return tpg->crop.top + src_y * 2;
1478 case V4L2_FIELD_BOTTOM:
1479 return tpg->crop.top + src_y * 2 + 1;
1480 default:
1481 return src_y + tpg->crop.top;
1482 }
1483}
1484
1485/*
1486 * Map the line number relative to the compose rectangle to a destination
1487 * buffer line number.
1488 */
Hans Verkuildfff0482015-03-09 11:04:02 -03001489static unsigned tpg_calc_buffer_line(const struct tpg_data *tpg, unsigned y,
Hans Verkuil63881df2014-08-25 08:02:14 -03001490 unsigned field)
1491{
1492 y += tpg->compose.top;
1493 switch (field) {
1494 case V4L2_FIELD_SEQ_TB:
1495 if (y & 1)
1496 return tpg->buf_height / 2 + y / 2;
1497 return y / 2;
1498 case V4L2_FIELD_SEQ_BT:
1499 if (y & 1)
1500 return y / 2;
1501 return tpg->buf_height / 2 + y / 2;
1502 default:
1503 return y;
1504 }
1505}
1506
1507static void tpg_recalc(struct tpg_data *tpg)
1508{
1509 if (tpg->recalc_colors) {
1510 tpg->recalc_colors = false;
1511 tpg->recalc_lines = true;
Hans Verkuil481b97a2014-11-17 10:14:32 -03001512 tpg->real_ycbcr_enc = tpg->ycbcr_enc;
1513 tpg->real_quantization = tpg->quantization;
1514 if (tpg->ycbcr_enc == V4L2_YCBCR_ENC_DEFAULT) {
1515 switch (tpg->colorspace) {
1516 case V4L2_COLORSPACE_REC709:
1517 tpg->real_ycbcr_enc = V4L2_YCBCR_ENC_709;
1518 break;
1519 case V4L2_COLORSPACE_SRGB:
1520 tpg->real_ycbcr_enc = V4L2_YCBCR_ENC_SYCC;
1521 break;
1522 case V4L2_COLORSPACE_BT2020:
1523 tpg->real_ycbcr_enc = V4L2_YCBCR_ENC_BT2020;
1524 break;
1525 case V4L2_COLORSPACE_SMPTE240M:
1526 tpg->real_ycbcr_enc = V4L2_YCBCR_ENC_SMPTE240M;
1527 break;
1528 case V4L2_COLORSPACE_SMPTE170M:
1529 case V4L2_COLORSPACE_470_SYSTEM_M:
1530 case V4L2_COLORSPACE_470_SYSTEM_BG:
1531 case V4L2_COLORSPACE_ADOBERGB:
1532 default:
1533 tpg->real_ycbcr_enc = V4L2_YCBCR_ENC_601;
1534 break;
1535 }
1536 }
1537 if (tpg->quantization == V4L2_QUANTIZATION_DEFAULT) {
1538 tpg->real_quantization = V4L2_QUANTIZATION_FULL_RANGE;
1539 if (tpg->is_yuv) {
1540 switch (tpg->real_ycbcr_enc) {
1541 case V4L2_YCBCR_ENC_SYCC:
1542 case V4L2_YCBCR_ENC_XV601:
1543 case V4L2_YCBCR_ENC_XV709:
1544 break;
1545 default:
1546 tpg->real_quantization =
1547 V4L2_QUANTIZATION_LIM_RANGE;
1548 break;
1549 }
Hans Verkuilc0b50d92015-03-08 04:53:33 -03001550 } else if (tpg->colorspace == V4L2_COLORSPACE_BT2020) {
1551 /* R'G'B' BT.2020 is limited range */
1552 tpg->real_quantization =
1553 V4L2_QUANTIZATION_LIM_RANGE;
Hans Verkuil481b97a2014-11-17 10:14:32 -03001554 }
1555 }
Hans Verkuil63881df2014-08-25 08:02:14 -03001556 tpg_precalculate_colors(tpg);
1557 }
1558 if (tpg->recalc_square_border) {
1559 tpg->recalc_square_border = false;
1560 tpg_calculate_square_border(tpg);
1561 }
1562 if (tpg->recalc_lines) {
1563 tpg->recalc_lines = false;
1564 tpg_precalculate_line(tpg);
1565 }
1566}
1567
1568void tpg_calc_text_basep(struct tpg_data *tpg,
1569 u8 *basep[TPG_MAX_PLANES][2], unsigned p, u8 *vbuf)
1570{
1571 unsigned stride = tpg->bytesperline[p];
Hans Verkuil280abe42015-03-07 14:50:41 -03001572 unsigned h = tpg->buf_height;
Hans Verkuil63881df2014-08-25 08:02:14 -03001573
1574 tpg_recalc(tpg);
1575
1576 basep[p][0] = vbuf;
1577 basep[p][1] = vbuf;
Hans Verkuil280abe42015-03-07 14:50:41 -03001578 h /= tpg->vdownsampling[p];
Hans Verkuil63881df2014-08-25 08:02:14 -03001579 if (tpg->field == V4L2_FIELD_SEQ_TB)
Hans Verkuil280abe42015-03-07 14:50:41 -03001580 basep[p][1] += h * stride / 2;
Hans Verkuil63881df2014-08-25 08:02:14 -03001581 else if (tpg->field == V4L2_FIELD_SEQ_BT)
Hans Verkuil280abe42015-03-07 14:50:41 -03001582 basep[p][0] += h * stride / 2;
1583}
1584
1585static int tpg_pattern_avg(const struct tpg_data *tpg,
1586 unsigned pat1, unsigned pat2)
1587{
1588 unsigned pat_lines = tpg_get_pat_lines(tpg);
1589
1590 if (pat1 == (pat2 + 1) % pat_lines)
1591 return pat2;
1592 if (pat2 == (pat1 + 1) % pat_lines)
1593 return pat1;
1594 return -1;
Hans Verkuil63881df2014-08-25 08:02:14 -03001595}
1596
Hans Verkuile76036d2015-03-09 11:07:23 -03001597/*
1598 * This struct contains common parameters used by both the drawing of the
1599 * test pattern and the drawing of the extras (borders, square, etc.)
1600 */
1601struct tpg_draw_params {
1602 /* common data */
1603 bool is_tv;
1604 bool is_60hz;
1605 unsigned twopixsize;
1606 unsigned img_width;
1607 unsigned stride;
1608 unsigned hmax;
1609 unsigned frame_line;
1610 unsigned frame_line_next;
1611
1612 /* test pattern */
1613 unsigned mv_hor_old;
1614 unsigned mv_hor_new;
1615 unsigned mv_vert_old;
1616 unsigned mv_vert_new;
1617
1618 /* extras */
1619 unsigned wss_width;
1620 unsigned wss_random_offset;
1621 unsigned sav_eav_f;
1622 unsigned left_pillar_width;
1623 unsigned right_pillar_start;
1624};
1625
Hans Verkuilf0ce4fd2015-03-09 11:30:05 -03001626static void tpg_fill_params_pattern(const struct tpg_data *tpg, unsigned p,
1627 struct tpg_draw_params *params)
1628{
1629 params->mv_hor_old =
1630 tpg_hscale_div(tpg, p, tpg->mv_hor_count % tpg->src_width);
1631 params->mv_hor_new =
1632 tpg_hscale_div(tpg, p, (tpg->mv_hor_count + tpg->mv_hor_step) %
1633 tpg->src_width);
1634 params->mv_vert_old = tpg->mv_vert_count % tpg->src_height;
1635 params->mv_vert_new =
1636 (tpg->mv_vert_count + tpg->mv_vert_step) % tpg->src_height;
1637}
1638
Hans Verkuil07386b92015-03-09 11:39:19 -03001639static void tpg_fill_params_extras(const struct tpg_data *tpg,
1640 unsigned p,
1641 struct tpg_draw_params *params)
1642{
1643 unsigned left_pillar_width = 0;
1644 unsigned right_pillar_start = params->img_width;
1645
1646 params->wss_width = tpg->crop.left < tpg->src_width / 2 ?
1647 tpg->src_width / 2 - tpg->crop.left : 0;
1648 if (params->wss_width > tpg->crop.width)
1649 params->wss_width = tpg->crop.width;
1650 params->wss_width = tpg_hscale_div(tpg, p, params->wss_width);
1651 params->wss_random_offset =
1652 params->twopixsize * prandom_u32_max(tpg->src_width / 2);
1653
1654 if (tpg->crop.left < tpg->border.left) {
1655 left_pillar_width = tpg->border.left - tpg->crop.left;
1656 if (left_pillar_width > tpg->crop.width)
1657 left_pillar_width = tpg->crop.width;
1658 left_pillar_width = tpg_hscale_div(tpg, p, left_pillar_width);
1659 }
1660 params->left_pillar_width = left_pillar_width;
1661
1662 if (tpg->crop.left + tpg->crop.width >
1663 tpg->border.left + tpg->border.width) {
1664 right_pillar_start =
1665 tpg->border.left + tpg->border.width - tpg->crop.left;
1666 right_pillar_start =
1667 tpg_hscale_div(tpg, p, right_pillar_start);
1668 if (right_pillar_start > params->img_width)
1669 right_pillar_start = params->img_width;
1670 }
1671 params->right_pillar_start = right_pillar_start;
1672
1673 params->sav_eav_f = tpg->field ==
1674 (params->is_60hz ? V4L2_FIELD_TOP : V4L2_FIELD_BOTTOM);
1675}
1676
Hans Verkuilc6ff1c12015-03-09 11:47:48 -03001677static void tpg_fill_plane_extras(const struct tpg_data *tpg,
1678 const struct tpg_draw_params *params,
1679 unsigned p, unsigned h, u8 *vbuf)
1680{
1681 unsigned twopixsize = params->twopixsize;
1682 unsigned img_width = params->img_width;
1683 unsigned frame_line = params->frame_line;
1684 const struct v4l2_rect *sq = &tpg->square;
1685 const struct v4l2_rect *b = &tpg->border;
1686 const struct v4l2_rect *c = &tpg->crop;
1687
1688 if (params->is_tv && !params->is_60hz &&
1689 frame_line == 0 && params->wss_width) {
1690 /*
1691 * Replace the first half of the top line of a 50 Hz frame
1692 * with random data to simulate a WSS signal.
1693 */
1694 u8 *wss = tpg->random_line[p] + params->wss_random_offset;
1695
1696 memcpy(vbuf, wss, params->wss_width);
1697 }
1698
1699 if (tpg->show_border && frame_line >= b->top &&
1700 frame_line < b->top + b->height) {
1701 unsigned bottom = b->top + b->height - 1;
1702 unsigned left = params->left_pillar_width;
1703 unsigned right = params->right_pillar_start;
1704
1705 if (frame_line == b->top || frame_line == b->top + 1 ||
1706 frame_line == bottom || frame_line == bottom - 1) {
1707 memcpy(vbuf + left, tpg->contrast_line[p],
1708 right - left);
1709 } else {
1710 if (b->left >= c->left &&
1711 b->left < c->left + c->width)
1712 memcpy(vbuf + left,
1713 tpg->contrast_line[p], twopixsize);
1714 if (b->left + b->width > c->left &&
1715 b->left + b->width <= c->left + c->width)
1716 memcpy(vbuf + right - twopixsize,
1717 tpg->contrast_line[p], twopixsize);
1718 }
1719 }
1720 if (tpg->qual != TPG_QUAL_NOISE && frame_line >= b->top &&
1721 frame_line < b->top + b->height) {
1722 memcpy(vbuf, tpg->black_line[p], params->left_pillar_width);
1723 memcpy(vbuf + params->right_pillar_start, tpg->black_line[p],
1724 img_width - params->right_pillar_start);
1725 }
1726 if (tpg->show_square && frame_line >= sq->top &&
1727 frame_line < sq->top + sq->height &&
1728 sq->left < c->left + c->width &&
1729 sq->left + sq->width >= c->left) {
1730 unsigned left = sq->left;
1731 unsigned width = sq->width;
1732
1733 if (c->left > left) {
1734 width -= c->left - left;
1735 left = c->left;
1736 }
1737 if (c->left + c->width < left + width)
1738 width -= left + width - c->left - c->width;
1739 left -= c->left;
1740 left = tpg_hscale_div(tpg, p, left);
1741 width = tpg_hscale_div(tpg, p, width);
1742 memcpy(vbuf + left, tpg->contrast_line[p], width);
1743 }
1744 if (tpg->insert_sav) {
1745 unsigned offset = tpg_hdiv(tpg, p, tpg->compose.width / 3);
1746 u8 *p = vbuf + offset;
1747 unsigned vact = 0, hact = 0;
1748
1749 p[0] = 0xff;
1750 p[1] = 0;
1751 p[2] = 0;
1752 p[3] = 0x80 | (params->sav_eav_f << 6) |
1753 (vact << 5) | (hact << 4) |
1754 ((hact ^ vact) << 3) |
1755 ((hact ^ params->sav_eav_f) << 2) |
1756 ((params->sav_eav_f ^ vact) << 1) |
1757 (hact ^ vact ^ params->sav_eav_f);
1758 }
1759 if (tpg->insert_eav) {
1760 unsigned offset = tpg_hdiv(tpg, p, tpg->compose.width * 2 / 3);
1761 u8 *p = vbuf + offset;
1762 unsigned vact = 0, hact = 1;
1763
1764 p[0] = 0xff;
1765 p[1] = 0;
1766 p[2] = 0;
1767 p[3] = 0x80 | (params->sav_eav_f << 6) |
1768 (vact << 5) | (hact << 4) |
1769 ((hact ^ vact) << 3) |
1770 ((hact ^ params->sav_eav_f) << 2) |
1771 ((params->sav_eav_f ^ vact) << 1) |
1772 (hact ^ vact ^ params->sav_eav_f);
1773 }
1774}
1775
Hans Verkuilecb9e912015-03-09 11:52:43 -03001776static void tpg_fill_plane_pattern(const struct tpg_data *tpg,
1777 const struct tpg_draw_params *params,
1778 unsigned p, unsigned h, u8 *vbuf)
1779{
1780 unsigned twopixsize = params->twopixsize;
1781 unsigned img_width = params->img_width;
1782 unsigned mv_hor_old = params->mv_hor_old;
1783 unsigned mv_hor_new = params->mv_hor_new;
1784 unsigned mv_vert_old = params->mv_vert_old;
1785 unsigned mv_vert_new = params->mv_vert_new;
1786 unsigned frame_line = params->frame_line;
1787 unsigned frame_line_next = params->frame_line_next;
1788 unsigned line_offset = tpg_hscale_div(tpg, p, tpg->crop.left);
1789 bool even;
1790 bool fill_blank = false;
1791 unsigned pat_line_old;
1792 unsigned pat_line_new;
1793 u8 *linestart_older;
1794 u8 *linestart_newer;
1795 u8 *linestart_top;
1796 u8 *linestart_bottom;
1797
1798 even = !(frame_line & 1);
1799
1800 if (h >= params->hmax) {
1801 if (params->hmax == tpg->compose.height)
1802 return;
1803 if (!tpg->perc_fill_blank)
1804 return;
1805 fill_blank = true;
1806 }
1807
1808 if (tpg->vflip) {
1809 frame_line = tpg->src_height - frame_line - 1;
1810 frame_line_next = tpg->src_height - frame_line_next - 1;
1811 }
1812
1813 if (fill_blank) {
1814 linestart_older = tpg->contrast_line[p];
1815 linestart_newer = tpg->contrast_line[p];
1816 } else if (tpg->qual != TPG_QUAL_NOISE &&
1817 (frame_line < tpg->border.top ||
1818 frame_line >= tpg->border.top + tpg->border.height)) {
1819 linestart_older = tpg->black_line[p];
1820 linestart_newer = tpg->black_line[p];
1821 } else if (tpg->pattern == TPG_PAT_NOISE || tpg->qual == TPG_QUAL_NOISE) {
1822 linestart_older = tpg->random_line[p] +
1823 twopixsize * prandom_u32_max(tpg->src_width / 2);
1824 linestart_newer = tpg->random_line[p] +
1825 twopixsize * prandom_u32_max(tpg->src_width / 2);
1826 } else {
1827 unsigned frame_line_old =
1828 (frame_line + mv_vert_old) % tpg->src_height;
1829 unsigned frame_line_new =
1830 (frame_line + mv_vert_new) % tpg->src_height;
1831 unsigned pat_line_next_old;
1832 unsigned pat_line_next_new;
1833
1834 pat_line_old = tpg_get_pat_line(tpg, frame_line_old);
1835 pat_line_new = tpg_get_pat_line(tpg, frame_line_new);
1836 linestart_older = tpg->lines[pat_line_old][p] + mv_hor_old;
1837 linestart_newer = tpg->lines[pat_line_new][p] + mv_hor_new;
1838
1839 if (tpg->vdownsampling[p] > 1 && frame_line != frame_line_next) {
1840 int avg_pat;
1841
1842 /*
1843 * Now decide whether we need to use downsampled_lines[].
1844 * That's necessary if the two lines use different patterns.
1845 */
1846 pat_line_next_old = tpg_get_pat_line(tpg,
1847 (frame_line_next + mv_vert_old) % tpg->src_height);
1848 pat_line_next_new = tpg_get_pat_line(tpg,
1849 (frame_line_next + mv_vert_new) % tpg->src_height);
1850
1851 switch (tpg->field) {
1852 case V4L2_FIELD_INTERLACED:
1853 case V4L2_FIELD_INTERLACED_BT:
1854 case V4L2_FIELD_INTERLACED_TB:
1855 avg_pat = tpg_pattern_avg(tpg, pat_line_old, pat_line_new);
1856 if (avg_pat < 0)
1857 break;
1858 linestart_older = tpg->downsampled_lines[avg_pat][p] + mv_hor_old;
1859 linestart_newer = linestart_older;
1860 break;
1861 case V4L2_FIELD_NONE:
1862 case V4L2_FIELD_TOP:
1863 case V4L2_FIELD_BOTTOM:
1864 case V4L2_FIELD_SEQ_BT:
1865 case V4L2_FIELD_SEQ_TB:
1866 avg_pat = tpg_pattern_avg(tpg, pat_line_old, pat_line_next_old);
1867 if (avg_pat >= 0)
1868 linestart_older = tpg->downsampled_lines[avg_pat][p] +
1869 mv_hor_old;
1870 avg_pat = tpg_pattern_avg(tpg, pat_line_new, pat_line_next_new);
1871 if (avg_pat >= 0)
1872 linestart_newer = tpg->downsampled_lines[avg_pat][p] +
1873 mv_hor_new;
1874 break;
1875 }
1876 }
1877 linestart_older += line_offset;
1878 linestart_newer += line_offset;
1879 }
1880 if (tpg->field_alternate) {
1881 linestart_top = linestart_bottom = linestart_older;
1882 } else if (params->is_60hz) {
1883 linestart_top = linestart_newer;
1884 linestart_bottom = linestart_older;
1885 } else {
1886 linestart_top = linestart_older;
1887 linestart_bottom = linestart_newer;
1888 }
1889
1890 switch (tpg->field) {
1891 case V4L2_FIELD_INTERLACED:
1892 case V4L2_FIELD_INTERLACED_TB:
1893 case V4L2_FIELD_SEQ_TB:
1894 case V4L2_FIELD_SEQ_BT:
1895 if (even)
1896 memcpy(vbuf, linestart_top, img_width);
1897 else
1898 memcpy(vbuf, linestart_bottom, img_width);
1899 break;
1900 case V4L2_FIELD_INTERLACED_BT:
1901 if (even)
1902 memcpy(vbuf, linestart_bottom, img_width);
1903 else
1904 memcpy(vbuf, linestart_top, img_width);
1905 break;
1906 case V4L2_FIELD_TOP:
1907 memcpy(vbuf, linestart_top, img_width);
1908 break;
1909 case V4L2_FIELD_BOTTOM:
1910 memcpy(vbuf, linestart_bottom, img_width);
1911 break;
1912 case V4L2_FIELD_NONE:
1913 default:
1914 memcpy(vbuf, linestart_older, img_width);
1915 break;
1916 }
1917}
1918
1919void tpg_fill_plane_buffer(struct tpg_data *tpg, v4l2_std_id std,
1920 unsigned p, u8 *vbuf)
Hans Verkuil63881df2014-08-25 08:02:14 -03001921{
Hans Verkuil5e729392015-03-09 11:26:43 -03001922 struct tpg_draw_params params;
Hans Verkuil63881df2014-08-25 08:02:14 -03001923 unsigned factor = V4L2_FIELD_HAS_T_OR_B(tpg->field) ? 2 : 1;
Hans Verkuil63881df2014-08-25 08:02:14 -03001924
1925 /* Coarse scaling with Bresenham */
1926 unsigned int_part = (tpg->crop.height / factor) / tpg->compose.height;
1927 unsigned fract_part = (tpg->crop.height / factor) % tpg->compose.height;
1928 unsigned src_y = 0;
1929 unsigned error = 0;
Hans Verkuilecb9e912015-03-09 11:52:43 -03001930 unsigned h;
Hans Verkuil63881df2014-08-25 08:02:14 -03001931
1932 tpg_recalc(tpg);
1933
Hans Verkuil5e729392015-03-09 11:26:43 -03001934 params.is_tv = std;
1935 params.is_60hz = std & V4L2_STD_525_60;
1936 params.twopixsize = tpg->twopixelsize[p];
1937 params.img_width = tpg_hdiv(tpg, p, tpg->compose.width);
1938 params.stride = tpg->bytesperline[p];
1939 params.hmax = (tpg->compose.height * tpg->perc_fill) / 100;
1940
Hans Verkuilf0ce4fd2015-03-09 11:30:05 -03001941 tpg_fill_params_pattern(tpg, p, &params);
Hans Verkuil07386b92015-03-09 11:39:19 -03001942 tpg_fill_params_extras(tpg, p, &params);
1943
Hans Verkuil9991def2015-03-08 05:53:10 -03001944 vbuf += tpg_hdiv(tpg, p, tpg->compose.left);
Hans Verkuil63881df2014-08-25 08:02:14 -03001945
1946 for (h = 0; h < tpg->compose.height; h++) {
Hans Verkuil63881df2014-08-25 08:02:14 -03001947 unsigned buf_line;
Hans Verkuil63881df2014-08-25 08:02:14 -03001948
Hans Verkuilc6ff1c12015-03-09 11:47:48 -03001949 params.frame_line = tpg_calc_frameline(tpg, src_y, tpg->field);
1950 params.frame_line_next = params.frame_line;
Hans Verkuil63881df2014-08-25 08:02:14 -03001951 buf_line = tpg_calc_buffer_line(tpg, h, tpg->field);
1952 src_y += int_part;
1953 error += fract_part;
1954 if (error >= tpg->compose.height) {
1955 error -= tpg->compose.height;
1956 src_y++;
1957 }
1958
Hans Verkuilecb9e912015-03-09 11:52:43 -03001959 if (tpg->vdownsampling[p] > 1) {
Hans Verkuil280abe42015-03-07 14:50:41 -03001960 /*
1961 * When doing vertical downsampling the field setting
1962 * matters: for SEQ_BT/TB we downsample each field
1963 * separately (i.e. lines 0+2 are combined, as are
1964 * lines 1+3), for the other field settings we combine
1965 * odd and even lines. Doing that for SEQ_BT/TB would
1966 * be really weird.
1967 */
1968 if (tpg->field == V4L2_FIELD_SEQ_BT ||
1969 tpg->field == V4L2_FIELD_SEQ_TB) {
Hans Verkuilecb9e912015-03-09 11:52:43 -03001970 unsigned next_src_y = src_y;
1971
Hans Verkuil280abe42015-03-07 14:50:41 -03001972 if ((h & 3) >= 2)
1973 continue;
Hans Verkuilecb9e912015-03-09 11:52:43 -03001974 next_src_y += int_part;
1975 if (error + fract_part >= tpg->compose.height)
1976 next_src_y++;
1977 params.frame_line_next =
1978 tpg_calc_frameline(tpg, next_src_y, tpg->field);
1979 } else {
1980 if (h & 1)
1981 continue;
1982 params.frame_line_next =
1983 tpg_calc_frameline(tpg, src_y, tpg->field);
Hans Verkuil280abe42015-03-07 14:50:41 -03001984 }
1985
Hans Verkuilecb9e912015-03-09 11:52:43 -03001986 buf_line /= tpg->vdownsampling[p];
Hans Verkuil280abe42015-03-07 14:50:41 -03001987 }
Hans Verkuilecb9e912015-03-09 11:52:43 -03001988 tpg_fill_plane_pattern(tpg, &params, p, h,
1989 vbuf + buf_line * params.stride);
Hans Verkuilc6ff1c12015-03-09 11:47:48 -03001990 tpg_fill_plane_extras(tpg, &params, p, h,
1991 vbuf + buf_line * params.stride);
Hans Verkuil63881df2014-08-25 08:02:14 -03001992 }
1993}
Hans Verkuil4db22042015-03-07 13:39:01 -03001994
1995void tpg_fillbuffer(struct tpg_data *tpg, v4l2_std_id std, unsigned p, u8 *vbuf)
1996{
1997 unsigned offset = 0;
1998 unsigned i;
1999
2000 if (tpg->buffers > 1) {
2001 tpg_fill_plane_buffer(tpg, std, p, vbuf);
2002 return;
2003 }
2004
2005 for (i = 0; i < tpg->planes; i++) {
2006 tpg_fill_plane_buffer(tpg, std, i, vbuf + offset);
2007 offset += tpg_calc_plane_size(tpg, i);
2008 }
2009}