blob: 8cac0bdefd9aef29c9e75ac2a056885c64c12cb0 [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 Verkuil02aa7692015-03-14 08:01:50 -0300184 tpg->interleaved = false;
Hans Verkuilba01f672015-03-07 13:57:27 -0300185 tpg->vdownsampling[0] = 1;
186 tpg->hdownsampling[0] = 1;
Hans Verkuil9991def2015-03-08 05:53:10 -0300187 tpg->hmask[0] = ~0;
188 tpg->hmask[1] = ~0;
189 tpg->hmask[2] = ~0;
Hans Verkuil06d1f0c2015-03-07 13:01:53 -0300190
Hans Verkuil63881df2014-08-25 08:02:14 -0300191 switch (fourcc) {
Hans Verkuil02aa7692015-03-14 08:01:50 -0300192 case V4L2_PIX_FMT_SBGGR8:
193 case V4L2_PIX_FMT_SGBRG8:
194 case V4L2_PIX_FMT_SGRBG8:
195 case V4L2_PIX_FMT_SRGGB8:
196 tpg->interleaved = true;
197 tpg->vdownsampling[1] = 1;
198 tpg->hdownsampling[1] = 1;
199 tpg->planes = 2;
200 /* fall through */
Hans Verkuil71491062015-03-12 15:40:36 -0300201 case V4L2_PIX_FMT_RGB332:
Hans Verkuil63881df2014-08-25 08:02:14 -0300202 case V4L2_PIX_FMT_RGB565:
203 case V4L2_PIX_FMT_RGB565X:
Hans Verkuil8aca2302015-03-11 08:14:34 -0300204 case V4L2_PIX_FMT_RGB444:
205 case V4L2_PIX_FMT_XRGB444:
206 case V4L2_PIX_FMT_ARGB444:
Hans Verkuil63881df2014-08-25 08:02:14 -0300207 case V4L2_PIX_FMT_RGB555:
208 case V4L2_PIX_FMT_XRGB555:
209 case V4L2_PIX_FMT_ARGB555:
210 case V4L2_PIX_FMT_RGB555X:
Hans Verkuil8f1ff542015-03-12 05:08:01 -0300211 case V4L2_PIX_FMT_XRGB555X:
212 case V4L2_PIX_FMT_ARGB555X:
Hans Verkuil68cd4e92015-03-13 05:36:08 -0300213 case V4L2_PIX_FMT_BGR666:
Hans Verkuil63881df2014-08-25 08:02:14 -0300214 case V4L2_PIX_FMT_RGB24:
215 case V4L2_PIX_FMT_BGR24:
216 case V4L2_PIX_FMT_RGB32:
217 case V4L2_PIX_FMT_BGR32:
218 case V4L2_PIX_FMT_XRGB32:
219 case V4L2_PIX_FMT_XBGR32:
220 case V4L2_PIX_FMT_ARGB32:
221 case V4L2_PIX_FMT_ABGR32:
Hans Verkuil51f30962015-03-07 14:57:50 -0300222 case V4L2_PIX_FMT_GREY:
Ricardo Ribalda18b3b3b2015-05-04 05:07:29 -0300223 case V4L2_PIX_FMT_Y16:
Ricardo Ribaldab0ce23f2015-05-04 05:07:31 -0300224 case V4L2_PIX_FMT_Y16_BE:
Mauro Carvalho Chehab6c515a42014-09-03 15:53:45 -0300225 tpg->is_yuv = false;
Hans Verkuil63881df2014-08-25 08:02:14 -0300226 break;
Hans Verkuil628821c2015-03-13 06:35:40 -0300227 case V4L2_PIX_FMT_YUV444:
228 case V4L2_PIX_FMT_YUV555:
229 case V4L2_PIX_FMT_YUV565:
230 case V4L2_PIX_FMT_YUV32:
231 tpg->is_yuv = true;
232 break;
Hans Verkuil68c90d62015-03-07 14:55:09 -0300233 case V4L2_PIX_FMT_YUV420M:
234 case V4L2_PIX_FMT_YVU420M:
235 tpg->buffers = 3;
236 /* fall through */
237 case V4L2_PIX_FMT_YUV420:
238 case V4L2_PIX_FMT_YVU420:
239 tpg->vdownsampling[1] = 2;
240 tpg->vdownsampling[2] = 2;
241 tpg->hdownsampling[1] = 2;
242 tpg->hdownsampling[2] = 2;
243 tpg->planes = 3;
244 tpg->is_yuv = true;
245 break;
246 case V4L2_PIX_FMT_YUV422P:
247 tpg->vdownsampling[1] = 1;
248 tpg->vdownsampling[2] = 1;
249 tpg->hdownsampling[1] = 2;
250 tpg->hdownsampling[2] = 2;
251 tpg->planes = 3;
252 tpg->is_yuv = true;
253 break;
Hans Verkuil63881df2014-08-25 08:02:14 -0300254 case V4L2_PIX_FMT_NV16M:
255 case V4L2_PIX_FMT_NV61M:
Hans Verkuil68c90d62015-03-07 14:55:09 -0300256 tpg->buffers = 2;
257 /* fall through */
258 case V4L2_PIX_FMT_NV16:
259 case V4L2_PIX_FMT_NV61:
Hans Verkuilba01f672015-03-07 13:57:27 -0300260 tpg->vdownsampling[1] = 1;
261 tpg->hdownsampling[1] = 1;
Hans Verkuil9991def2015-03-08 05:53:10 -0300262 tpg->hmask[1] = ~1;
Hans Verkuil63881df2014-08-25 08:02:14 -0300263 tpg->planes = 2;
Hans Verkuil68c90d62015-03-07 14:55:09 -0300264 tpg->is_yuv = true;
265 break;
266 case V4L2_PIX_FMT_NV12M:
267 case V4L2_PIX_FMT_NV21M:
268 tpg->buffers = 2;
269 /* fall through */
270 case V4L2_PIX_FMT_NV12:
271 case V4L2_PIX_FMT_NV21:
272 tpg->vdownsampling[1] = 2;
273 tpg->hdownsampling[1] = 1;
Hans Verkuil9991def2015-03-08 05:53:10 -0300274 tpg->hmask[1] = ~1;
Hans Verkuil68c90d62015-03-07 14:55:09 -0300275 tpg->planes = 2;
276 tpg->is_yuv = true;
277 break;
Hans Verkuildde72bd2015-03-13 05:51:21 -0300278 case V4L2_PIX_FMT_NV24:
279 case V4L2_PIX_FMT_NV42:
280 tpg->vdownsampling[1] = 1;
281 tpg->hdownsampling[1] = 1;
282 tpg->planes = 2;
283 tpg->is_yuv = true;
284 break;
Hans Verkuil63881df2014-08-25 08:02:14 -0300285 case V4L2_PIX_FMT_YUYV:
286 case V4L2_PIX_FMT_UYVY:
287 case V4L2_PIX_FMT_YVYU:
288 case V4L2_PIX_FMT_VYUY:
Hans Verkuil9991def2015-03-08 05:53:10 -0300289 tpg->hmask[0] = ~1;
Mauro Carvalho Chehab6c515a42014-09-03 15:53:45 -0300290 tpg->is_yuv = true;
Hans Verkuil63881df2014-08-25 08:02:14 -0300291 break;
292 default:
293 return false;
294 }
295
296 switch (fourcc) {
Ricardo Ribaldaed1bc6642015-05-04 05:07:32 -0300297 case V4L2_PIX_FMT_GREY:
Hans Verkuil71491062015-03-12 15:40:36 -0300298 case V4L2_PIX_FMT_RGB332:
299 tpg->twopixelsize[0] = 2;
300 break;
Hans Verkuil63881df2014-08-25 08:02:14 -0300301 case V4L2_PIX_FMT_RGB565:
302 case V4L2_PIX_FMT_RGB565X:
Hans Verkuil8aca2302015-03-11 08:14:34 -0300303 case V4L2_PIX_FMT_RGB444:
304 case V4L2_PIX_FMT_XRGB444:
305 case V4L2_PIX_FMT_ARGB444:
Hans Verkuil63881df2014-08-25 08:02:14 -0300306 case V4L2_PIX_FMT_RGB555:
307 case V4L2_PIX_FMT_XRGB555:
308 case V4L2_PIX_FMT_ARGB555:
309 case V4L2_PIX_FMT_RGB555X:
Hans Verkuil8f1ff542015-03-12 05:08:01 -0300310 case V4L2_PIX_FMT_XRGB555X:
311 case V4L2_PIX_FMT_ARGB555X:
Hans Verkuil63881df2014-08-25 08:02:14 -0300312 case V4L2_PIX_FMT_YUYV:
313 case V4L2_PIX_FMT_UYVY:
314 case V4L2_PIX_FMT_YVYU:
315 case V4L2_PIX_FMT_VYUY:
Hans Verkuil628821c2015-03-13 06:35:40 -0300316 case V4L2_PIX_FMT_YUV444:
317 case V4L2_PIX_FMT_YUV555:
318 case V4L2_PIX_FMT_YUV565:
Ricardo Ribalda18b3b3b2015-05-04 05:07:29 -0300319 case V4L2_PIX_FMT_Y16:
Ricardo Ribaldab0ce23f2015-05-04 05:07:31 -0300320 case V4L2_PIX_FMT_Y16_BE:
Hans Verkuil63881df2014-08-25 08:02:14 -0300321 tpg->twopixelsize[0] = 2 * 2;
322 break;
323 case V4L2_PIX_FMT_RGB24:
324 case V4L2_PIX_FMT_BGR24:
325 tpg->twopixelsize[0] = 2 * 3;
326 break;
Hans Verkuil68cd4e92015-03-13 05:36:08 -0300327 case V4L2_PIX_FMT_BGR666:
Hans Verkuil63881df2014-08-25 08:02:14 -0300328 case V4L2_PIX_FMT_RGB32:
329 case V4L2_PIX_FMT_BGR32:
330 case V4L2_PIX_FMT_XRGB32:
331 case V4L2_PIX_FMT_XBGR32:
332 case V4L2_PIX_FMT_ARGB32:
333 case V4L2_PIX_FMT_ABGR32:
Hans Verkuil628821c2015-03-13 06:35:40 -0300334 case V4L2_PIX_FMT_YUV32:
Hans Verkuil63881df2014-08-25 08:02:14 -0300335 tpg->twopixelsize[0] = 2 * 4;
336 break;
Hans Verkuil68c90d62015-03-07 14:55:09 -0300337 case V4L2_PIX_FMT_NV12:
338 case V4L2_PIX_FMT_NV21:
339 case V4L2_PIX_FMT_NV12M:
340 case V4L2_PIX_FMT_NV21M:
Hans Verkuil68c90d62015-03-07 14:55:09 -0300341 case V4L2_PIX_FMT_NV16:
342 case V4L2_PIX_FMT_NV61:
Hans Verkuil63881df2014-08-25 08:02:14 -0300343 case V4L2_PIX_FMT_NV16M:
344 case V4L2_PIX_FMT_NV61M:
Hans Verkuil02aa7692015-03-14 08:01:50 -0300345 case V4L2_PIX_FMT_SBGGR8:
346 case V4L2_PIX_FMT_SGBRG8:
347 case V4L2_PIX_FMT_SGRBG8:
348 case V4L2_PIX_FMT_SRGGB8:
Hans Verkuil63881df2014-08-25 08:02:14 -0300349 tpg->twopixelsize[0] = 2;
350 tpg->twopixelsize[1] = 2;
351 break;
Hans Verkuil68c90d62015-03-07 14:55:09 -0300352 case V4L2_PIX_FMT_YUV422P:
353 case V4L2_PIX_FMT_YUV420:
354 case V4L2_PIX_FMT_YVU420:
355 case V4L2_PIX_FMT_YUV420M:
356 case V4L2_PIX_FMT_YVU420M:
357 tpg->twopixelsize[0] = 2;
358 tpg->twopixelsize[1] = 2;
359 tpg->twopixelsize[2] = 2;
360 break;
Hans Verkuildde72bd2015-03-13 05:51:21 -0300361 case V4L2_PIX_FMT_NV24:
362 case V4L2_PIX_FMT_NV42:
363 tpg->twopixelsize[0] = 2;
364 tpg->twopixelsize[1] = 4;
365 break;
Hans Verkuil63881df2014-08-25 08:02:14 -0300366 }
367 return true;
368}
369
370void tpg_s_crop_compose(struct tpg_data *tpg, const struct v4l2_rect *crop,
371 const struct v4l2_rect *compose)
372{
373 tpg->crop = *crop;
374 tpg->compose = *compose;
375 tpg->scaled_width = (tpg->src_width * tpg->compose.width +
376 tpg->crop.width - 1) / tpg->crop.width;
377 tpg->scaled_width &= ~1;
378 if (tpg->scaled_width > tpg->max_line_width)
379 tpg->scaled_width = tpg->max_line_width;
380 if (tpg->scaled_width < 2)
381 tpg->scaled_width = 2;
382 tpg->recalc_lines = true;
383}
384
385void tpg_reset_source(struct tpg_data *tpg, unsigned width, unsigned height,
Hans Verkuil73d81022014-09-03 10:18:57 -0300386 u32 field)
Hans Verkuil63881df2014-08-25 08:02:14 -0300387{
388 unsigned p;
389
390 tpg->src_width = width;
391 tpg->src_height = height;
392 tpg->field = field;
393 tpg->buf_height = height;
394 if (V4L2_FIELD_HAS_T_OR_B(field))
395 tpg->buf_height /= 2;
396 tpg->scaled_width = width;
397 tpg->crop.top = tpg->crop.left = 0;
398 tpg->crop.width = width;
399 tpg->crop.height = height;
400 tpg->compose.top = tpg->compose.left = 0;
401 tpg->compose.width = width;
402 tpg->compose.height = tpg->buf_height;
403 for (p = 0; p < tpg->planes; p++)
Hans Verkuilba01f672015-03-07 13:57:27 -0300404 tpg->bytesperline[p] = (width * tpg->twopixelsize[p]) /
405 (2 * tpg->hdownsampling[p]);
Hans Verkuil63881df2014-08-25 08:02:14 -0300406 tpg->recalc_square_border = true;
407}
408
409static enum tpg_color tpg_get_textbg_color(struct tpg_data *tpg)
410{
411 switch (tpg->pattern) {
412 case TPG_PAT_BLACK:
413 return TPG_COLOR_100_WHITE;
414 case TPG_PAT_CSC_COLORBAR:
415 return TPG_COLOR_CSC_BLACK;
416 default:
417 return TPG_COLOR_100_BLACK;
418 }
419}
420
421static enum tpg_color tpg_get_textfg_color(struct tpg_data *tpg)
422{
423 switch (tpg->pattern) {
424 case TPG_PAT_75_COLORBAR:
425 case TPG_PAT_CSC_COLORBAR:
426 return TPG_COLOR_CSC_WHITE;
427 case TPG_PAT_BLACK:
428 return TPG_COLOR_100_BLACK;
429 default:
430 return TPG_COLOR_100_WHITE;
431 }
432}
433
Hans Verkuil481b97a2014-11-17 10:14:32 -0300434static inline int rec709_to_linear(int v)
Hans Verkuil63881df2014-08-25 08:02:14 -0300435{
Hans Verkuil481b97a2014-11-17 10:14:32 -0300436 v = clamp(v, 0, 0xff0);
437 return tpg_rec709_to_linear[v];
438}
439
440static inline int linear_to_rec709(int v)
441{
442 v = clamp(v, 0, 0xff0);
443 return tpg_linear_to_rec709[v];
444}
445
446static void rgb2ycbcr(const int m[3][3], int r, int g, int b,
447 int y_offset, int *y, int *cb, int *cr)
448{
449 *y = ((m[0][0] * r + m[0][1] * g + m[0][2] * b) >> 16) + (y_offset << 4);
450 *cb = ((m[1][0] * r + m[1][1] * g + m[1][2] * b) >> 16) + (128 << 4);
451 *cr = ((m[2][0] * r + m[2][1] * g + m[2][2] * b) >> 16) + (128 << 4);
452}
453
454static void color_to_ycbcr(struct tpg_data *tpg, int r, int g, int b,
455 int *y, int *cb, int *cr)
456{
457#define COEFF(v, r) ((int)(0.5 + (v) * (r) * 256.0))
458
459 static const int bt601[3][3] = {
460 { COEFF(0.299, 219), COEFF(0.587, 219), COEFF(0.114, 219) },
461 { COEFF(-0.169, 224), COEFF(-0.331, 224), COEFF(0.5, 224) },
462 { COEFF(0.5, 224), COEFF(-0.419, 224), COEFF(-0.081, 224) },
463 };
464 static const int bt601_full[3][3] = {
465 { COEFF(0.299, 255), COEFF(0.587, 255), COEFF(0.114, 255) },
466 { COEFF(-0.169, 255), COEFF(-0.331, 255), COEFF(0.5, 255) },
467 { COEFF(0.5, 255), COEFF(-0.419, 255), COEFF(-0.081, 255) },
468 };
469 static const int rec709[3][3] = {
470 { COEFF(0.2126, 219), COEFF(0.7152, 219), COEFF(0.0722, 219) },
471 { COEFF(-0.1146, 224), COEFF(-0.3854, 224), COEFF(0.5, 224) },
472 { COEFF(0.5, 224), COEFF(-0.4542, 224), COEFF(-0.0458, 224) },
473 };
474 static const int rec709_full[3][3] = {
475 { COEFF(0.2126, 255), COEFF(0.7152, 255), COEFF(0.0722, 255) },
476 { COEFF(-0.1146, 255), COEFF(-0.3854, 255), COEFF(0.5, 255) },
477 { COEFF(0.5, 255), COEFF(-0.4542, 255), COEFF(-0.0458, 255) },
478 };
479 static const int smpte240m[3][3] = {
480 { COEFF(0.212, 219), COEFF(0.701, 219), COEFF(0.087, 219) },
481 { COEFF(-0.116, 224), COEFF(-0.384, 224), COEFF(0.5, 224) },
482 { COEFF(0.5, 224), COEFF(-0.445, 224), COEFF(-0.055, 224) },
483 };
Hans Verkuilc702f682015-04-24 11:16:23 -0300484 static const int smpte240m_full[3][3] = {
485 { COEFF(0.212, 255), COEFF(0.701, 255), COEFF(0.087, 255) },
486 { COEFF(-0.116, 255), COEFF(-0.384, 255), COEFF(0.5, 255) },
487 { COEFF(0.5, 255), COEFF(-0.445, 255), COEFF(-0.055, 255) },
488 };
Hans Verkuil481b97a2014-11-17 10:14:32 -0300489 static const int bt2020[3][3] = {
Hans Verkuile202e512015-03-20 13:23:06 -0300490 { COEFF(0.2627, 219), COEFF(0.6780, 219), COEFF(0.0593, 219) },
Hans Verkuil481b97a2014-11-17 10:14:32 -0300491 { COEFF(-0.1396, 224), COEFF(-0.3604, 224), COEFF(0.5, 224) },
Hans Verkuile202e512015-03-20 13:23:06 -0300492 { COEFF(0.5, 224), COEFF(-0.4598, 224), COEFF(-0.0402, 224) },
Hans Verkuil481b97a2014-11-17 10:14:32 -0300493 };
Hans Verkuilcf73b712015-04-24 11:16:24 -0300494 static const int bt2020_full[3][3] = {
495 { COEFF(0.2627, 255), COEFF(0.6780, 255), COEFF(0.0593, 255) },
496 { COEFF(-0.1396, 255), COEFF(-0.3604, 255), COEFF(0.5, 255) },
497 { COEFF(0.5, 255), COEFF(-0.4698, 255), COEFF(-0.0402, 255) },
498 };
Hans Verkuilbbfef492015-04-24 11:16:25 -0300499 static const int bt2020c[4] = {
500 COEFF(1.0 / 1.9404, 224), COEFF(1.0 / 1.5816, 224),
501 COEFF(1.0 / 1.7184, 224), COEFF(1.0 / 0.9936, 224),
502 };
503 static const int bt2020c_full[4] = {
504 COEFF(1.0 / 1.9404, 255), COEFF(1.0 / 1.5816, 255),
505 COEFF(1.0 / 1.7184, 255), COEFF(1.0 / 0.9936, 255),
506 };
Hans Verkuilcf73b712015-04-24 11:16:24 -0300507
Hans Verkuil481b97a2014-11-17 10:14:32 -0300508 bool full = tpg->real_quantization == V4L2_QUANTIZATION_FULL_RANGE;
Hans Verkuilafad4dd2015-01-27 13:46:17 -0300509 unsigned y_offset = full ? 0 : 16;
Hans Verkuil481b97a2014-11-17 10:14:32 -0300510 int lin_y, yc;
511
512 switch (tpg->real_ycbcr_enc) {
513 case V4L2_YCBCR_ENC_601:
Hans Verkuil481b97a2014-11-17 10:14:32 -0300514 case V4L2_YCBCR_ENC_SYCC:
Hans Verkuilafad4dd2015-01-27 13:46:17 -0300515 rgb2ycbcr(full ? bt601_full : bt601, r, g, b, y_offset, y, cb, cr);
Hans Verkuil481b97a2014-11-17 10:14:32 -0300516 break;
Hans Verkuilf6b8af22015-04-24 11:16:26 -0300517 case V4L2_YCBCR_ENC_XV601:
518 /* Ignore quantization range, there is only one possible
519 * Y'CbCr encoding. */
520 rgb2ycbcr(bt601, r, g, b, 16, y, cb, cr);
521 break;
522 case V4L2_YCBCR_ENC_XV709:
523 /* Ignore quantization range, there is only one possible
524 * Y'CbCr encoding. */
525 rgb2ycbcr(rec709, r, g, b, 16, y, cb, cr);
526 break;
Hans Verkuil481b97a2014-11-17 10:14:32 -0300527 case V4L2_YCBCR_ENC_BT2020:
Hans Verkuilcf73b712015-04-24 11:16:24 -0300528 rgb2ycbcr(full ? bt2020_full : bt2020, r, g, b, y_offset, y, cb, cr);
Hans Verkuil481b97a2014-11-17 10:14:32 -0300529 break;
530 case V4L2_YCBCR_ENC_BT2020_CONST_LUM:
531 lin_y = (COEFF(0.2627, 255) * rec709_to_linear(r) +
532 COEFF(0.6780, 255) * rec709_to_linear(g) +
533 COEFF(0.0593, 255) * rec709_to_linear(b)) >> 16;
534 yc = linear_to_rec709(lin_y);
Hans Verkuilbbfef492015-04-24 11:16:25 -0300535 *y = full ? yc : (yc * 219) / 255 + (16 << 4);
Hans Verkuil481b97a2014-11-17 10:14:32 -0300536 if (b <= yc)
Hans Verkuilbbfef492015-04-24 11:16:25 -0300537 *cb = (((b - yc) * (full ? bt2020c_full[0] : bt2020c[0])) >> 16) + (128 << 4);
Hans Verkuil481b97a2014-11-17 10:14:32 -0300538 else
Hans Verkuilbbfef492015-04-24 11:16:25 -0300539 *cb = (((b - yc) * (full ? bt2020c_full[1] : bt2020c[1])) >> 16) + (128 << 4);
Hans Verkuil481b97a2014-11-17 10:14:32 -0300540 if (r <= yc)
Hans Verkuilbbfef492015-04-24 11:16:25 -0300541 *cr = (((r - yc) * (full ? bt2020c_full[2] : bt2020c[2])) >> 16) + (128 << 4);
Hans Verkuil481b97a2014-11-17 10:14:32 -0300542 else
Hans Verkuilbbfef492015-04-24 11:16:25 -0300543 *cr = (((r - yc) * (full ? bt2020c_full[3] : bt2020c[3])) >> 16) + (128 << 4);
Hans Verkuil481b97a2014-11-17 10:14:32 -0300544 break;
545 case V4L2_YCBCR_ENC_SMPTE240M:
Hans Verkuilc702f682015-04-24 11:16:23 -0300546 rgb2ycbcr(full ? smpte240m_full : smpte240m, r, g, b, y_offset, y, cb, cr);
Hans Verkuil481b97a2014-11-17 10:14:32 -0300547 break;
548 case V4L2_YCBCR_ENC_709:
Hans Verkuil63881df2014-08-25 08:02:14 -0300549 default:
Hans Verkuilafad4dd2015-01-27 13:46:17 -0300550 rgb2ycbcr(full ? rec709_full : rec709, r, g, b, y_offset, y, cb, cr);
Hans Verkuil481b97a2014-11-17 10:14:32 -0300551 break;
Hans Verkuil63881df2014-08-25 08:02:14 -0300552 }
553}
554
Hans Verkuil481b97a2014-11-17 10:14:32 -0300555static void ycbcr2rgb(const int m[3][3], int y, int cb, int cr,
556 int y_offset, int *r, int *g, int *b)
Hans Verkuil63881df2014-08-25 08:02:14 -0300557{
Hans Verkuil481b97a2014-11-17 10:14:32 -0300558 y -= y_offset << 4;
Hans Verkuil63881df2014-08-25 08:02:14 -0300559 cb -= 128 << 4;
560 cr -= 128 << 4;
Hans Verkuil481b97a2014-11-17 10:14:32 -0300561 *r = m[0][0] * y + m[0][1] * cb + m[0][2] * cr;
562 *g = m[1][0] * y + m[1][1] * cb + m[1][2] * cr;
563 *b = m[2][0] * y + m[2][1] * cb + m[2][2] * cr;
564 *r = clamp(*r >> 12, 0, 0xff0);
565 *g = clamp(*g >> 12, 0, 0xff0);
566 *b = clamp(*b >> 12, 0, 0xff0);
Hans Verkuil63881df2014-08-25 08:02:14 -0300567}
568
Hans Verkuil481b97a2014-11-17 10:14:32 -0300569static void ycbcr_to_color(struct tpg_data *tpg, int y, int cb, int cr,
570 int *r, int *g, int *b)
Hans Verkuil63881df2014-08-25 08:02:14 -0300571{
Hans Verkuil481b97a2014-11-17 10:14:32 -0300572#undef COEFF
573#define COEFF(v, r) ((int)(0.5 + (v) * ((255.0 * 255.0 * 16.0) / (r))))
574 static const int bt601[3][3] = {
575 { COEFF(1, 219), COEFF(0, 224), COEFF(1.4020, 224) },
576 { COEFF(1, 219), COEFF(-0.3441, 224), COEFF(-0.7141, 224) },
577 { COEFF(1, 219), COEFF(1.7720, 224), COEFF(0, 224) },
578 };
579 static const int bt601_full[3][3] = {
580 { COEFF(1, 255), COEFF(0, 255), COEFF(1.4020, 255) },
581 { COEFF(1, 255), COEFF(-0.3441, 255), COEFF(-0.7141, 255) },
582 { COEFF(1, 255), COEFF(1.7720, 255), COEFF(0, 255) },
583 };
584 static const int rec709[3][3] = {
585 { COEFF(1, 219), COEFF(0, 224), COEFF(1.5748, 224) },
586 { COEFF(1, 219), COEFF(-0.1873, 224), COEFF(-0.4681, 224) },
587 { COEFF(1, 219), COEFF(1.8556, 224), COEFF(0, 224) },
588 };
589 static const int rec709_full[3][3] = {
590 { COEFF(1, 255), COEFF(0, 255), COEFF(1.5748, 255) },
591 { COEFF(1, 255), COEFF(-0.1873, 255), COEFF(-0.4681, 255) },
592 { COEFF(1, 255), COEFF(1.8556, 255), COEFF(0, 255) },
593 };
594 static const int smpte240m[3][3] = {
595 { COEFF(1, 219), COEFF(0, 224), COEFF(1.5756, 224) },
596 { COEFF(1, 219), COEFF(-0.2253, 224), COEFF(-0.4767, 224) },
597 { COEFF(1, 219), COEFF(1.8270, 224), COEFF(0, 224) },
598 };
Hans Verkuilc702f682015-04-24 11:16:23 -0300599 static const int smpte240m_full[3][3] = {
600 { COEFF(1, 255), COEFF(0, 255), COEFF(1.5756, 255) },
601 { COEFF(1, 255), COEFF(-0.2253, 255), COEFF(-0.4767, 255) },
602 { COEFF(1, 255), COEFF(1.8270, 255), COEFF(0, 255) },
603 };
Hans Verkuil481b97a2014-11-17 10:14:32 -0300604 static const int bt2020[3][3] = {
605 { COEFF(1, 219), COEFF(0, 224), COEFF(1.4746, 224) },
606 { COEFF(1, 219), COEFF(-0.1646, 224), COEFF(-0.5714, 224) },
607 { COEFF(1, 219), COEFF(1.8814, 224), COEFF(0, 224) },
608 };
Hans Verkuilcf73b712015-04-24 11:16:24 -0300609 static const int bt2020_full[3][3] = {
610 { COEFF(1, 255), COEFF(0, 255), COEFF(1.4746, 255) },
611 { COEFF(1, 255), COEFF(-0.1646, 255), COEFF(-0.5714, 255) },
612 { COEFF(1, 255), COEFF(1.8814, 255), COEFF(0, 255) },
613 };
Hans Verkuilbbfef492015-04-24 11:16:25 -0300614 static const int bt2020c[4] = {
615 COEFF(1.9404, 224), COEFF(1.5816, 224),
616 COEFF(1.7184, 224), COEFF(0.9936, 224),
617 };
618 static const int bt2020c_full[4] = {
619 COEFF(1.9404, 255), COEFF(1.5816, 255),
620 COEFF(1.7184, 255), COEFF(0.9936, 255),
621 };
622
Hans Verkuil481b97a2014-11-17 10:14:32 -0300623 bool full = tpg->real_quantization == V4L2_QUANTIZATION_FULL_RANGE;
Hans Verkuilafad4dd2015-01-27 13:46:17 -0300624 unsigned y_offset = full ? 0 : 16;
Hans Verkuilbbfef492015-04-24 11:16:25 -0300625 int y_fac = full ? COEFF(1.0, 255) : COEFF(1.0, 219);
Hans Verkuil481b97a2014-11-17 10:14:32 -0300626 int lin_r, lin_g, lin_b, lin_y;
Hans Verkuil63881df2014-08-25 08:02:14 -0300627
Hans Verkuil481b97a2014-11-17 10:14:32 -0300628 switch (tpg->real_ycbcr_enc) {
629 case V4L2_YCBCR_ENC_601:
Hans Verkuil481b97a2014-11-17 10:14:32 -0300630 case V4L2_YCBCR_ENC_SYCC:
Hans Verkuilafad4dd2015-01-27 13:46:17 -0300631 ycbcr2rgb(full ? bt601_full : bt601, y, cb, cr, y_offset, r, g, b);
Hans Verkuil63881df2014-08-25 08:02:14 -0300632 break;
Hans Verkuilf6b8af22015-04-24 11:16:26 -0300633 case V4L2_YCBCR_ENC_XV601:
634 /* Ignore quantization range, there is only one possible
635 * Y'CbCr encoding. */
636 ycbcr2rgb(bt601, y, cb, cr, 16, r, g, b);
637 break;
638 case V4L2_YCBCR_ENC_XV709:
639 /* Ignore quantization range, there is only one possible
640 * Y'CbCr encoding. */
641 ycbcr2rgb(rec709, y, cb, cr, 16, r, g, b);
642 break;
Hans Verkuil481b97a2014-11-17 10:14:32 -0300643 case V4L2_YCBCR_ENC_BT2020:
Hans Verkuilcf73b712015-04-24 11:16:24 -0300644 ycbcr2rgb(full ? bt2020_full : bt2020, y, cb, cr, y_offset, r, g, b);
Hans Verkuil63881df2014-08-25 08:02:14 -0300645 break;
Hans Verkuil481b97a2014-11-17 10:14:32 -0300646 case V4L2_YCBCR_ENC_BT2020_CONST_LUM:
Hans Verkuilbbfef492015-04-24 11:16:25 -0300647 y -= full ? 0 : 16 << 4;
Hans Verkuil481b97a2014-11-17 10:14:32 -0300648 cb -= 128 << 4;
649 cr -= 128 << 4;
650
651 if (cb <= 0)
Hans Verkuilbbfef492015-04-24 11:16:25 -0300652 *b = y_fac * y + (full ? bt2020c_full[0] : bt2020c[0]) * cb;
Hans Verkuil481b97a2014-11-17 10:14:32 -0300653 else
Hans Verkuilbbfef492015-04-24 11:16:25 -0300654 *b = y_fac * y + (full ? bt2020c_full[1] : bt2020c[1]) * cb;
Hans Verkuil481b97a2014-11-17 10:14:32 -0300655 *b = *b >> 12;
656 if (cr <= 0)
Hans Verkuilbbfef492015-04-24 11:16:25 -0300657 *r = y_fac * y + (full ? bt2020c_full[2] : bt2020c[2]) * cr;
Hans Verkuil481b97a2014-11-17 10:14:32 -0300658 else
Hans Verkuilbbfef492015-04-24 11:16:25 -0300659 *r = y_fac * y + (full ? bt2020c_full[3] : bt2020c[3]) * cr;
Hans Verkuil481b97a2014-11-17 10:14:32 -0300660 *r = *r >> 12;
661 lin_r = rec709_to_linear(*r);
662 lin_b = rec709_to_linear(*b);
Hans Verkuilbbfef492015-04-24 11:16:25 -0300663 lin_y = rec709_to_linear((y * 255) / (full ? 255 : 219));
Hans Verkuil481b97a2014-11-17 10:14:32 -0300664
665 lin_g = COEFF(1.0 / 0.6780, 255) * lin_y -
666 COEFF(0.2627 / 0.6780, 255) * lin_r -
667 COEFF(0.0593 / 0.6780, 255) * lin_b;
668 *g = linear_to_rec709(lin_g >> 12);
669 break;
670 case V4L2_YCBCR_ENC_SMPTE240M:
Hans Verkuilc702f682015-04-24 11:16:23 -0300671 ycbcr2rgb(full ? smpte240m_full : smpte240m, y, cb, cr, y_offset, r, g, b);
Hans Verkuil481b97a2014-11-17 10:14:32 -0300672 break;
673 case V4L2_YCBCR_ENC_709:
Hans Verkuil63881df2014-08-25 08:02:14 -0300674 default:
Hans Verkuilafad4dd2015-01-27 13:46:17 -0300675 ycbcr2rgb(full ? rec709_full : rec709, y, cb, cr, y_offset, r, g, b);
Hans Verkuil63881df2014-08-25 08:02:14 -0300676 break;
677 }
Hans Verkuil63881df2014-08-25 08:02:14 -0300678}
679
680/* precalculate color bar values to speed up rendering */
681static void precalculate_color(struct tpg_data *tpg, int k)
682{
683 int col = k;
684 int r = tpg_colors[col].r;
685 int g = tpg_colors[col].g;
686 int b = tpg_colors[col].b;
687
688 if (k == TPG_COLOR_TEXTBG) {
689 col = tpg_get_textbg_color(tpg);
690
691 r = tpg_colors[col].r;
692 g = tpg_colors[col].g;
693 b = tpg_colors[col].b;
694 } else if (k == TPG_COLOR_TEXTFG) {
695 col = tpg_get_textfg_color(tpg);
696
697 r = tpg_colors[col].r;
698 g = tpg_colors[col].g;
699 b = tpg_colors[col].b;
700 } else if (tpg->pattern == TPG_PAT_NOISE) {
701 r = g = b = prandom_u32_max(256);
702 } else if (k == TPG_COLOR_RANDOM) {
703 r = g = b = tpg->qual_offset + prandom_u32_max(196);
704 } else if (k >= TPG_COLOR_RAMP) {
705 r = g = b = k - TPG_COLOR_RAMP;
706 }
707
708 if (tpg->pattern == TPG_PAT_CSC_COLORBAR && col <= TPG_COLOR_CSC_BLACK) {
709 r = tpg_csc_colors[tpg->colorspace][col].r;
710 g = tpg_csc_colors[tpg->colorspace][col].g;
711 b = tpg_csc_colors[tpg->colorspace][col].b;
712 } else {
713 r <<= 4;
714 g <<= 4;
715 b <<= 4;
716 }
Ricardo Ribalda18b3b3b2015-05-04 05:07:29 -0300717 if (tpg->qual == TPG_QUAL_GRAY || tpg->fourcc == V4L2_PIX_FMT_GREY ||
Ricardo Ribaldab0ce23f2015-05-04 05:07:31 -0300718 tpg->fourcc == V4L2_PIX_FMT_Y16 ||
719 tpg->fourcc == V4L2_PIX_FMT_Y16_BE) {
Hans Verkuil481b97a2014-11-17 10:14:32 -0300720 /* Rec. 709 Luma function */
721 /* (0.2126, 0.7152, 0.0722) * (255 * 256) */
Hans Verkuil9c35bd42015-03-07 12:53:39 -0300722 r = g = b = (13879 * r + 46688 * g + 4713 * b) >> 16;
Hans Verkuil481b97a2014-11-17 10:14:32 -0300723 }
Hans Verkuil63881df2014-08-25 08:02:14 -0300724
725 /*
726 * The assumption is that the RGB output is always full range,
727 * so only if the rgb_range overrides the 'real' rgb range do
728 * we need to convert the RGB values.
729 *
Hans Verkuil63881df2014-08-25 08:02:14 -0300730 * Remember that r, g and b are still in the 0 - 0xff0 range.
731 */
732 if (tpg->real_rgb_range == V4L2_DV_RGB_RANGE_LIMITED &&
733 tpg->rgb_range == V4L2_DV_RGB_RANGE_FULL) {
734 /*
735 * Convert from full range (which is what r, g and b are)
736 * to limited range (which is the 'real' RGB range), which
737 * is then interpreted as full range.
738 */
739 r = (r * 219) / 255 + (16 << 4);
740 g = (g * 219) / 255 + (16 << 4);
741 b = (b * 219) / 255 + (16 << 4);
742 } else if (tpg->real_rgb_range != V4L2_DV_RGB_RANGE_LIMITED &&
743 tpg->rgb_range == V4L2_DV_RGB_RANGE_LIMITED) {
744 /*
745 * Clamp r, g and b to the limited range and convert to full
746 * range since that's what we deliver.
747 */
748 r = clamp(r, 16 << 4, 235 << 4);
749 g = clamp(g, 16 << 4, 235 << 4);
750 b = clamp(b, 16 << 4, 235 << 4);
751 r = (r - (16 << 4)) * 255 / 219;
752 g = (g - (16 << 4)) * 255 / 219;
753 b = (b - (16 << 4)) * 255 / 219;
754 }
755
756 if (tpg->brightness != 128 || tpg->contrast != 128 ||
757 tpg->saturation != 128 || tpg->hue) {
758 /* Implement these operations */
Hans Verkuil481b97a2014-11-17 10:14:32 -0300759 int y, cb, cr;
760 int tmp_cb, tmp_cr;
Hans Verkuil63881df2014-08-25 08:02:14 -0300761
762 /* First convert to YCbCr */
Hans Verkuil481b97a2014-11-17 10:14:32 -0300763
764 color_to_ycbcr(tpg, r, g, b, &y, &cb, &cr);
Hans Verkuil63881df2014-08-25 08:02:14 -0300765
766 y = (16 << 4) + ((y - (16 << 4)) * tpg->contrast) / 128;
767 y += (tpg->brightness << 4) - (128 << 4);
768
769 cb -= 128 << 4;
770 cr -= 128 << 4;
771 tmp_cb = (cb * cos(128 + tpg->hue)) / 127 + (cr * sin[128 + tpg->hue]) / 127;
772 tmp_cr = (cr * cos(128 + tpg->hue)) / 127 - (cb * sin[128 + tpg->hue]) / 127;
773
774 cb = (128 << 4) + (tmp_cb * tpg->contrast * tpg->saturation) / (128 * 128);
775 cr = (128 << 4) + (tmp_cr * tpg->contrast * tpg->saturation) / (128 * 128);
776 if (tpg->is_yuv) {
777 tpg->colors[k][0] = clamp(y >> 4, 1, 254);
778 tpg->colors[k][1] = clamp(cb >> 4, 1, 254);
779 tpg->colors[k][2] = clamp(cr >> 4, 1, 254);
780 return;
781 }
Hans Verkuil481b97a2014-11-17 10:14:32 -0300782 ycbcr_to_color(tpg, y, cb, cr, &r, &g, &b);
Hans Verkuil63881df2014-08-25 08:02:14 -0300783 }
784
785 if (tpg->is_yuv) {
786 /* Convert to YCbCr */
Hans Verkuil481b97a2014-11-17 10:14:32 -0300787 int y, cb, cr;
Hans Verkuil63881df2014-08-25 08:02:14 -0300788
Hans Verkuil481b97a2014-11-17 10:14:32 -0300789 color_to_ycbcr(tpg, r, g, b, &y, &cb, &cr);
790
791 if (tpg->real_quantization == V4L2_QUANTIZATION_LIM_RANGE) {
792 y = clamp(y, 16 << 4, 235 << 4);
793 cb = clamp(cb, 16 << 4, 240 << 4);
794 cr = clamp(cr, 16 << 4, 240 << 4);
795 }
Hans Verkuil628821c2015-03-13 06:35:40 -0300796 y = clamp(y >> 4, 1, 254);
797 cb = clamp(cb >> 4, 1, 254);
798 cr = clamp(cr >> 4, 1, 254);
799 switch (tpg->fourcc) {
800 case V4L2_PIX_FMT_YUV444:
801 y >>= 4;
802 cb >>= 4;
803 cr >>= 4;
804 break;
805 case V4L2_PIX_FMT_YUV555:
806 y >>= 3;
807 cb >>= 3;
808 cr >>= 3;
809 break;
810 case V4L2_PIX_FMT_YUV565:
811 y >>= 3;
812 cb >>= 2;
813 cr >>= 3;
814 break;
815 }
816 tpg->colors[k][0] = y;
817 tpg->colors[k][1] = cb;
818 tpg->colors[k][2] = cr;
Hans Verkuil63881df2014-08-25 08:02:14 -0300819 } else {
Hans Verkuil481b97a2014-11-17 10:14:32 -0300820 if (tpg->real_quantization == V4L2_QUANTIZATION_LIM_RANGE) {
821 r = (r * 219) / 255 + (16 << 4);
822 g = (g * 219) / 255 + (16 << 4);
823 b = (b * 219) / 255 + (16 << 4);
824 }
Hans Verkuil63881df2014-08-25 08:02:14 -0300825 switch (tpg->fourcc) {
Hans Verkuil71491062015-03-12 15:40:36 -0300826 case V4L2_PIX_FMT_RGB332:
827 r >>= 9;
828 g >>= 9;
829 b >>= 10;
830 break;
Hans Verkuil63881df2014-08-25 08:02:14 -0300831 case V4L2_PIX_FMT_RGB565:
832 case V4L2_PIX_FMT_RGB565X:
833 r >>= 7;
834 g >>= 6;
835 b >>= 7;
836 break;
Hans Verkuil8aca2302015-03-11 08:14:34 -0300837 case V4L2_PIX_FMT_RGB444:
838 case V4L2_PIX_FMT_XRGB444:
839 case V4L2_PIX_FMT_ARGB444:
840 r >>= 8;
841 g >>= 8;
842 b >>= 8;
843 break;
Hans Verkuil63881df2014-08-25 08:02:14 -0300844 case V4L2_PIX_FMT_RGB555:
845 case V4L2_PIX_FMT_XRGB555:
846 case V4L2_PIX_FMT_ARGB555:
847 case V4L2_PIX_FMT_RGB555X:
Hans Verkuil8f1ff542015-03-12 05:08:01 -0300848 case V4L2_PIX_FMT_XRGB555X:
849 case V4L2_PIX_FMT_ARGB555X:
Hans Verkuil63881df2014-08-25 08:02:14 -0300850 r >>= 7;
851 g >>= 7;
852 b >>= 7;
853 break;
Hans Verkuil68cd4e92015-03-13 05:36:08 -0300854 case V4L2_PIX_FMT_BGR666:
855 r >>= 6;
856 g >>= 6;
857 b >>= 6;
858 break;
Hans Verkuil63881df2014-08-25 08:02:14 -0300859 default:
860 r >>= 4;
861 g >>= 4;
862 b >>= 4;
863 break;
864 }
865
866 tpg->colors[k][0] = r;
867 tpg->colors[k][1] = g;
868 tpg->colors[k][2] = b;
869 }
870}
871
872static void tpg_precalculate_colors(struct tpg_data *tpg)
873{
874 int k;
875
876 for (k = 0; k < TPG_COLOR_MAX; k++)
877 precalculate_color(tpg, k);
878}
879
880/* 'odd' is true for pixels 1, 3, 5, etc. and false for pixels 0, 2, 4, etc. */
881static void gen_twopix(struct tpg_data *tpg,
882 u8 buf[TPG_MAX_PLANES][8], int color, bool odd)
883{
884 unsigned offset = odd * tpg->twopixelsize[0] / 2;
885 u8 alpha = tpg->alpha_component;
886 u8 r_y, g_u, b_v;
887
888 if (tpg->alpha_red_only && color != TPG_COLOR_CSC_RED &&
889 color != TPG_COLOR_100_RED &&
890 color != TPG_COLOR_75_RED)
891 alpha = 0;
892 if (color == TPG_COLOR_RANDOM)
893 precalculate_color(tpg, color);
894 r_y = tpg->colors[color][0]; /* R or precalculated Y */
895 g_u = tpg->colors[color][1]; /* G or precalculated U */
896 b_v = tpg->colors[color][2]; /* B or precalculated V */
897
898 switch (tpg->fourcc) {
Hans Verkuil51f30962015-03-07 14:57:50 -0300899 case V4L2_PIX_FMT_GREY:
900 buf[0][offset] = r_y;
901 break;
Ricardo Ribalda18b3b3b2015-05-04 05:07:29 -0300902 case V4L2_PIX_FMT_Y16:
903 buf[0][offset] = 0;
904 buf[0][offset+1] = r_y;
905 break;
Ricardo Ribaldab0ce23f2015-05-04 05:07:31 -0300906 case V4L2_PIX_FMT_Y16_BE:
907 buf[0][offset] = r_y;
908 buf[0][offset+1] = 0;
909 break;
Hans Verkuil68c90d62015-03-07 14:55:09 -0300910 case V4L2_PIX_FMT_YUV422P:
911 case V4L2_PIX_FMT_YUV420:
912 case V4L2_PIX_FMT_YUV420M:
913 buf[0][offset] = r_y;
914 if (odd) {
915 buf[1][0] = (buf[1][0] + g_u) / 2;
916 buf[2][0] = (buf[2][0] + b_v) / 2;
917 buf[1][1] = buf[1][0];
918 buf[2][1] = buf[2][0];
919 break;
920 }
921 buf[1][0] = g_u;
922 buf[2][0] = b_v;
923 break;
924 case V4L2_PIX_FMT_YVU420:
925 case V4L2_PIX_FMT_YVU420M:
926 buf[0][offset] = r_y;
927 if (odd) {
928 buf[1][0] = (buf[1][0] + b_v) / 2;
929 buf[2][0] = (buf[2][0] + g_u) / 2;
930 buf[1][1] = buf[1][0];
931 buf[2][1] = buf[2][0];
932 break;
933 }
934 buf[1][0] = b_v;
935 buf[2][0] = g_u;
936 break;
937
938 case V4L2_PIX_FMT_NV12:
939 case V4L2_PIX_FMT_NV12M:
940 case V4L2_PIX_FMT_NV16:
Hans Verkuil63881df2014-08-25 08:02:14 -0300941 case V4L2_PIX_FMT_NV16M:
942 buf[0][offset] = r_y;
Hans Verkuil1f088dc2015-03-07 14:15:25 -0300943 if (odd) {
944 buf[1][0] = (buf[1][0] + g_u) / 2;
945 buf[1][1] = (buf[1][1] + b_v) / 2;
946 break;
947 }
948 buf[1][0] = g_u;
949 buf[1][1] = b_v;
Hans Verkuil63881df2014-08-25 08:02:14 -0300950 break;
Hans Verkuil68c90d62015-03-07 14:55:09 -0300951 case V4L2_PIX_FMT_NV21:
952 case V4L2_PIX_FMT_NV21M:
953 case V4L2_PIX_FMT_NV61:
Hans Verkuil63881df2014-08-25 08:02:14 -0300954 case V4L2_PIX_FMT_NV61M:
955 buf[0][offset] = r_y;
Hans Verkuil1f088dc2015-03-07 14:15:25 -0300956 if (odd) {
957 buf[1][0] = (buf[1][0] + b_v) / 2;
958 buf[1][1] = (buf[1][1] + g_u) / 2;
959 break;
960 }
961 buf[1][0] = b_v;
962 buf[1][1] = g_u;
Hans Verkuil63881df2014-08-25 08:02:14 -0300963 break;
964
Hans Verkuildde72bd2015-03-13 05:51:21 -0300965 case V4L2_PIX_FMT_NV24:
966 buf[0][offset] = r_y;
967 buf[1][2 * offset] = g_u;
968 buf[1][2 * offset + 1] = b_v;
969 break;
970
971 case V4L2_PIX_FMT_NV42:
972 buf[0][offset] = r_y;
973 buf[1][2 * offset] = b_v;
974 buf[1][2 * offset + 1] = g_u;
975 break;
976
Hans Verkuil63881df2014-08-25 08:02:14 -0300977 case V4L2_PIX_FMT_YUYV:
978 buf[0][offset] = r_y;
Hans Verkuil1f088dc2015-03-07 14:15:25 -0300979 if (odd) {
980 buf[0][1] = (buf[0][1] + g_u) / 2;
981 buf[0][3] = (buf[0][3] + b_v) / 2;
982 break;
983 }
984 buf[0][1] = g_u;
985 buf[0][3] = b_v;
Hans Verkuil63881df2014-08-25 08:02:14 -0300986 break;
987 case V4L2_PIX_FMT_UYVY:
Hans Verkuil63881df2014-08-25 08:02:14 -0300988 buf[0][offset + 1] = r_y;
Hans Verkuil1f088dc2015-03-07 14:15:25 -0300989 if (odd) {
990 buf[0][0] = (buf[0][0] + g_u) / 2;
991 buf[0][2] = (buf[0][2] + b_v) / 2;
992 break;
993 }
994 buf[0][0] = g_u;
995 buf[0][2] = b_v;
Hans Verkuil63881df2014-08-25 08:02:14 -0300996 break;
997 case V4L2_PIX_FMT_YVYU:
998 buf[0][offset] = r_y;
Hans Verkuil1f088dc2015-03-07 14:15:25 -0300999 if (odd) {
1000 buf[0][1] = (buf[0][1] + b_v) / 2;
1001 buf[0][3] = (buf[0][3] + g_u) / 2;
1002 break;
1003 }
1004 buf[0][1] = b_v;
1005 buf[0][3] = g_u;
Hans Verkuil63881df2014-08-25 08:02:14 -03001006 break;
1007 case V4L2_PIX_FMT_VYUY:
Hans Verkuil63881df2014-08-25 08:02:14 -03001008 buf[0][offset + 1] = r_y;
Hans Verkuil1f088dc2015-03-07 14:15:25 -03001009 if (odd) {
1010 buf[0][0] = (buf[0][0] + b_v) / 2;
1011 buf[0][2] = (buf[0][2] + g_u) / 2;
1012 break;
1013 }
1014 buf[0][0] = b_v;
1015 buf[0][2] = g_u;
Hans Verkuil63881df2014-08-25 08:02:14 -03001016 break;
Hans Verkuil71491062015-03-12 15:40:36 -03001017 case V4L2_PIX_FMT_RGB332:
1018 buf[0][offset] = (r_y << 5) | (g_u << 2) | b_v;
1019 break;
Hans Verkuil628821c2015-03-13 06:35:40 -03001020 case V4L2_PIX_FMT_YUV565:
Hans Verkuil63881df2014-08-25 08:02:14 -03001021 case V4L2_PIX_FMT_RGB565:
1022 buf[0][offset] = (g_u << 5) | b_v;
1023 buf[0][offset + 1] = (r_y << 3) | (g_u >> 3);
1024 break;
1025 case V4L2_PIX_FMT_RGB565X:
1026 buf[0][offset] = (r_y << 3) | (g_u >> 3);
1027 buf[0][offset + 1] = (g_u << 5) | b_v;
1028 break;
Hans Verkuil8aca2302015-03-11 08:14:34 -03001029 case V4L2_PIX_FMT_RGB444:
1030 case V4L2_PIX_FMT_XRGB444:
1031 alpha = 0;
1032 /* fall through */
Hans Verkuil628821c2015-03-13 06:35:40 -03001033 case V4L2_PIX_FMT_YUV444:
Hans Verkuil8aca2302015-03-11 08:14:34 -03001034 case V4L2_PIX_FMT_ARGB444:
1035 buf[0][offset] = (g_u << 4) | b_v;
1036 buf[0][offset + 1] = (alpha & 0xf0) | r_y;
1037 break;
Hans Verkuil63881df2014-08-25 08:02:14 -03001038 case V4L2_PIX_FMT_RGB555:
1039 case V4L2_PIX_FMT_XRGB555:
1040 alpha = 0;
1041 /* fall through */
Hans Verkuil628821c2015-03-13 06:35:40 -03001042 case V4L2_PIX_FMT_YUV555:
Hans Verkuil63881df2014-08-25 08:02:14 -03001043 case V4L2_PIX_FMT_ARGB555:
1044 buf[0][offset] = (g_u << 5) | b_v;
1045 buf[0][offset + 1] = (alpha & 0x80) | (r_y << 2) | (g_u >> 3);
1046 break;
1047 case V4L2_PIX_FMT_RGB555X:
Hans Verkuil8f1ff542015-03-12 05:08:01 -03001048 case V4L2_PIX_FMT_XRGB555X:
1049 alpha = 0;
1050 /* fall through */
1051 case V4L2_PIX_FMT_ARGB555X:
Hans Verkuil63881df2014-08-25 08:02:14 -03001052 buf[0][offset] = (alpha & 0x80) | (r_y << 2) | (g_u >> 3);
1053 buf[0][offset + 1] = (g_u << 5) | b_v;
1054 break;
1055 case V4L2_PIX_FMT_RGB24:
1056 buf[0][offset] = r_y;
1057 buf[0][offset + 1] = g_u;
1058 buf[0][offset + 2] = b_v;
1059 break;
1060 case V4L2_PIX_FMT_BGR24:
1061 buf[0][offset] = b_v;
1062 buf[0][offset + 1] = g_u;
1063 buf[0][offset + 2] = r_y;
1064 break;
Hans Verkuil68cd4e92015-03-13 05:36:08 -03001065 case V4L2_PIX_FMT_BGR666:
1066 buf[0][offset] = (b_v << 2) | (g_u >> 4);
1067 buf[0][offset + 1] = (g_u << 4) | (r_y >> 2);
1068 buf[0][offset + 2] = r_y << 6;
1069 buf[0][offset + 3] = 0;
1070 break;
Hans Verkuil63881df2014-08-25 08:02:14 -03001071 case V4L2_PIX_FMT_RGB32:
1072 case V4L2_PIX_FMT_XRGB32:
1073 alpha = 0;
1074 /* fall through */
Hans Verkuil628821c2015-03-13 06:35:40 -03001075 case V4L2_PIX_FMT_YUV32:
Hans Verkuil63881df2014-08-25 08:02:14 -03001076 case V4L2_PIX_FMT_ARGB32:
1077 buf[0][offset] = alpha;
1078 buf[0][offset + 1] = r_y;
1079 buf[0][offset + 2] = g_u;
1080 buf[0][offset + 3] = b_v;
1081 break;
1082 case V4L2_PIX_FMT_BGR32:
1083 case V4L2_PIX_FMT_XBGR32:
1084 alpha = 0;
1085 /* fall through */
1086 case V4L2_PIX_FMT_ABGR32:
1087 buf[0][offset] = b_v;
1088 buf[0][offset + 1] = g_u;
1089 buf[0][offset + 2] = r_y;
1090 buf[0][offset + 3] = alpha;
1091 break;
Hans Verkuil02aa7692015-03-14 08:01:50 -03001092 case V4L2_PIX_FMT_SBGGR8:
1093 buf[0][offset] = odd ? g_u : b_v;
1094 buf[1][offset] = odd ? r_y : g_u;
1095 break;
1096 case V4L2_PIX_FMT_SGBRG8:
1097 buf[0][offset] = odd ? b_v : g_u;
1098 buf[1][offset] = odd ? g_u : r_y;
1099 break;
1100 case V4L2_PIX_FMT_SGRBG8:
1101 buf[0][offset] = odd ? r_y : g_u;
1102 buf[1][offset] = odd ? g_u : b_v;
1103 break;
1104 case V4L2_PIX_FMT_SRGGB8:
1105 buf[0][offset] = odd ? g_u : r_y;
1106 buf[1][offset] = odd ? b_v : g_u;
1107 break;
1108 }
1109}
1110
1111unsigned tpg_g_interleaved_plane(const struct tpg_data *tpg, unsigned buf_line)
1112{
1113 switch (tpg->fourcc) {
1114 case V4L2_PIX_FMT_SBGGR8:
1115 case V4L2_PIX_FMT_SGBRG8:
1116 case V4L2_PIX_FMT_SGRBG8:
1117 case V4L2_PIX_FMT_SRGGB8:
1118 return buf_line & 1;
1119 default:
1120 return 0;
Hans Verkuil63881df2014-08-25 08:02:14 -03001121 }
1122}
1123
1124/* Return how many pattern lines are used by the current pattern. */
Hans Verkuil1a05d312015-03-07 12:49:57 -03001125static unsigned tpg_get_pat_lines(const struct tpg_data *tpg)
Hans Verkuil63881df2014-08-25 08:02:14 -03001126{
1127 switch (tpg->pattern) {
1128 case TPG_PAT_CHECKERS_16X16:
Hans Verkuil1a05d312015-03-07 12:49:57 -03001129 case TPG_PAT_CHECKERS_2X2:
Hans Verkuil63881df2014-08-25 08:02:14 -03001130 case TPG_PAT_CHECKERS_1X1:
Hans Verkuil1a05d312015-03-07 12:49:57 -03001131 case TPG_PAT_COLOR_CHECKERS_2X2:
1132 case TPG_PAT_COLOR_CHECKERS_1X1:
Hans Verkuil63881df2014-08-25 08:02:14 -03001133 case TPG_PAT_ALTERNATING_HLINES:
1134 case TPG_PAT_CROSS_1_PIXEL:
1135 case TPG_PAT_CROSS_2_PIXELS:
1136 case TPG_PAT_CROSS_10_PIXELS:
1137 return 2;
1138 case TPG_PAT_100_COLORSQUARES:
1139 case TPG_PAT_100_HCOLORBAR:
1140 return 8;
1141 default:
1142 return 1;
1143 }
1144}
1145
1146/* Which pattern line should be used for the given frame line. */
Hans Verkuil1a05d312015-03-07 12:49:57 -03001147static unsigned tpg_get_pat_line(const struct tpg_data *tpg, unsigned line)
Hans Verkuil63881df2014-08-25 08:02:14 -03001148{
1149 switch (tpg->pattern) {
1150 case TPG_PAT_CHECKERS_16X16:
1151 return (line >> 4) & 1;
1152 case TPG_PAT_CHECKERS_1X1:
Hans Verkuil1a05d312015-03-07 12:49:57 -03001153 case TPG_PAT_COLOR_CHECKERS_1X1:
Hans Verkuil63881df2014-08-25 08:02:14 -03001154 case TPG_PAT_ALTERNATING_HLINES:
1155 return line & 1;
Hans Verkuil1a05d312015-03-07 12:49:57 -03001156 case TPG_PAT_CHECKERS_2X2:
1157 case TPG_PAT_COLOR_CHECKERS_2X2:
1158 return (line & 2) >> 1;
Hans Verkuil63881df2014-08-25 08:02:14 -03001159 case TPG_PAT_100_COLORSQUARES:
1160 case TPG_PAT_100_HCOLORBAR:
1161 return (line * 8) / tpg->src_height;
1162 case TPG_PAT_CROSS_1_PIXEL:
1163 return line == tpg->src_height / 2;
1164 case TPG_PAT_CROSS_2_PIXELS:
1165 return (line + 1) / 2 == tpg->src_height / 4;
1166 case TPG_PAT_CROSS_10_PIXELS:
1167 return (line + 10) / 20 == tpg->src_height / 40;
1168 default:
1169 return 0;
1170 }
1171}
1172
1173/*
1174 * Which color should be used for the given pattern line and X coordinate.
1175 * Note: x is in the range 0 to 2 * tpg->src_width.
1176 */
Hans Verkuil1a05d312015-03-07 12:49:57 -03001177static enum tpg_color tpg_get_color(const struct tpg_data *tpg,
1178 unsigned pat_line, unsigned x)
Hans Verkuil63881df2014-08-25 08:02:14 -03001179{
1180 /* Maximum number of bars are TPG_COLOR_MAX - otherwise, the input print code
1181 should be modified */
1182 static const enum tpg_color bars[3][8] = {
1183 /* Standard ITU-R 75% color bar sequence */
1184 { TPG_COLOR_CSC_WHITE, TPG_COLOR_75_YELLOW,
1185 TPG_COLOR_75_CYAN, TPG_COLOR_75_GREEN,
1186 TPG_COLOR_75_MAGENTA, TPG_COLOR_75_RED,
1187 TPG_COLOR_75_BLUE, TPG_COLOR_100_BLACK, },
1188 /* Standard ITU-R 100% color bar sequence */
1189 { TPG_COLOR_100_WHITE, TPG_COLOR_100_YELLOW,
1190 TPG_COLOR_100_CYAN, TPG_COLOR_100_GREEN,
1191 TPG_COLOR_100_MAGENTA, TPG_COLOR_100_RED,
1192 TPG_COLOR_100_BLUE, TPG_COLOR_100_BLACK, },
1193 /* Color bar sequence suitable to test CSC */
1194 { TPG_COLOR_CSC_WHITE, TPG_COLOR_CSC_YELLOW,
1195 TPG_COLOR_CSC_CYAN, TPG_COLOR_CSC_GREEN,
1196 TPG_COLOR_CSC_MAGENTA, TPG_COLOR_CSC_RED,
1197 TPG_COLOR_CSC_BLUE, TPG_COLOR_CSC_BLACK, },
1198 };
1199
1200 switch (tpg->pattern) {
1201 case TPG_PAT_75_COLORBAR:
1202 case TPG_PAT_100_COLORBAR:
1203 case TPG_PAT_CSC_COLORBAR:
1204 return bars[tpg->pattern][((x * 8) / tpg->src_width) % 8];
1205 case TPG_PAT_100_COLORSQUARES:
1206 return bars[1][(pat_line + (x * 8) / tpg->src_width) % 8];
1207 case TPG_PAT_100_HCOLORBAR:
1208 return bars[1][pat_line];
1209 case TPG_PAT_BLACK:
1210 return TPG_COLOR_100_BLACK;
1211 case TPG_PAT_WHITE:
1212 return TPG_COLOR_100_WHITE;
1213 case TPG_PAT_RED:
1214 return TPG_COLOR_100_RED;
1215 case TPG_PAT_GREEN:
1216 return TPG_COLOR_100_GREEN;
1217 case TPG_PAT_BLUE:
1218 return TPG_COLOR_100_BLUE;
1219 case TPG_PAT_CHECKERS_16X16:
1220 return (((x >> 4) & 1) ^ (pat_line & 1)) ?
1221 TPG_COLOR_100_BLACK : TPG_COLOR_100_WHITE;
1222 case TPG_PAT_CHECKERS_1X1:
1223 return ((x & 1) ^ (pat_line & 1)) ?
1224 TPG_COLOR_100_WHITE : TPG_COLOR_100_BLACK;
Hans Verkuil1a05d312015-03-07 12:49:57 -03001225 case TPG_PAT_COLOR_CHECKERS_1X1:
1226 return ((x & 1) ^ (pat_line & 1)) ?
1227 TPG_COLOR_100_RED : TPG_COLOR_100_BLUE;
1228 case TPG_PAT_CHECKERS_2X2:
1229 return (((x >> 1) & 1) ^ (pat_line & 1)) ?
1230 TPG_COLOR_100_WHITE : TPG_COLOR_100_BLACK;
1231 case TPG_PAT_COLOR_CHECKERS_2X2:
1232 return (((x >> 1) & 1) ^ (pat_line & 1)) ?
1233 TPG_COLOR_100_RED : TPG_COLOR_100_BLUE;
Hans Verkuil63881df2014-08-25 08:02:14 -03001234 case TPG_PAT_ALTERNATING_HLINES:
1235 return pat_line ? TPG_COLOR_100_WHITE : TPG_COLOR_100_BLACK;
1236 case TPG_PAT_ALTERNATING_VLINES:
1237 return (x & 1) ? TPG_COLOR_100_WHITE : TPG_COLOR_100_BLACK;
1238 case TPG_PAT_CROSS_1_PIXEL:
1239 if (pat_line || (x % tpg->src_width) == tpg->src_width / 2)
1240 return TPG_COLOR_100_BLACK;
1241 return TPG_COLOR_100_WHITE;
1242 case TPG_PAT_CROSS_2_PIXELS:
1243 if (pat_line || ((x % tpg->src_width) + 1) / 2 == tpg->src_width / 4)
1244 return TPG_COLOR_100_BLACK;
1245 return TPG_COLOR_100_WHITE;
1246 case TPG_PAT_CROSS_10_PIXELS:
1247 if (pat_line || ((x % tpg->src_width) + 10) / 20 == tpg->src_width / 40)
1248 return TPG_COLOR_100_BLACK;
1249 return TPG_COLOR_100_WHITE;
1250 case TPG_PAT_GRAY_RAMP:
1251 return TPG_COLOR_RAMP + ((x % tpg->src_width) * 256) / tpg->src_width;
1252 default:
1253 return TPG_COLOR_100_RED;
1254 }
1255}
1256
1257/*
1258 * Given the pixel aspect ratio and video aspect ratio calculate the
1259 * coordinates of a centered square and the coordinates of the border of
1260 * the active video area. The coordinates are relative to the source
1261 * frame rectangle.
1262 */
1263static void tpg_calculate_square_border(struct tpg_data *tpg)
1264{
1265 unsigned w = tpg->src_width;
1266 unsigned h = tpg->src_height;
1267 unsigned sq_w, sq_h;
1268
1269 sq_w = (w * 2 / 5) & ~1;
1270 if (((w - sq_w) / 2) & 1)
1271 sq_w += 2;
1272 sq_h = sq_w;
1273 tpg->square.width = sq_w;
1274 if (tpg->vid_aspect == TPG_VIDEO_ASPECT_16X9_ANAMORPHIC) {
1275 unsigned ana_sq_w = (sq_w / 4) * 3;
1276
1277 if (((w - ana_sq_w) / 2) & 1)
1278 ana_sq_w += 2;
1279 tpg->square.width = ana_sq_w;
1280 }
1281 tpg->square.left = (w - tpg->square.width) / 2;
1282 if (tpg->pix_aspect == TPG_PIXEL_ASPECT_NTSC)
1283 sq_h = sq_w * 10 / 11;
1284 else if (tpg->pix_aspect == TPG_PIXEL_ASPECT_PAL)
1285 sq_h = sq_w * 59 / 54;
1286 tpg->square.height = sq_h;
1287 tpg->square.top = (h - sq_h) / 2;
1288 tpg->border.left = 0;
1289 tpg->border.width = w;
1290 tpg->border.top = 0;
1291 tpg->border.height = h;
1292 switch (tpg->vid_aspect) {
1293 case TPG_VIDEO_ASPECT_4X3:
1294 if (tpg->pix_aspect)
1295 return;
1296 if (3 * w >= 4 * h) {
1297 tpg->border.width = ((4 * h) / 3) & ~1;
1298 if (((w - tpg->border.width) / 2) & ~1)
1299 tpg->border.width -= 2;
1300 tpg->border.left = (w - tpg->border.width) / 2;
1301 break;
1302 }
1303 tpg->border.height = ((3 * w) / 4) & ~1;
1304 tpg->border.top = (h - tpg->border.height) / 2;
1305 break;
1306 case TPG_VIDEO_ASPECT_14X9_CENTRE:
1307 if (tpg->pix_aspect) {
1308 tpg->border.height = tpg->pix_aspect == TPG_PIXEL_ASPECT_NTSC ? 420 : 506;
1309 tpg->border.top = (h - tpg->border.height) / 2;
1310 break;
1311 }
1312 if (9 * w >= 14 * h) {
1313 tpg->border.width = ((14 * h) / 9) & ~1;
1314 if (((w - tpg->border.width) / 2) & ~1)
1315 tpg->border.width -= 2;
1316 tpg->border.left = (w - tpg->border.width) / 2;
1317 break;
1318 }
1319 tpg->border.height = ((9 * w) / 14) & ~1;
1320 tpg->border.top = (h - tpg->border.height) / 2;
1321 break;
1322 case TPG_VIDEO_ASPECT_16X9_CENTRE:
1323 if (tpg->pix_aspect) {
1324 tpg->border.height = tpg->pix_aspect == TPG_PIXEL_ASPECT_NTSC ? 368 : 442;
1325 tpg->border.top = (h - tpg->border.height) / 2;
1326 break;
1327 }
1328 if (9 * w >= 16 * h) {
1329 tpg->border.width = ((16 * h) / 9) & ~1;
1330 if (((w - tpg->border.width) / 2) & ~1)
1331 tpg->border.width -= 2;
1332 tpg->border.left = (w - tpg->border.width) / 2;
1333 break;
1334 }
1335 tpg->border.height = ((9 * w) / 16) & ~1;
1336 tpg->border.top = (h - tpg->border.height) / 2;
1337 break;
1338 default:
1339 break;
1340 }
1341}
1342
1343static void tpg_precalculate_line(struct tpg_data *tpg)
1344{
1345 enum tpg_color contrast;
Hans Verkuil9991def2015-03-08 05:53:10 -03001346 u8 pix[TPG_MAX_PLANES][8];
Hans Verkuil63881df2014-08-25 08:02:14 -03001347 unsigned pat;
1348 unsigned p;
1349 unsigned x;
1350
1351 switch (tpg->pattern) {
1352 case TPG_PAT_GREEN:
1353 contrast = TPG_COLOR_100_RED;
1354 break;
1355 case TPG_PAT_CSC_COLORBAR:
1356 contrast = TPG_COLOR_CSC_GREEN;
1357 break;
1358 default:
1359 contrast = TPG_COLOR_100_GREEN;
1360 break;
1361 }
1362
1363 for (pat = 0; pat < tpg_get_pat_lines(tpg); pat++) {
1364 /* Coarse scaling with Bresenham */
1365 unsigned int_part = tpg->src_width / tpg->scaled_width;
1366 unsigned fract_part = tpg->src_width % tpg->scaled_width;
1367 unsigned src_x = 0;
1368 unsigned error = 0;
1369
1370 for (x = 0; x < tpg->scaled_width * 2; x += 2) {
1371 unsigned real_x = src_x;
1372 enum tpg_color color1, color2;
Hans Verkuil63881df2014-08-25 08:02:14 -03001373
1374 real_x = tpg->hflip ? tpg->src_width * 2 - real_x - 2 : real_x;
1375 color1 = tpg_get_color(tpg, pat, real_x);
1376
1377 src_x += int_part;
1378 error += fract_part;
1379 if (error >= tpg->scaled_width) {
1380 error -= tpg->scaled_width;
1381 src_x++;
1382 }
1383
1384 real_x = src_x;
1385 real_x = tpg->hflip ? tpg->src_width * 2 - real_x - 2 : real_x;
1386 color2 = tpg_get_color(tpg, pat, real_x);
1387
1388 src_x += int_part;
1389 error += fract_part;
1390 if (error >= tpg->scaled_width) {
1391 error -= tpg->scaled_width;
1392 src_x++;
1393 }
1394
1395 gen_twopix(tpg, pix, tpg->hflip ? color2 : color1, 0);
1396 gen_twopix(tpg, pix, tpg->hflip ? color1 : color2, 1);
1397 for (p = 0; p < tpg->planes; p++) {
1398 unsigned twopixsize = tpg->twopixelsize[p];
Hans Verkuil5d7c5392015-03-07 14:06:43 -03001399 unsigned hdiv = tpg->hdownsampling[p];
Hans Verkuil9991def2015-03-08 05:53:10 -03001400 u8 *pos = tpg->lines[pat][p] + tpg_hdiv(tpg, p, x);
Hans Verkuil63881df2014-08-25 08:02:14 -03001401
Hans Verkuil5d7c5392015-03-07 14:06:43 -03001402 memcpy(pos, pix[p], twopixsize / hdiv);
Hans Verkuil63881df2014-08-25 08:02:14 -03001403 }
1404 }
1405 }
Hans Verkuil5d7c5392015-03-07 14:06:43 -03001406
1407 if (tpg->vdownsampling[tpg->planes - 1] > 1) {
1408 unsigned pat_lines = tpg_get_pat_lines(tpg);
1409
1410 for (pat = 0; pat < pat_lines; pat++) {
1411 unsigned next_pat = (pat + 1) % pat_lines;
1412
1413 for (p = 1; p < tpg->planes; p++) {
Hans Verkuil9991def2015-03-08 05:53:10 -03001414 unsigned w = tpg_hdiv(tpg, p, tpg->scaled_width * 2);
1415 u8 *pos1 = tpg->lines[pat][p];
1416 u8 *pos2 = tpg->lines[next_pat][p];
1417 u8 *dest = tpg->downsampled_lines[pat][p];
Hans Verkuil5d7c5392015-03-07 14:06:43 -03001418
Hans Verkuil9991def2015-03-08 05:53:10 -03001419 for (x = 0; x < w; x++, pos1++, pos2++, dest++)
1420 *dest = ((u16)*pos1 + (u16)*pos2) / 2;
Hans Verkuil5d7c5392015-03-07 14:06:43 -03001421 }
1422 }
1423 }
1424
Hans Verkuil9991def2015-03-08 05:53:10 -03001425 gen_twopix(tpg, pix, contrast, 0);
1426 gen_twopix(tpg, pix, contrast, 1);
1427 for (p = 0; p < tpg->planes; p++) {
1428 unsigned twopixsize = tpg->twopixelsize[p];
1429 u8 *pos = tpg->contrast_line[p];
Hans Verkuil63881df2014-08-25 08:02:14 -03001430
Hans Verkuil9991def2015-03-08 05:53:10 -03001431 for (x = 0; x < tpg->scaled_width; x += 2, pos += twopixsize)
Hans Verkuil63881df2014-08-25 08:02:14 -03001432 memcpy(pos, pix[p], twopixsize);
Hans Verkuil63881df2014-08-25 08:02:14 -03001433 }
Hans Verkuil63881df2014-08-25 08:02:14 -03001434
Hans Verkuil9991def2015-03-08 05:53:10 -03001435 gen_twopix(tpg, pix, TPG_COLOR_100_BLACK, 0);
1436 gen_twopix(tpg, pix, TPG_COLOR_100_BLACK, 1);
1437 for (p = 0; p < tpg->planes; p++) {
1438 unsigned twopixsize = tpg->twopixelsize[p];
1439 u8 *pos = tpg->black_line[p];
Hans Verkuil63881df2014-08-25 08:02:14 -03001440
Hans Verkuil9991def2015-03-08 05:53:10 -03001441 for (x = 0; x < tpg->scaled_width; x += 2, pos += twopixsize)
Hans Verkuil63881df2014-08-25 08:02:14 -03001442 memcpy(pos, pix[p], twopixsize);
Hans Verkuil63881df2014-08-25 08:02:14 -03001443 }
Hans Verkuil9991def2015-03-08 05:53:10 -03001444
Hans Verkuil63881df2014-08-25 08:02:14 -03001445 for (x = 0; x < tpg->scaled_width * 2; x += 2) {
Hans Verkuil63881df2014-08-25 08:02:14 -03001446 gen_twopix(tpg, pix, TPG_COLOR_RANDOM, 0);
1447 gen_twopix(tpg, pix, TPG_COLOR_RANDOM, 1);
1448 for (p = 0; p < tpg->planes; p++) {
1449 unsigned twopixsize = tpg->twopixelsize[p];
1450 u8 *pos = tpg->random_line[p] + x * twopixsize / 2;
1451
1452 memcpy(pos, pix[p], twopixsize);
1453 }
1454 }
Hans Verkuil9991def2015-03-08 05:53:10 -03001455
Hans Verkuil63881df2014-08-25 08:02:14 -03001456 gen_twopix(tpg, tpg->textbg, TPG_COLOR_TEXTBG, 0);
1457 gen_twopix(tpg, tpg->textbg, TPG_COLOR_TEXTBG, 1);
1458 gen_twopix(tpg, tpg->textfg, TPG_COLOR_TEXTFG, 0);
1459 gen_twopix(tpg, tpg->textfg, TPG_COLOR_TEXTFG, 1);
1460}
1461
1462/* need this to do rgb24 rendering */
1463typedef struct { u16 __; u8 _; } __packed x24;
1464
Hans Verkuildfff0482015-03-09 11:04:02 -03001465void tpg_gen_text(const struct tpg_data *tpg, u8 *basep[TPG_MAX_PLANES][2],
1466 int y, int x, char *text)
Hans Verkuil63881df2014-08-25 08:02:14 -03001467{
1468 int line;
1469 unsigned step = V4L2_FIELD_HAS_T_OR_B(tpg->field) ? 2 : 1;
1470 unsigned div = step;
1471 unsigned first = 0;
1472 unsigned len = strlen(text);
1473 unsigned p;
1474
1475 if (font8x16 == NULL || basep == NULL)
1476 return;
1477
1478 /* Checks if it is possible to show string */
1479 if (y + 16 >= tpg->compose.height || x + 8 >= tpg->compose.width)
1480 return;
1481
1482 if (len > (tpg->compose.width - x) / 8)
1483 len = (tpg->compose.width - x) / 8;
1484 if (tpg->vflip)
1485 y = tpg->compose.height - y - 16;
1486 if (tpg->hflip)
1487 x = tpg->compose.width - x - 8;
1488 y += tpg->compose.top;
1489 x += tpg->compose.left;
1490 if (tpg->field == V4L2_FIELD_BOTTOM)
1491 first = 1;
1492 else if (tpg->field == V4L2_FIELD_SEQ_TB || tpg->field == V4L2_FIELD_SEQ_BT)
1493 div = 2;
1494
1495 for (p = 0; p < tpg->planes; p++) {
Hans Verkuil3e14e7a82015-03-07 14:23:16 -03001496 unsigned vdiv = tpg->vdownsampling[p];
1497 unsigned hdiv = tpg->hdownsampling[p];
1498
1499 /* Print text */
Hans Verkuil63881df2014-08-25 08:02:14 -03001500#define PRINTSTR(PIXTYPE) do { \
1501 PIXTYPE fg; \
1502 PIXTYPE bg; \
1503 memcpy(&fg, tpg->textfg[p], sizeof(PIXTYPE)); \
1504 memcpy(&bg, tpg->textbg[p], sizeof(PIXTYPE)); \
1505 \
Hans Verkuil3e14e7a82015-03-07 14:23:16 -03001506 for (line = first; line < 16; line += vdiv * step) { \
Hans Verkuil63881df2014-08-25 08:02:14 -03001507 int l = tpg->vflip ? 15 - line : line; \
Hans Verkuil3e14e7a82015-03-07 14:23:16 -03001508 PIXTYPE *pos = (PIXTYPE *)(basep[p][(line / vdiv) & 1] + \
1509 ((y * step + l) / (vdiv * div)) * tpg->bytesperline[p] + \
1510 (x / hdiv) * sizeof(PIXTYPE)); \
Hans Verkuil63881df2014-08-25 08:02:14 -03001511 unsigned s; \
1512 \
1513 for (s = 0; s < len; s++) { \
1514 u8 chr = font8x16[text[s] * 16 + line]; \
1515 \
Hans Verkuil3e14e7a82015-03-07 14:23:16 -03001516 if (hdiv == 2 && tpg->hflip) { \
1517 pos[3] = (chr & (0x01 << 6) ? fg : bg); \
1518 pos[2] = (chr & (0x01 << 4) ? fg : bg); \
1519 pos[1] = (chr & (0x01 << 2) ? fg : bg); \
1520 pos[0] = (chr & (0x01 << 0) ? fg : bg); \
1521 } else if (hdiv == 2) { \
1522 pos[0] = (chr & (0x01 << 7) ? fg : bg); \
1523 pos[1] = (chr & (0x01 << 5) ? fg : bg); \
1524 pos[2] = (chr & (0x01 << 3) ? fg : bg); \
1525 pos[3] = (chr & (0x01 << 1) ? fg : bg); \
1526 } else if (tpg->hflip) { \
Hans Verkuil63881df2014-08-25 08:02:14 -03001527 pos[7] = (chr & (0x01 << 7) ? fg : bg); \
1528 pos[6] = (chr & (0x01 << 6) ? fg : bg); \
1529 pos[5] = (chr & (0x01 << 5) ? fg : bg); \
1530 pos[4] = (chr & (0x01 << 4) ? fg : bg); \
1531 pos[3] = (chr & (0x01 << 3) ? fg : bg); \
1532 pos[2] = (chr & (0x01 << 2) ? fg : bg); \
1533 pos[1] = (chr & (0x01 << 1) ? fg : bg); \
1534 pos[0] = (chr & (0x01 << 0) ? fg : bg); \
1535 } else { \
1536 pos[0] = (chr & (0x01 << 7) ? fg : bg); \
1537 pos[1] = (chr & (0x01 << 6) ? fg : bg); \
1538 pos[2] = (chr & (0x01 << 5) ? fg : bg); \
1539 pos[3] = (chr & (0x01 << 4) ? fg : bg); \
1540 pos[4] = (chr & (0x01 << 3) ? fg : bg); \
1541 pos[5] = (chr & (0x01 << 2) ? fg : bg); \
1542 pos[6] = (chr & (0x01 << 1) ? fg : bg); \
1543 pos[7] = (chr & (0x01 << 0) ? fg : bg); \
1544 } \
1545 \
Hans Verkuil3e14e7a82015-03-07 14:23:16 -03001546 pos += (tpg->hflip ? -8 : 8) / hdiv; \
Hans Verkuil63881df2014-08-25 08:02:14 -03001547 } \
1548 } \
1549} while (0)
1550
1551 switch (tpg->twopixelsize[p]) {
1552 case 2:
1553 PRINTSTR(u8); break;
1554 case 4:
1555 PRINTSTR(u16); break;
1556 case 6:
1557 PRINTSTR(x24); break;
1558 case 8:
1559 PRINTSTR(u32); break;
1560 }
1561 }
1562}
1563
1564void tpg_update_mv_step(struct tpg_data *tpg)
1565{
1566 int factor = tpg->mv_hor_mode > TPG_MOVE_NONE ? -1 : 1;
1567
1568 if (tpg->hflip)
1569 factor = -factor;
1570 switch (tpg->mv_hor_mode) {
1571 case TPG_MOVE_NEG_FAST:
1572 case TPG_MOVE_POS_FAST:
1573 tpg->mv_hor_step = ((tpg->src_width + 319) / 320) * 4;
1574 break;
1575 case TPG_MOVE_NEG:
1576 case TPG_MOVE_POS:
1577 tpg->mv_hor_step = ((tpg->src_width + 639) / 640) * 4;
1578 break;
1579 case TPG_MOVE_NEG_SLOW:
1580 case TPG_MOVE_POS_SLOW:
1581 tpg->mv_hor_step = 2;
1582 break;
1583 case TPG_MOVE_NONE:
1584 tpg->mv_hor_step = 0;
1585 break;
1586 }
1587 if (factor < 0)
1588 tpg->mv_hor_step = tpg->src_width - tpg->mv_hor_step;
1589
1590 factor = tpg->mv_vert_mode > TPG_MOVE_NONE ? -1 : 1;
1591 switch (tpg->mv_vert_mode) {
1592 case TPG_MOVE_NEG_FAST:
1593 case TPG_MOVE_POS_FAST:
1594 tpg->mv_vert_step = ((tpg->src_width + 319) / 320) * 4;
1595 break;
1596 case TPG_MOVE_NEG:
1597 case TPG_MOVE_POS:
1598 tpg->mv_vert_step = ((tpg->src_width + 639) / 640) * 4;
1599 break;
1600 case TPG_MOVE_NEG_SLOW:
1601 case TPG_MOVE_POS_SLOW:
1602 tpg->mv_vert_step = 1;
1603 break;
1604 case TPG_MOVE_NONE:
1605 tpg->mv_vert_step = 0;
1606 break;
1607 }
1608 if (factor < 0)
1609 tpg->mv_vert_step = tpg->src_height - tpg->mv_vert_step;
1610}
1611
1612/* Map the line number relative to the crop rectangle to a frame line number */
Hans Verkuildfff0482015-03-09 11:04:02 -03001613static unsigned tpg_calc_frameline(const struct tpg_data *tpg, unsigned src_y,
Hans Verkuil63881df2014-08-25 08:02:14 -03001614 unsigned field)
1615{
1616 switch (field) {
1617 case V4L2_FIELD_TOP:
1618 return tpg->crop.top + src_y * 2;
1619 case V4L2_FIELD_BOTTOM:
1620 return tpg->crop.top + src_y * 2 + 1;
1621 default:
1622 return src_y + tpg->crop.top;
1623 }
1624}
1625
1626/*
1627 * Map the line number relative to the compose rectangle to a destination
1628 * buffer line number.
1629 */
Hans Verkuildfff0482015-03-09 11:04:02 -03001630static unsigned tpg_calc_buffer_line(const struct tpg_data *tpg, unsigned y,
Hans Verkuil63881df2014-08-25 08:02:14 -03001631 unsigned field)
1632{
1633 y += tpg->compose.top;
1634 switch (field) {
1635 case V4L2_FIELD_SEQ_TB:
1636 if (y & 1)
1637 return tpg->buf_height / 2 + y / 2;
1638 return y / 2;
1639 case V4L2_FIELD_SEQ_BT:
1640 if (y & 1)
1641 return y / 2;
1642 return tpg->buf_height / 2 + y / 2;
1643 default:
1644 return y;
1645 }
1646}
1647
1648static void tpg_recalc(struct tpg_data *tpg)
1649{
1650 if (tpg->recalc_colors) {
1651 tpg->recalc_colors = false;
1652 tpg->recalc_lines = true;
Hans Verkuil481b97a2014-11-17 10:14:32 -03001653 tpg->real_ycbcr_enc = tpg->ycbcr_enc;
1654 tpg->real_quantization = tpg->quantization;
1655 if (tpg->ycbcr_enc == V4L2_YCBCR_ENC_DEFAULT) {
1656 switch (tpg->colorspace) {
1657 case V4L2_COLORSPACE_REC709:
1658 tpg->real_ycbcr_enc = V4L2_YCBCR_ENC_709;
1659 break;
1660 case V4L2_COLORSPACE_SRGB:
1661 tpg->real_ycbcr_enc = V4L2_YCBCR_ENC_SYCC;
1662 break;
1663 case V4L2_COLORSPACE_BT2020:
1664 tpg->real_ycbcr_enc = V4L2_YCBCR_ENC_BT2020;
1665 break;
1666 case V4L2_COLORSPACE_SMPTE240M:
1667 tpg->real_ycbcr_enc = V4L2_YCBCR_ENC_SMPTE240M;
1668 break;
1669 case V4L2_COLORSPACE_SMPTE170M:
1670 case V4L2_COLORSPACE_470_SYSTEM_M:
1671 case V4L2_COLORSPACE_470_SYSTEM_BG:
1672 case V4L2_COLORSPACE_ADOBERGB:
1673 default:
1674 tpg->real_ycbcr_enc = V4L2_YCBCR_ENC_601;
1675 break;
1676 }
1677 }
1678 if (tpg->quantization == V4L2_QUANTIZATION_DEFAULT) {
1679 tpg->real_quantization = V4L2_QUANTIZATION_FULL_RANGE;
1680 if (tpg->is_yuv) {
1681 switch (tpg->real_ycbcr_enc) {
1682 case V4L2_YCBCR_ENC_SYCC:
1683 case V4L2_YCBCR_ENC_XV601:
1684 case V4L2_YCBCR_ENC_XV709:
1685 break;
1686 default:
1687 tpg->real_quantization =
1688 V4L2_QUANTIZATION_LIM_RANGE;
1689 break;
1690 }
Hans Verkuilc0b50d92015-03-08 04:53:33 -03001691 } else if (tpg->colorspace == V4L2_COLORSPACE_BT2020) {
1692 /* R'G'B' BT.2020 is limited range */
1693 tpg->real_quantization =
1694 V4L2_QUANTIZATION_LIM_RANGE;
Hans Verkuil481b97a2014-11-17 10:14:32 -03001695 }
1696 }
Hans Verkuil63881df2014-08-25 08:02:14 -03001697 tpg_precalculate_colors(tpg);
1698 }
1699 if (tpg->recalc_square_border) {
1700 tpg->recalc_square_border = false;
1701 tpg_calculate_square_border(tpg);
1702 }
1703 if (tpg->recalc_lines) {
1704 tpg->recalc_lines = false;
1705 tpg_precalculate_line(tpg);
1706 }
1707}
1708
1709void tpg_calc_text_basep(struct tpg_data *tpg,
1710 u8 *basep[TPG_MAX_PLANES][2], unsigned p, u8 *vbuf)
1711{
1712 unsigned stride = tpg->bytesperline[p];
Hans Verkuil280abe42015-03-07 14:50:41 -03001713 unsigned h = tpg->buf_height;
Hans Verkuil63881df2014-08-25 08:02:14 -03001714
1715 tpg_recalc(tpg);
1716
1717 basep[p][0] = vbuf;
1718 basep[p][1] = vbuf;
Hans Verkuil280abe42015-03-07 14:50:41 -03001719 h /= tpg->vdownsampling[p];
Hans Verkuil63881df2014-08-25 08:02:14 -03001720 if (tpg->field == V4L2_FIELD_SEQ_TB)
Hans Verkuil280abe42015-03-07 14:50:41 -03001721 basep[p][1] += h * stride / 2;
Hans Verkuil63881df2014-08-25 08:02:14 -03001722 else if (tpg->field == V4L2_FIELD_SEQ_BT)
Hans Verkuil280abe42015-03-07 14:50:41 -03001723 basep[p][0] += h * stride / 2;
Hans Verkuil02aa7692015-03-14 08:01:50 -03001724 if (p == 0 && tpg->interleaved)
1725 tpg_calc_text_basep(tpg, basep, 1, vbuf);
Hans Verkuil280abe42015-03-07 14:50:41 -03001726}
1727
1728static int tpg_pattern_avg(const struct tpg_data *tpg,
1729 unsigned pat1, unsigned pat2)
1730{
1731 unsigned pat_lines = tpg_get_pat_lines(tpg);
1732
1733 if (pat1 == (pat2 + 1) % pat_lines)
1734 return pat2;
1735 if (pat2 == (pat1 + 1) % pat_lines)
1736 return pat1;
1737 return -1;
Hans Verkuil63881df2014-08-25 08:02:14 -03001738}
1739
Hans Verkuil84b76d72015-04-24 11:16:22 -03001740void tpg_log_status(struct tpg_data *tpg)
1741{
1742 pr_info("tpg source WxH: %ux%u (%s)\n",
1743 tpg->src_width, tpg->src_height,
1744 tpg->is_yuv ? "YCbCr" : "RGB");
1745 pr_info("tpg field: %u\n", tpg->field);
1746 pr_info("tpg crop: %ux%u@%dx%d\n", tpg->crop.width, tpg->crop.height,
1747 tpg->crop.left, tpg->crop.top);
1748 pr_info("tpg compose: %ux%u@%dx%d\n", tpg->compose.width, tpg->compose.height,
1749 tpg->compose.left, tpg->compose.top);
1750 pr_info("tpg colorspace: %d\n", tpg->colorspace);
1751 pr_info("tpg Y'CbCr encoding: %d/%d\n", tpg->ycbcr_enc, tpg->real_ycbcr_enc);
1752 pr_info("tpg quantization: %d/%d\n", tpg->quantization, tpg->real_quantization);
1753 pr_info("tpg RGB range: %d/%d\n", tpg->rgb_range, tpg->real_rgb_range);
1754}
1755
Hans Verkuile76036d2015-03-09 11:07:23 -03001756/*
1757 * This struct contains common parameters used by both the drawing of the
1758 * test pattern and the drawing of the extras (borders, square, etc.)
1759 */
1760struct tpg_draw_params {
1761 /* common data */
1762 bool is_tv;
1763 bool is_60hz;
1764 unsigned twopixsize;
1765 unsigned img_width;
1766 unsigned stride;
1767 unsigned hmax;
1768 unsigned frame_line;
1769 unsigned frame_line_next;
1770
1771 /* test pattern */
1772 unsigned mv_hor_old;
1773 unsigned mv_hor_new;
1774 unsigned mv_vert_old;
1775 unsigned mv_vert_new;
1776
1777 /* extras */
1778 unsigned wss_width;
1779 unsigned wss_random_offset;
1780 unsigned sav_eav_f;
1781 unsigned left_pillar_width;
1782 unsigned right_pillar_start;
1783};
1784
Hans Verkuilf0ce4fd2015-03-09 11:30:05 -03001785static void tpg_fill_params_pattern(const struct tpg_data *tpg, unsigned p,
1786 struct tpg_draw_params *params)
1787{
1788 params->mv_hor_old =
1789 tpg_hscale_div(tpg, p, tpg->mv_hor_count % tpg->src_width);
1790 params->mv_hor_new =
1791 tpg_hscale_div(tpg, p, (tpg->mv_hor_count + tpg->mv_hor_step) %
1792 tpg->src_width);
1793 params->mv_vert_old = tpg->mv_vert_count % tpg->src_height;
1794 params->mv_vert_new =
1795 (tpg->mv_vert_count + tpg->mv_vert_step) % tpg->src_height;
1796}
1797
Hans Verkuil07386b92015-03-09 11:39:19 -03001798static void tpg_fill_params_extras(const struct tpg_data *tpg,
1799 unsigned p,
1800 struct tpg_draw_params *params)
1801{
1802 unsigned left_pillar_width = 0;
1803 unsigned right_pillar_start = params->img_width;
1804
1805 params->wss_width = tpg->crop.left < tpg->src_width / 2 ?
1806 tpg->src_width / 2 - tpg->crop.left : 0;
1807 if (params->wss_width > tpg->crop.width)
1808 params->wss_width = tpg->crop.width;
1809 params->wss_width = tpg_hscale_div(tpg, p, params->wss_width);
1810 params->wss_random_offset =
1811 params->twopixsize * prandom_u32_max(tpg->src_width / 2);
1812
1813 if (tpg->crop.left < tpg->border.left) {
1814 left_pillar_width = tpg->border.left - tpg->crop.left;
1815 if (left_pillar_width > tpg->crop.width)
1816 left_pillar_width = tpg->crop.width;
1817 left_pillar_width = tpg_hscale_div(tpg, p, left_pillar_width);
1818 }
1819 params->left_pillar_width = left_pillar_width;
1820
1821 if (tpg->crop.left + tpg->crop.width >
1822 tpg->border.left + tpg->border.width) {
1823 right_pillar_start =
1824 tpg->border.left + tpg->border.width - tpg->crop.left;
1825 right_pillar_start =
1826 tpg_hscale_div(tpg, p, right_pillar_start);
1827 if (right_pillar_start > params->img_width)
1828 right_pillar_start = params->img_width;
1829 }
1830 params->right_pillar_start = right_pillar_start;
1831
1832 params->sav_eav_f = tpg->field ==
1833 (params->is_60hz ? V4L2_FIELD_TOP : V4L2_FIELD_BOTTOM);
1834}
1835
Hans Verkuilc6ff1c12015-03-09 11:47:48 -03001836static void tpg_fill_plane_extras(const struct tpg_data *tpg,
1837 const struct tpg_draw_params *params,
1838 unsigned p, unsigned h, u8 *vbuf)
1839{
1840 unsigned twopixsize = params->twopixsize;
1841 unsigned img_width = params->img_width;
1842 unsigned frame_line = params->frame_line;
1843 const struct v4l2_rect *sq = &tpg->square;
1844 const struct v4l2_rect *b = &tpg->border;
1845 const struct v4l2_rect *c = &tpg->crop;
1846
1847 if (params->is_tv && !params->is_60hz &&
1848 frame_line == 0 && params->wss_width) {
1849 /*
1850 * Replace the first half of the top line of a 50 Hz frame
1851 * with random data to simulate a WSS signal.
1852 */
1853 u8 *wss = tpg->random_line[p] + params->wss_random_offset;
1854
1855 memcpy(vbuf, wss, params->wss_width);
1856 }
1857
1858 if (tpg->show_border && frame_line >= b->top &&
1859 frame_line < b->top + b->height) {
1860 unsigned bottom = b->top + b->height - 1;
1861 unsigned left = params->left_pillar_width;
1862 unsigned right = params->right_pillar_start;
1863
1864 if (frame_line == b->top || frame_line == b->top + 1 ||
1865 frame_line == bottom || frame_line == bottom - 1) {
1866 memcpy(vbuf + left, tpg->contrast_line[p],
1867 right - left);
1868 } else {
1869 if (b->left >= c->left &&
1870 b->left < c->left + c->width)
1871 memcpy(vbuf + left,
1872 tpg->contrast_line[p], twopixsize);
1873 if (b->left + b->width > c->left &&
1874 b->left + b->width <= c->left + c->width)
1875 memcpy(vbuf + right - twopixsize,
1876 tpg->contrast_line[p], twopixsize);
1877 }
1878 }
1879 if (tpg->qual != TPG_QUAL_NOISE && frame_line >= b->top &&
1880 frame_line < b->top + b->height) {
1881 memcpy(vbuf, tpg->black_line[p], params->left_pillar_width);
1882 memcpy(vbuf + params->right_pillar_start, tpg->black_line[p],
1883 img_width - params->right_pillar_start);
1884 }
1885 if (tpg->show_square && frame_line >= sq->top &&
1886 frame_line < sq->top + sq->height &&
1887 sq->left < c->left + c->width &&
1888 sq->left + sq->width >= c->left) {
1889 unsigned left = sq->left;
1890 unsigned width = sq->width;
1891
1892 if (c->left > left) {
1893 width -= c->left - left;
1894 left = c->left;
1895 }
1896 if (c->left + c->width < left + width)
1897 width -= left + width - c->left - c->width;
1898 left -= c->left;
1899 left = tpg_hscale_div(tpg, p, left);
1900 width = tpg_hscale_div(tpg, p, width);
1901 memcpy(vbuf + left, tpg->contrast_line[p], width);
1902 }
1903 if (tpg->insert_sav) {
1904 unsigned offset = tpg_hdiv(tpg, p, tpg->compose.width / 3);
1905 u8 *p = vbuf + offset;
1906 unsigned vact = 0, hact = 0;
1907
1908 p[0] = 0xff;
1909 p[1] = 0;
1910 p[2] = 0;
1911 p[3] = 0x80 | (params->sav_eav_f << 6) |
1912 (vact << 5) | (hact << 4) |
1913 ((hact ^ vact) << 3) |
1914 ((hact ^ params->sav_eav_f) << 2) |
1915 ((params->sav_eav_f ^ vact) << 1) |
1916 (hact ^ vact ^ params->sav_eav_f);
1917 }
1918 if (tpg->insert_eav) {
1919 unsigned offset = tpg_hdiv(tpg, p, tpg->compose.width * 2 / 3);
1920 u8 *p = vbuf + offset;
1921 unsigned vact = 0, hact = 1;
1922
1923 p[0] = 0xff;
1924 p[1] = 0;
1925 p[2] = 0;
1926 p[3] = 0x80 | (params->sav_eav_f << 6) |
1927 (vact << 5) | (hact << 4) |
1928 ((hact ^ vact) << 3) |
1929 ((hact ^ params->sav_eav_f) << 2) |
1930 ((params->sav_eav_f ^ vact) << 1) |
1931 (hact ^ vact ^ params->sav_eav_f);
1932 }
1933}
1934
Hans Verkuilecb9e912015-03-09 11:52:43 -03001935static void tpg_fill_plane_pattern(const struct tpg_data *tpg,
1936 const struct tpg_draw_params *params,
1937 unsigned p, unsigned h, u8 *vbuf)
1938{
1939 unsigned twopixsize = params->twopixsize;
1940 unsigned img_width = params->img_width;
1941 unsigned mv_hor_old = params->mv_hor_old;
1942 unsigned mv_hor_new = params->mv_hor_new;
1943 unsigned mv_vert_old = params->mv_vert_old;
1944 unsigned mv_vert_new = params->mv_vert_new;
1945 unsigned frame_line = params->frame_line;
1946 unsigned frame_line_next = params->frame_line_next;
1947 unsigned line_offset = tpg_hscale_div(tpg, p, tpg->crop.left);
1948 bool even;
1949 bool fill_blank = false;
1950 unsigned pat_line_old;
1951 unsigned pat_line_new;
1952 u8 *linestart_older;
1953 u8 *linestart_newer;
1954 u8 *linestart_top;
1955 u8 *linestart_bottom;
1956
1957 even = !(frame_line & 1);
1958
1959 if (h >= params->hmax) {
1960 if (params->hmax == tpg->compose.height)
1961 return;
1962 if (!tpg->perc_fill_blank)
1963 return;
1964 fill_blank = true;
1965 }
1966
1967 if (tpg->vflip) {
1968 frame_line = tpg->src_height - frame_line - 1;
1969 frame_line_next = tpg->src_height - frame_line_next - 1;
1970 }
1971
1972 if (fill_blank) {
1973 linestart_older = tpg->contrast_line[p];
1974 linestart_newer = tpg->contrast_line[p];
1975 } else if (tpg->qual != TPG_QUAL_NOISE &&
1976 (frame_line < tpg->border.top ||
1977 frame_line >= tpg->border.top + tpg->border.height)) {
1978 linestart_older = tpg->black_line[p];
1979 linestart_newer = tpg->black_line[p];
1980 } else if (tpg->pattern == TPG_PAT_NOISE || tpg->qual == TPG_QUAL_NOISE) {
1981 linestart_older = tpg->random_line[p] +
1982 twopixsize * prandom_u32_max(tpg->src_width / 2);
1983 linestart_newer = tpg->random_line[p] +
1984 twopixsize * prandom_u32_max(tpg->src_width / 2);
1985 } else {
1986 unsigned frame_line_old =
1987 (frame_line + mv_vert_old) % tpg->src_height;
1988 unsigned frame_line_new =
1989 (frame_line + mv_vert_new) % tpg->src_height;
1990 unsigned pat_line_next_old;
1991 unsigned pat_line_next_new;
1992
1993 pat_line_old = tpg_get_pat_line(tpg, frame_line_old);
1994 pat_line_new = tpg_get_pat_line(tpg, frame_line_new);
1995 linestart_older = tpg->lines[pat_line_old][p] + mv_hor_old;
1996 linestart_newer = tpg->lines[pat_line_new][p] + mv_hor_new;
1997
1998 if (tpg->vdownsampling[p] > 1 && frame_line != frame_line_next) {
1999 int avg_pat;
2000
2001 /*
2002 * Now decide whether we need to use downsampled_lines[].
2003 * That's necessary if the two lines use different patterns.
2004 */
2005 pat_line_next_old = tpg_get_pat_line(tpg,
2006 (frame_line_next + mv_vert_old) % tpg->src_height);
2007 pat_line_next_new = tpg_get_pat_line(tpg,
2008 (frame_line_next + mv_vert_new) % tpg->src_height);
2009
2010 switch (tpg->field) {
2011 case V4L2_FIELD_INTERLACED:
2012 case V4L2_FIELD_INTERLACED_BT:
2013 case V4L2_FIELD_INTERLACED_TB:
2014 avg_pat = tpg_pattern_avg(tpg, pat_line_old, pat_line_new);
2015 if (avg_pat < 0)
2016 break;
2017 linestart_older = tpg->downsampled_lines[avg_pat][p] + mv_hor_old;
2018 linestart_newer = linestart_older;
2019 break;
2020 case V4L2_FIELD_NONE:
2021 case V4L2_FIELD_TOP:
2022 case V4L2_FIELD_BOTTOM:
2023 case V4L2_FIELD_SEQ_BT:
2024 case V4L2_FIELD_SEQ_TB:
2025 avg_pat = tpg_pattern_avg(tpg, pat_line_old, pat_line_next_old);
2026 if (avg_pat >= 0)
2027 linestart_older = tpg->downsampled_lines[avg_pat][p] +
2028 mv_hor_old;
2029 avg_pat = tpg_pattern_avg(tpg, pat_line_new, pat_line_next_new);
2030 if (avg_pat >= 0)
2031 linestart_newer = tpg->downsampled_lines[avg_pat][p] +
2032 mv_hor_new;
2033 break;
2034 }
2035 }
2036 linestart_older += line_offset;
2037 linestart_newer += line_offset;
2038 }
2039 if (tpg->field_alternate) {
2040 linestart_top = linestart_bottom = linestart_older;
2041 } else if (params->is_60hz) {
2042 linestart_top = linestart_newer;
2043 linestart_bottom = linestart_older;
2044 } else {
2045 linestart_top = linestart_older;
2046 linestart_bottom = linestart_newer;
2047 }
2048
2049 switch (tpg->field) {
2050 case V4L2_FIELD_INTERLACED:
2051 case V4L2_FIELD_INTERLACED_TB:
2052 case V4L2_FIELD_SEQ_TB:
2053 case V4L2_FIELD_SEQ_BT:
2054 if (even)
2055 memcpy(vbuf, linestart_top, img_width);
2056 else
2057 memcpy(vbuf, linestart_bottom, img_width);
2058 break;
2059 case V4L2_FIELD_INTERLACED_BT:
2060 if (even)
2061 memcpy(vbuf, linestart_bottom, img_width);
2062 else
2063 memcpy(vbuf, linestart_top, img_width);
2064 break;
2065 case V4L2_FIELD_TOP:
2066 memcpy(vbuf, linestart_top, img_width);
2067 break;
2068 case V4L2_FIELD_BOTTOM:
2069 memcpy(vbuf, linestart_bottom, img_width);
2070 break;
2071 case V4L2_FIELD_NONE:
2072 default:
2073 memcpy(vbuf, linestart_older, img_width);
2074 break;
2075 }
2076}
2077
2078void tpg_fill_plane_buffer(struct tpg_data *tpg, v4l2_std_id std,
2079 unsigned p, u8 *vbuf)
Hans Verkuil63881df2014-08-25 08:02:14 -03002080{
Hans Verkuil5e729392015-03-09 11:26:43 -03002081 struct tpg_draw_params params;
Hans Verkuil63881df2014-08-25 08:02:14 -03002082 unsigned factor = V4L2_FIELD_HAS_T_OR_B(tpg->field) ? 2 : 1;
Hans Verkuil63881df2014-08-25 08:02:14 -03002083
2084 /* Coarse scaling with Bresenham */
2085 unsigned int_part = (tpg->crop.height / factor) / tpg->compose.height;
2086 unsigned fract_part = (tpg->crop.height / factor) % tpg->compose.height;
2087 unsigned src_y = 0;
2088 unsigned error = 0;
Hans Verkuilecb9e912015-03-09 11:52:43 -03002089 unsigned h;
Hans Verkuil63881df2014-08-25 08:02:14 -03002090
2091 tpg_recalc(tpg);
2092
Hans Verkuil5e729392015-03-09 11:26:43 -03002093 params.is_tv = std;
2094 params.is_60hz = std & V4L2_STD_525_60;
2095 params.twopixsize = tpg->twopixelsize[p];
2096 params.img_width = tpg_hdiv(tpg, p, tpg->compose.width);
2097 params.stride = tpg->bytesperline[p];
2098 params.hmax = (tpg->compose.height * tpg->perc_fill) / 100;
2099
Hans Verkuilf0ce4fd2015-03-09 11:30:05 -03002100 tpg_fill_params_pattern(tpg, p, &params);
Hans Verkuil07386b92015-03-09 11:39:19 -03002101 tpg_fill_params_extras(tpg, p, &params);
2102
Hans Verkuil9991def2015-03-08 05:53:10 -03002103 vbuf += tpg_hdiv(tpg, p, tpg->compose.left);
Hans Verkuil63881df2014-08-25 08:02:14 -03002104
2105 for (h = 0; h < tpg->compose.height; h++) {
Hans Verkuil63881df2014-08-25 08:02:14 -03002106 unsigned buf_line;
Hans Verkuil63881df2014-08-25 08:02:14 -03002107
Hans Verkuilc6ff1c12015-03-09 11:47:48 -03002108 params.frame_line = tpg_calc_frameline(tpg, src_y, tpg->field);
2109 params.frame_line_next = params.frame_line;
Hans Verkuil63881df2014-08-25 08:02:14 -03002110 buf_line = tpg_calc_buffer_line(tpg, h, tpg->field);
2111 src_y += int_part;
2112 error += fract_part;
2113 if (error >= tpg->compose.height) {
2114 error -= tpg->compose.height;
2115 src_y++;
2116 }
2117
Hans Verkuil02aa7692015-03-14 08:01:50 -03002118 /*
2119 * For line-interleaved formats determine the 'plane'
2120 * based on the buffer line.
2121 */
2122 if (tpg_g_interleaved(tpg))
2123 p = tpg_g_interleaved_plane(tpg, buf_line);
2124
Hans Verkuilecb9e912015-03-09 11:52:43 -03002125 if (tpg->vdownsampling[p] > 1) {
Hans Verkuil280abe42015-03-07 14:50:41 -03002126 /*
2127 * When doing vertical downsampling the field setting
2128 * matters: for SEQ_BT/TB we downsample each field
2129 * separately (i.e. lines 0+2 are combined, as are
2130 * lines 1+3), for the other field settings we combine
2131 * odd and even lines. Doing that for SEQ_BT/TB would
2132 * be really weird.
2133 */
2134 if (tpg->field == V4L2_FIELD_SEQ_BT ||
2135 tpg->field == V4L2_FIELD_SEQ_TB) {
Hans Verkuilecb9e912015-03-09 11:52:43 -03002136 unsigned next_src_y = src_y;
2137
Hans Verkuil280abe42015-03-07 14:50:41 -03002138 if ((h & 3) >= 2)
2139 continue;
Hans Verkuilecb9e912015-03-09 11:52:43 -03002140 next_src_y += int_part;
2141 if (error + fract_part >= tpg->compose.height)
2142 next_src_y++;
2143 params.frame_line_next =
2144 tpg_calc_frameline(tpg, next_src_y, tpg->field);
2145 } else {
2146 if (h & 1)
2147 continue;
2148 params.frame_line_next =
2149 tpg_calc_frameline(tpg, src_y, tpg->field);
Hans Verkuil280abe42015-03-07 14:50:41 -03002150 }
2151
Hans Verkuilecb9e912015-03-09 11:52:43 -03002152 buf_line /= tpg->vdownsampling[p];
Hans Verkuil280abe42015-03-07 14:50:41 -03002153 }
Hans Verkuilecb9e912015-03-09 11:52:43 -03002154 tpg_fill_plane_pattern(tpg, &params, p, h,
2155 vbuf + buf_line * params.stride);
Hans Verkuilc6ff1c12015-03-09 11:47:48 -03002156 tpg_fill_plane_extras(tpg, &params, p, h,
2157 vbuf + buf_line * params.stride);
Hans Verkuil63881df2014-08-25 08:02:14 -03002158 }
2159}
Hans Verkuil4db22042015-03-07 13:39:01 -03002160
2161void tpg_fillbuffer(struct tpg_data *tpg, v4l2_std_id std, unsigned p, u8 *vbuf)
2162{
2163 unsigned offset = 0;
2164 unsigned i;
2165
2166 if (tpg->buffers > 1) {
2167 tpg_fill_plane_buffer(tpg, std, p, vbuf);
2168 return;
2169 }
2170
Hans Verkuil02aa7692015-03-14 08:01:50 -03002171 for (i = 0; i < tpg_g_planes(tpg); i++) {
Hans Verkuil4db22042015-03-07 13:39:01 -03002172 tpg_fill_plane_buffer(tpg, std, i, vbuf + offset);
2173 offset += tpg_calc_plane_size(tpg, i);
2174 }
2175}