blob: cb766eb154e71eff55004bbf0e667fc44964dde7 [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:
Mauro Carvalho Chehab6c515a42014-09-03 15:53:45 -0300223 tpg->is_yuv = false;
Hans Verkuil63881df2014-08-25 08:02:14 -0300224 break;
Hans Verkuil628821c2015-03-13 06:35:40 -0300225 case V4L2_PIX_FMT_YUV444:
226 case V4L2_PIX_FMT_YUV555:
227 case V4L2_PIX_FMT_YUV565:
228 case V4L2_PIX_FMT_YUV32:
229 tpg->is_yuv = true;
230 break;
Hans Verkuil68c90d62015-03-07 14:55:09 -0300231 case V4L2_PIX_FMT_YUV420M:
232 case V4L2_PIX_FMT_YVU420M:
233 tpg->buffers = 3;
234 /* fall through */
235 case V4L2_PIX_FMT_YUV420:
236 case V4L2_PIX_FMT_YVU420:
237 tpg->vdownsampling[1] = 2;
238 tpg->vdownsampling[2] = 2;
239 tpg->hdownsampling[1] = 2;
240 tpg->hdownsampling[2] = 2;
241 tpg->planes = 3;
242 tpg->is_yuv = true;
243 break;
244 case V4L2_PIX_FMT_YUV422P:
245 tpg->vdownsampling[1] = 1;
246 tpg->vdownsampling[2] = 1;
247 tpg->hdownsampling[1] = 2;
248 tpg->hdownsampling[2] = 2;
249 tpg->planes = 3;
250 tpg->is_yuv = true;
251 break;
Hans Verkuil63881df2014-08-25 08:02:14 -0300252 case V4L2_PIX_FMT_NV16M:
253 case V4L2_PIX_FMT_NV61M:
Hans Verkuil68c90d62015-03-07 14:55:09 -0300254 tpg->buffers = 2;
255 /* fall through */
256 case V4L2_PIX_FMT_NV16:
257 case V4L2_PIX_FMT_NV61:
Hans Verkuilba01f672015-03-07 13:57:27 -0300258 tpg->vdownsampling[1] = 1;
259 tpg->hdownsampling[1] = 1;
Hans Verkuil9991def2015-03-08 05:53:10 -0300260 tpg->hmask[1] = ~1;
Hans Verkuil63881df2014-08-25 08:02:14 -0300261 tpg->planes = 2;
Hans Verkuil68c90d62015-03-07 14:55:09 -0300262 tpg->is_yuv = true;
263 break;
264 case V4L2_PIX_FMT_NV12M:
265 case V4L2_PIX_FMT_NV21M:
266 tpg->buffers = 2;
267 /* fall through */
268 case V4L2_PIX_FMT_NV12:
269 case V4L2_PIX_FMT_NV21:
270 tpg->vdownsampling[1] = 2;
271 tpg->hdownsampling[1] = 1;
Hans Verkuil9991def2015-03-08 05:53:10 -0300272 tpg->hmask[1] = ~1;
Hans Verkuil68c90d62015-03-07 14:55:09 -0300273 tpg->planes = 2;
274 tpg->is_yuv = true;
275 break;
Hans Verkuildde72bd2015-03-13 05:51:21 -0300276 case V4L2_PIX_FMT_NV24:
277 case V4L2_PIX_FMT_NV42:
278 tpg->vdownsampling[1] = 1;
279 tpg->hdownsampling[1] = 1;
280 tpg->planes = 2;
281 tpg->is_yuv = true;
282 break;
Hans Verkuil63881df2014-08-25 08:02:14 -0300283 case V4L2_PIX_FMT_YUYV:
284 case V4L2_PIX_FMT_UYVY:
285 case V4L2_PIX_FMT_YVYU:
286 case V4L2_PIX_FMT_VYUY:
Hans Verkuil9991def2015-03-08 05:53:10 -0300287 tpg->hmask[0] = ~1;
Mauro Carvalho Chehab6c515a42014-09-03 15:53:45 -0300288 tpg->is_yuv = true;
Hans Verkuil63881df2014-08-25 08:02:14 -0300289 break;
290 default:
291 return false;
292 }
293
294 switch (fourcc) {
Hans Verkuil71491062015-03-12 15:40:36 -0300295 case V4L2_PIX_FMT_RGB332:
296 tpg->twopixelsize[0] = 2;
297 break;
Hans Verkuil63881df2014-08-25 08:02:14 -0300298 case V4L2_PIX_FMT_RGB565:
299 case V4L2_PIX_FMT_RGB565X:
Hans Verkuil8aca2302015-03-11 08:14:34 -0300300 case V4L2_PIX_FMT_RGB444:
301 case V4L2_PIX_FMT_XRGB444:
302 case V4L2_PIX_FMT_ARGB444:
Hans Verkuil63881df2014-08-25 08:02:14 -0300303 case V4L2_PIX_FMT_RGB555:
304 case V4L2_PIX_FMT_XRGB555:
305 case V4L2_PIX_FMT_ARGB555:
306 case V4L2_PIX_FMT_RGB555X:
Hans Verkuil8f1ff542015-03-12 05:08:01 -0300307 case V4L2_PIX_FMT_XRGB555X:
308 case V4L2_PIX_FMT_ARGB555X:
Hans Verkuil63881df2014-08-25 08:02:14 -0300309 case V4L2_PIX_FMT_YUYV:
310 case V4L2_PIX_FMT_UYVY:
311 case V4L2_PIX_FMT_YVYU:
312 case V4L2_PIX_FMT_VYUY:
Hans Verkuil628821c2015-03-13 06:35:40 -0300313 case V4L2_PIX_FMT_YUV444:
314 case V4L2_PIX_FMT_YUV555:
315 case V4L2_PIX_FMT_YUV565:
Hans Verkuil63881df2014-08-25 08:02:14 -0300316 tpg->twopixelsize[0] = 2 * 2;
317 break;
318 case V4L2_PIX_FMT_RGB24:
319 case V4L2_PIX_FMT_BGR24:
320 tpg->twopixelsize[0] = 2 * 3;
321 break;
Hans Verkuil68cd4e92015-03-13 05:36:08 -0300322 case V4L2_PIX_FMT_BGR666:
Hans Verkuil63881df2014-08-25 08:02:14 -0300323 case V4L2_PIX_FMT_RGB32:
324 case V4L2_PIX_FMT_BGR32:
325 case V4L2_PIX_FMT_XRGB32:
326 case V4L2_PIX_FMT_XBGR32:
327 case V4L2_PIX_FMT_ARGB32:
328 case V4L2_PIX_FMT_ABGR32:
Hans Verkuil628821c2015-03-13 06:35:40 -0300329 case V4L2_PIX_FMT_YUV32:
Hans Verkuil63881df2014-08-25 08:02:14 -0300330 tpg->twopixelsize[0] = 2 * 4;
331 break;
Hans Verkuil51f30962015-03-07 14:57:50 -0300332 case V4L2_PIX_FMT_GREY:
333 tpg->twopixelsize[0] = 2;
334 break;
Hans Verkuil68c90d62015-03-07 14:55:09 -0300335 case V4L2_PIX_FMT_NV12:
336 case V4L2_PIX_FMT_NV21:
337 case V4L2_PIX_FMT_NV12M:
338 case V4L2_PIX_FMT_NV21M:
Hans Verkuil68c90d62015-03-07 14:55:09 -0300339 case V4L2_PIX_FMT_NV16:
340 case V4L2_PIX_FMT_NV61:
Hans Verkuil63881df2014-08-25 08:02:14 -0300341 case V4L2_PIX_FMT_NV16M:
342 case V4L2_PIX_FMT_NV61M:
Hans Verkuil02aa7692015-03-14 08:01:50 -0300343 case V4L2_PIX_FMT_SBGGR8:
344 case V4L2_PIX_FMT_SGBRG8:
345 case V4L2_PIX_FMT_SGRBG8:
346 case V4L2_PIX_FMT_SRGGB8:
Hans Verkuil63881df2014-08-25 08:02:14 -0300347 tpg->twopixelsize[0] = 2;
348 tpg->twopixelsize[1] = 2;
349 break;
Hans Verkuil68c90d62015-03-07 14:55:09 -0300350 case V4L2_PIX_FMT_YUV422P:
351 case V4L2_PIX_FMT_YUV420:
352 case V4L2_PIX_FMT_YVU420:
353 case V4L2_PIX_FMT_YUV420M:
354 case V4L2_PIX_FMT_YVU420M:
355 tpg->twopixelsize[0] = 2;
356 tpg->twopixelsize[1] = 2;
357 tpg->twopixelsize[2] = 2;
358 break;
Hans Verkuildde72bd2015-03-13 05:51:21 -0300359 case V4L2_PIX_FMT_NV24:
360 case V4L2_PIX_FMT_NV42:
361 tpg->twopixelsize[0] = 2;
362 tpg->twopixelsize[1] = 4;
363 break;
Hans Verkuil63881df2014-08-25 08:02:14 -0300364 }
365 return true;
366}
367
368void tpg_s_crop_compose(struct tpg_data *tpg, const struct v4l2_rect *crop,
369 const struct v4l2_rect *compose)
370{
371 tpg->crop = *crop;
372 tpg->compose = *compose;
373 tpg->scaled_width = (tpg->src_width * tpg->compose.width +
374 tpg->crop.width - 1) / tpg->crop.width;
375 tpg->scaled_width &= ~1;
376 if (tpg->scaled_width > tpg->max_line_width)
377 tpg->scaled_width = tpg->max_line_width;
378 if (tpg->scaled_width < 2)
379 tpg->scaled_width = 2;
380 tpg->recalc_lines = true;
381}
382
383void tpg_reset_source(struct tpg_data *tpg, unsigned width, unsigned height,
Hans Verkuil73d81022014-09-03 10:18:57 -0300384 u32 field)
Hans Verkuil63881df2014-08-25 08:02:14 -0300385{
386 unsigned p;
387
388 tpg->src_width = width;
389 tpg->src_height = height;
390 tpg->field = field;
391 tpg->buf_height = height;
392 if (V4L2_FIELD_HAS_T_OR_B(field))
393 tpg->buf_height /= 2;
394 tpg->scaled_width = width;
395 tpg->crop.top = tpg->crop.left = 0;
396 tpg->crop.width = width;
397 tpg->crop.height = height;
398 tpg->compose.top = tpg->compose.left = 0;
399 tpg->compose.width = width;
400 tpg->compose.height = tpg->buf_height;
401 for (p = 0; p < tpg->planes; p++)
Hans Verkuilba01f672015-03-07 13:57:27 -0300402 tpg->bytesperline[p] = (width * tpg->twopixelsize[p]) /
403 (2 * tpg->hdownsampling[p]);
Hans Verkuil63881df2014-08-25 08:02:14 -0300404 tpg->recalc_square_border = true;
405}
406
407static enum tpg_color tpg_get_textbg_color(struct tpg_data *tpg)
408{
409 switch (tpg->pattern) {
410 case TPG_PAT_BLACK:
411 return TPG_COLOR_100_WHITE;
412 case TPG_PAT_CSC_COLORBAR:
413 return TPG_COLOR_CSC_BLACK;
414 default:
415 return TPG_COLOR_100_BLACK;
416 }
417}
418
419static enum tpg_color tpg_get_textfg_color(struct tpg_data *tpg)
420{
421 switch (tpg->pattern) {
422 case TPG_PAT_75_COLORBAR:
423 case TPG_PAT_CSC_COLORBAR:
424 return TPG_COLOR_CSC_WHITE;
425 case TPG_PAT_BLACK:
426 return TPG_COLOR_100_BLACK;
427 default:
428 return TPG_COLOR_100_WHITE;
429 }
430}
431
Hans Verkuil481b97a2014-11-17 10:14:32 -0300432static inline int rec709_to_linear(int v)
Hans Verkuil63881df2014-08-25 08:02:14 -0300433{
Hans Verkuil481b97a2014-11-17 10:14:32 -0300434 v = clamp(v, 0, 0xff0);
435 return tpg_rec709_to_linear[v];
436}
437
438static inline int linear_to_rec709(int v)
439{
440 v = clamp(v, 0, 0xff0);
441 return tpg_linear_to_rec709[v];
442}
443
444static void rgb2ycbcr(const int m[3][3], int r, int g, int b,
445 int y_offset, int *y, int *cb, int *cr)
446{
447 *y = ((m[0][0] * r + m[0][1] * g + m[0][2] * b) >> 16) + (y_offset << 4);
448 *cb = ((m[1][0] * r + m[1][1] * g + m[1][2] * b) >> 16) + (128 << 4);
449 *cr = ((m[2][0] * r + m[2][1] * g + m[2][2] * b) >> 16) + (128 << 4);
450}
451
452static void color_to_ycbcr(struct tpg_data *tpg, int r, int g, int b,
453 int *y, int *cb, int *cr)
454{
455#define COEFF(v, r) ((int)(0.5 + (v) * (r) * 256.0))
456
457 static const int bt601[3][3] = {
458 { COEFF(0.299, 219), COEFF(0.587, 219), COEFF(0.114, 219) },
459 { COEFF(-0.169, 224), COEFF(-0.331, 224), COEFF(0.5, 224) },
460 { COEFF(0.5, 224), COEFF(-0.419, 224), COEFF(-0.081, 224) },
461 };
462 static const int bt601_full[3][3] = {
463 { COEFF(0.299, 255), COEFF(0.587, 255), COEFF(0.114, 255) },
464 { COEFF(-0.169, 255), COEFF(-0.331, 255), COEFF(0.5, 255) },
465 { COEFF(0.5, 255), COEFF(-0.419, 255), COEFF(-0.081, 255) },
466 };
467 static const int rec709[3][3] = {
468 { COEFF(0.2126, 219), COEFF(0.7152, 219), COEFF(0.0722, 219) },
469 { COEFF(-0.1146, 224), COEFF(-0.3854, 224), COEFF(0.5, 224) },
470 { COEFF(0.5, 224), COEFF(-0.4542, 224), COEFF(-0.0458, 224) },
471 };
472 static const int rec709_full[3][3] = {
473 { COEFF(0.2126, 255), COEFF(0.7152, 255), COEFF(0.0722, 255) },
474 { COEFF(-0.1146, 255), COEFF(-0.3854, 255), COEFF(0.5, 255) },
475 { COEFF(0.5, 255), COEFF(-0.4542, 255), COEFF(-0.0458, 255) },
476 };
477 static const int smpte240m[3][3] = {
478 { COEFF(0.212, 219), COEFF(0.701, 219), COEFF(0.087, 219) },
479 { COEFF(-0.116, 224), COEFF(-0.384, 224), COEFF(0.5, 224) },
480 { COEFF(0.5, 224), COEFF(-0.445, 224), COEFF(-0.055, 224) },
481 };
482 static const int bt2020[3][3] = {
Hans Verkuile202e512015-03-20 13:23:06 -0300483 { COEFF(0.2627, 219), COEFF(0.6780, 219), COEFF(0.0593, 219) },
Hans Verkuil481b97a2014-11-17 10:14:32 -0300484 { COEFF(-0.1396, 224), COEFF(-0.3604, 224), COEFF(0.5, 224) },
Hans Verkuile202e512015-03-20 13:23:06 -0300485 { COEFF(0.5, 224), COEFF(-0.4598, 224), COEFF(-0.0402, 224) },
Hans Verkuil481b97a2014-11-17 10:14:32 -0300486 };
487 bool full = tpg->real_quantization == V4L2_QUANTIZATION_FULL_RANGE;
Hans Verkuilafad4dd2015-01-27 13:46:17 -0300488 unsigned y_offset = full ? 0 : 16;
Hans Verkuil481b97a2014-11-17 10:14:32 -0300489 int lin_y, yc;
490
491 switch (tpg->real_ycbcr_enc) {
492 case V4L2_YCBCR_ENC_601:
493 case V4L2_YCBCR_ENC_XV601:
494 case V4L2_YCBCR_ENC_SYCC:
Hans Verkuilafad4dd2015-01-27 13:46:17 -0300495 rgb2ycbcr(full ? bt601_full : bt601, r, g, b, y_offset, y, cb, cr);
Hans Verkuil481b97a2014-11-17 10:14:32 -0300496 break;
497 case V4L2_YCBCR_ENC_BT2020:
498 rgb2ycbcr(bt2020, r, g, b, 16, y, cb, cr);
499 break;
500 case V4L2_YCBCR_ENC_BT2020_CONST_LUM:
501 lin_y = (COEFF(0.2627, 255) * rec709_to_linear(r) +
502 COEFF(0.6780, 255) * rec709_to_linear(g) +
503 COEFF(0.0593, 255) * rec709_to_linear(b)) >> 16;
504 yc = linear_to_rec709(lin_y);
505 *y = (yc * 219) / 255 + (16 << 4);
506 if (b <= yc)
507 *cb = (((b - yc) * COEFF(1.0 / 1.9404, 224)) >> 16) + (128 << 4);
508 else
509 *cb = (((b - yc) * COEFF(1.0 / 1.5816, 224)) >> 16) + (128 << 4);
510 if (r <= yc)
511 *cr = (((r - yc) * COEFF(1.0 / 1.7184, 224)) >> 16) + (128 << 4);
512 else
513 *cr = (((r - yc) * COEFF(1.0 / 0.9936, 224)) >> 16) + (128 << 4);
514 break;
515 case V4L2_YCBCR_ENC_SMPTE240M:
516 rgb2ycbcr(smpte240m, r, g, b, 16, y, cb, cr);
517 break;
518 case V4L2_YCBCR_ENC_709:
519 case V4L2_YCBCR_ENC_XV709:
Hans Verkuil63881df2014-08-25 08:02:14 -0300520 default:
Hans Verkuilafad4dd2015-01-27 13:46:17 -0300521 rgb2ycbcr(full ? rec709_full : rec709, r, g, b, y_offset, y, cb, cr);
Hans Verkuil481b97a2014-11-17 10:14:32 -0300522 break;
Hans Verkuil63881df2014-08-25 08:02:14 -0300523 }
524}
525
Hans Verkuil481b97a2014-11-17 10:14:32 -0300526static void ycbcr2rgb(const int m[3][3], int y, int cb, int cr,
527 int y_offset, int *r, int *g, int *b)
Hans Verkuil63881df2014-08-25 08:02:14 -0300528{
Hans Verkuil481b97a2014-11-17 10:14:32 -0300529 y -= y_offset << 4;
Hans Verkuil63881df2014-08-25 08:02:14 -0300530 cb -= 128 << 4;
531 cr -= 128 << 4;
Hans Verkuil481b97a2014-11-17 10:14:32 -0300532 *r = m[0][0] * y + m[0][1] * cb + m[0][2] * cr;
533 *g = m[1][0] * y + m[1][1] * cb + m[1][2] * cr;
534 *b = m[2][0] * y + m[2][1] * cb + m[2][2] * cr;
535 *r = clamp(*r >> 12, 0, 0xff0);
536 *g = clamp(*g >> 12, 0, 0xff0);
537 *b = clamp(*b >> 12, 0, 0xff0);
Hans Verkuil63881df2014-08-25 08:02:14 -0300538}
539
Hans Verkuil481b97a2014-11-17 10:14:32 -0300540static void ycbcr_to_color(struct tpg_data *tpg, int y, int cb, int cr,
541 int *r, int *g, int *b)
Hans Verkuil63881df2014-08-25 08:02:14 -0300542{
Hans Verkuil481b97a2014-11-17 10:14:32 -0300543#undef COEFF
544#define COEFF(v, r) ((int)(0.5 + (v) * ((255.0 * 255.0 * 16.0) / (r))))
545 static const int bt601[3][3] = {
546 { COEFF(1, 219), COEFF(0, 224), COEFF(1.4020, 224) },
547 { COEFF(1, 219), COEFF(-0.3441, 224), COEFF(-0.7141, 224) },
548 { COEFF(1, 219), COEFF(1.7720, 224), COEFF(0, 224) },
549 };
550 static const int bt601_full[3][3] = {
551 { COEFF(1, 255), COEFF(0, 255), COEFF(1.4020, 255) },
552 { COEFF(1, 255), COEFF(-0.3441, 255), COEFF(-0.7141, 255) },
553 { COEFF(1, 255), COEFF(1.7720, 255), COEFF(0, 255) },
554 };
555 static const int rec709[3][3] = {
556 { COEFF(1, 219), COEFF(0, 224), COEFF(1.5748, 224) },
557 { COEFF(1, 219), COEFF(-0.1873, 224), COEFF(-0.4681, 224) },
558 { COEFF(1, 219), COEFF(1.8556, 224), COEFF(0, 224) },
559 };
560 static const int rec709_full[3][3] = {
561 { COEFF(1, 255), COEFF(0, 255), COEFF(1.5748, 255) },
562 { COEFF(1, 255), COEFF(-0.1873, 255), COEFF(-0.4681, 255) },
563 { COEFF(1, 255), COEFF(1.8556, 255), COEFF(0, 255) },
564 };
565 static const int smpte240m[3][3] = {
566 { COEFF(1, 219), COEFF(0, 224), COEFF(1.5756, 224) },
567 { COEFF(1, 219), COEFF(-0.2253, 224), COEFF(-0.4767, 224) },
568 { COEFF(1, 219), COEFF(1.8270, 224), COEFF(0, 224) },
569 };
570 static const int bt2020[3][3] = {
571 { COEFF(1, 219), COEFF(0, 224), COEFF(1.4746, 224) },
572 { COEFF(1, 219), COEFF(-0.1646, 224), COEFF(-0.5714, 224) },
573 { COEFF(1, 219), COEFF(1.8814, 224), COEFF(0, 224) },
574 };
575 bool full = tpg->real_quantization == V4L2_QUANTIZATION_FULL_RANGE;
Hans Verkuilafad4dd2015-01-27 13:46:17 -0300576 unsigned y_offset = full ? 0 : 16;
Hans Verkuil481b97a2014-11-17 10:14:32 -0300577 int lin_r, lin_g, lin_b, lin_y;
Hans Verkuil63881df2014-08-25 08:02:14 -0300578
Hans Verkuil481b97a2014-11-17 10:14:32 -0300579 switch (tpg->real_ycbcr_enc) {
580 case V4L2_YCBCR_ENC_601:
581 case V4L2_YCBCR_ENC_XV601:
582 case V4L2_YCBCR_ENC_SYCC:
Hans Verkuilafad4dd2015-01-27 13:46:17 -0300583 ycbcr2rgb(full ? bt601_full : bt601, y, cb, cr, y_offset, r, g, b);
Hans Verkuil63881df2014-08-25 08:02:14 -0300584 break;
Hans Verkuil481b97a2014-11-17 10:14:32 -0300585 case V4L2_YCBCR_ENC_BT2020:
586 ycbcr2rgb(bt2020, y, cb, cr, 16, r, g, b);
Hans Verkuil63881df2014-08-25 08:02:14 -0300587 break;
Hans Verkuil481b97a2014-11-17 10:14:32 -0300588 case V4L2_YCBCR_ENC_BT2020_CONST_LUM:
589 y -= 16 << 4;
590 cb -= 128 << 4;
591 cr -= 128 << 4;
592
593 if (cb <= 0)
594 *b = COEFF(1.0, 219) * y + COEFF(1.9404, 224) * cb;
595 else
596 *b = COEFF(1.0, 219) * y + COEFF(1.5816, 224) * cb;
597 *b = *b >> 12;
598 if (cr <= 0)
599 *r = COEFF(1.0, 219) * y + COEFF(1.7184, 224) * cr;
600 else
601 *r = COEFF(1.0, 219) * y + COEFF(0.9936, 224) * cr;
602 *r = *r >> 12;
603 lin_r = rec709_to_linear(*r);
604 lin_b = rec709_to_linear(*b);
605 lin_y = rec709_to_linear((y * 255) / 219);
606
607 lin_g = COEFF(1.0 / 0.6780, 255) * lin_y -
608 COEFF(0.2627 / 0.6780, 255) * lin_r -
609 COEFF(0.0593 / 0.6780, 255) * lin_b;
610 *g = linear_to_rec709(lin_g >> 12);
611 break;
612 case V4L2_YCBCR_ENC_SMPTE240M:
613 ycbcr2rgb(smpte240m, y, cb, cr, 16, r, g, b);
614 break;
615 case V4L2_YCBCR_ENC_709:
616 case V4L2_YCBCR_ENC_XV709:
Hans Verkuil63881df2014-08-25 08:02:14 -0300617 default:
Hans Verkuilafad4dd2015-01-27 13:46:17 -0300618 ycbcr2rgb(full ? rec709_full : rec709, y, cb, cr, y_offset, r, g, b);
Hans Verkuil63881df2014-08-25 08:02:14 -0300619 break;
620 }
Hans Verkuil63881df2014-08-25 08:02:14 -0300621}
622
623/* precalculate color bar values to speed up rendering */
624static void precalculate_color(struct tpg_data *tpg, int k)
625{
626 int col = k;
627 int r = tpg_colors[col].r;
628 int g = tpg_colors[col].g;
629 int b = tpg_colors[col].b;
630
631 if (k == TPG_COLOR_TEXTBG) {
632 col = tpg_get_textbg_color(tpg);
633
634 r = tpg_colors[col].r;
635 g = tpg_colors[col].g;
636 b = tpg_colors[col].b;
637 } else if (k == TPG_COLOR_TEXTFG) {
638 col = tpg_get_textfg_color(tpg);
639
640 r = tpg_colors[col].r;
641 g = tpg_colors[col].g;
642 b = tpg_colors[col].b;
643 } else if (tpg->pattern == TPG_PAT_NOISE) {
644 r = g = b = prandom_u32_max(256);
645 } else if (k == TPG_COLOR_RANDOM) {
646 r = g = b = tpg->qual_offset + prandom_u32_max(196);
647 } else if (k >= TPG_COLOR_RAMP) {
648 r = g = b = k - TPG_COLOR_RAMP;
649 }
650
651 if (tpg->pattern == TPG_PAT_CSC_COLORBAR && col <= TPG_COLOR_CSC_BLACK) {
652 r = tpg_csc_colors[tpg->colorspace][col].r;
653 g = tpg_csc_colors[tpg->colorspace][col].g;
654 b = tpg_csc_colors[tpg->colorspace][col].b;
655 } else {
656 r <<= 4;
657 g <<= 4;
658 b <<= 4;
659 }
Hans Verkuil51f30962015-03-07 14:57:50 -0300660 if (tpg->qual == TPG_QUAL_GRAY || tpg->fourcc == V4L2_PIX_FMT_GREY) {
Hans Verkuil481b97a2014-11-17 10:14:32 -0300661 /* Rec. 709 Luma function */
662 /* (0.2126, 0.7152, 0.0722) * (255 * 256) */
Hans Verkuil9c35bd42015-03-07 12:53:39 -0300663 r = g = b = (13879 * r + 46688 * g + 4713 * b) >> 16;
Hans Verkuil481b97a2014-11-17 10:14:32 -0300664 }
Hans Verkuil63881df2014-08-25 08:02:14 -0300665
666 /*
667 * The assumption is that the RGB output is always full range,
668 * so only if the rgb_range overrides the 'real' rgb range do
669 * we need to convert the RGB values.
670 *
Hans Verkuil63881df2014-08-25 08:02:14 -0300671 * Remember that r, g and b are still in the 0 - 0xff0 range.
672 */
673 if (tpg->real_rgb_range == V4L2_DV_RGB_RANGE_LIMITED &&
674 tpg->rgb_range == V4L2_DV_RGB_RANGE_FULL) {
675 /*
676 * Convert from full range (which is what r, g and b are)
677 * to limited range (which is the 'real' RGB range), which
678 * is then interpreted as full range.
679 */
680 r = (r * 219) / 255 + (16 << 4);
681 g = (g * 219) / 255 + (16 << 4);
682 b = (b * 219) / 255 + (16 << 4);
683 } else if (tpg->real_rgb_range != V4L2_DV_RGB_RANGE_LIMITED &&
684 tpg->rgb_range == V4L2_DV_RGB_RANGE_LIMITED) {
685 /*
686 * Clamp r, g and b to the limited range and convert to full
687 * range since that's what we deliver.
688 */
689 r = clamp(r, 16 << 4, 235 << 4);
690 g = clamp(g, 16 << 4, 235 << 4);
691 b = clamp(b, 16 << 4, 235 << 4);
692 r = (r - (16 << 4)) * 255 / 219;
693 g = (g - (16 << 4)) * 255 / 219;
694 b = (b - (16 << 4)) * 255 / 219;
695 }
696
697 if (tpg->brightness != 128 || tpg->contrast != 128 ||
698 tpg->saturation != 128 || tpg->hue) {
699 /* Implement these operations */
Hans Verkuil481b97a2014-11-17 10:14:32 -0300700 int y, cb, cr;
701 int tmp_cb, tmp_cr;
Hans Verkuil63881df2014-08-25 08:02:14 -0300702
703 /* First convert to YCbCr */
Hans Verkuil481b97a2014-11-17 10:14:32 -0300704
705 color_to_ycbcr(tpg, r, g, b, &y, &cb, &cr);
Hans Verkuil63881df2014-08-25 08:02:14 -0300706
707 y = (16 << 4) + ((y - (16 << 4)) * tpg->contrast) / 128;
708 y += (tpg->brightness << 4) - (128 << 4);
709
710 cb -= 128 << 4;
711 cr -= 128 << 4;
712 tmp_cb = (cb * cos(128 + tpg->hue)) / 127 + (cr * sin[128 + tpg->hue]) / 127;
713 tmp_cr = (cr * cos(128 + tpg->hue)) / 127 - (cb * sin[128 + tpg->hue]) / 127;
714
715 cb = (128 << 4) + (tmp_cb * tpg->contrast * tpg->saturation) / (128 * 128);
716 cr = (128 << 4) + (tmp_cr * tpg->contrast * tpg->saturation) / (128 * 128);
717 if (tpg->is_yuv) {
718 tpg->colors[k][0] = clamp(y >> 4, 1, 254);
719 tpg->colors[k][1] = clamp(cb >> 4, 1, 254);
720 tpg->colors[k][2] = clamp(cr >> 4, 1, 254);
721 return;
722 }
Hans Verkuil481b97a2014-11-17 10:14:32 -0300723 ycbcr_to_color(tpg, y, cb, cr, &r, &g, &b);
Hans Verkuil63881df2014-08-25 08:02:14 -0300724 }
725
726 if (tpg->is_yuv) {
727 /* Convert to YCbCr */
Hans Verkuil481b97a2014-11-17 10:14:32 -0300728 int y, cb, cr;
Hans Verkuil63881df2014-08-25 08:02:14 -0300729
Hans Verkuil481b97a2014-11-17 10:14:32 -0300730 color_to_ycbcr(tpg, r, g, b, &y, &cb, &cr);
731
732 if (tpg->real_quantization == V4L2_QUANTIZATION_LIM_RANGE) {
733 y = clamp(y, 16 << 4, 235 << 4);
734 cb = clamp(cb, 16 << 4, 240 << 4);
735 cr = clamp(cr, 16 << 4, 240 << 4);
736 }
Hans Verkuil628821c2015-03-13 06:35:40 -0300737 y = clamp(y >> 4, 1, 254);
738 cb = clamp(cb >> 4, 1, 254);
739 cr = clamp(cr >> 4, 1, 254);
740 switch (tpg->fourcc) {
741 case V4L2_PIX_FMT_YUV444:
742 y >>= 4;
743 cb >>= 4;
744 cr >>= 4;
745 break;
746 case V4L2_PIX_FMT_YUV555:
747 y >>= 3;
748 cb >>= 3;
749 cr >>= 3;
750 break;
751 case V4L2_PIX_FMT_YUV565:
752 y >>= 3;
753 cb >>= 2;
754 cr >>= 3;
755 break;
756 }
757 tpg->colors[k][0] = y;
758 tpg->colors[k][1] = cb;
759 tpg->colors[k][2] = cr;
Hans Verkuil63881df2014-08-25 08:02:14 -0300760 } else {
Hans Verkuil481b97a2014-11-17 10:14:32 -0300761 if (tpg->real_quantization == V4L2_QUANTIZATION_LIM_RANGE) {
762 r = (r * 219) / 255 + (16 << 4);
763 g = (g * 219) / 255 + (16 << 4);
764 b = (b * 219) / 255 + (16 << 4);
765 }
Hans Verkuil63881df2014-08-25 08:02:14 -0300766 switch (tpg->fourcc) {
Hans Verkuil71491062015-03-12 15:40:36 -0300767 case V4L2_PIX_FMT_RGB332:
768 r >>= 9;
769 g >>= 9;
770 b >>= 10;
771 break;
Hans Verkuil63881df2014-08-25 08:02:14 -0300772 case V4L2_PIX_FMT_RGB565:
773 case V4L2_PIX_FMT_RGB565X:
774 r >>= 7;
775 g >>= 6;
776 b >>= 7;
777 break;
Hans Verkuil8aca2302015-03-11 08:14:34 -0300778 case V4L2_PIX_FMT_RGB444:
779 case V4L2_PIX_FMT_XRGB444:
780 case V4L2_PIX_FMT_ARGB444:
781 r >>= 8;
782 g >>= 8;
783 b >>= 8;
784 break;
Hans Verkuil63881df2014-08-25 08:02:14 -0300785 case V4L2_PIX_FMT_RGB555:
786 case V4L2_PIX_FMT_XRGB555:
787 case V4L2_PIX_FMT_ARGB555:
788 case V4L2_PIX_FMT_RGB555X:
Hans Verkuil8f1ff542015-03-12 05:08:01 -0300789 case V4L2_PIX_FMT_XRGB555X:
790 case V4L2_PIX_FMT_ARGB555X:
Hans Verkuil63881df2014-08-25 08:02:14 -0300791 r >>= 7;
792 g >>= 7;
793 b >>= 7;
794 break;
Hans Verkuil68cd4e92015-03-13 05:36:08 -0300795 case V4L2_PIX_FMT_BGR666:
796 r >>= 6;
797 g >>= 6;
798 b >>= 6;
799 break;
Hans Verkuil63881df2014-08-25 08:02:14 -0300800 default:
801 r >>= 4;
802 g >>= 4;
803 b >>= 4;
804 break;
805 }
806
807 tpg->colors[k][0] = r;
808 tpg->colors[k][1] = g;
809 tpg->colors[k][2] = b;
810 }
811}
812
813static void tpg_precalculate_colors(struct tpg_data *tpg)
814{
815 int k;
816
817 for (k = 0; k < TPG_COLOR_MAX; k++)
818 precalculate_color(tpg, k);
819}
820
821/* 'odd' is true for pixels 1, 3, 5, etc. and false for pixels 0, 2, 4, etc. */
822static void gen_twopix(struct tpg_data *tpg,
823 u8 buf[TPG_MAX_PLANES][8], int color, bool odd)
824{
825 unsigned offset = odd * tpg->twopixelsize[0] / 2;
826 u8 alpha = tpg->alpha_component;
827 u8 r_y, g_u, b_v;
828
829 if (tpg->alpha_red_only && color != TPG_COLOR_CSC_RED &&
830 color != TPG_COLOR_100_RED &&
831 color != TPG_COLOR_75_RED)
832 alpha = 0;
833 if (color == TPG_COLOR_RANDOM)
834 precalculate_color(tpg, color);
835 r_y = tpg->colors[color][0]; /* R or precalculated Y */
836 g_u = tpg->colors[color][1]; /* G or precalculated U */
837 b_v = tpg->colors[color][2]; /* B or precalculated V */
838
839 switch (tpg->fourcc) {
Hans Verkuil51f30962015-03-07 14:57:50 -0300840 case V4L2_PIX_FMT_GREY:
841 buf[0][offset] = r_y;
842 break;
Hans Verkuil68c90d62015-03-07 14:55:09 -0300843 case V4L2_PIX_FMT_YUV422P:
844 case V4L2_PIX_FMT_YUV420:
845 case V4L2_PIX_FMT_YUV420M:
846 buf[0][offset] = r_y;
847 if (odd) {
848 buf[1][0] = (buf[1][0] + g_u) / 2;
849 buf[2][0] = (buf[2][0] + b_v) / 2;
850 buf[1][1] = buf[1][0];
851 buf[2][1] = buf[2][0];
852 break;
853 }
854 buf[1][0] = g_u;
855 buf[2][0] = b_v;
856 break;
857 case V4L2_PIX_FMT_YVU420:
858 case V4L2_PIX_FMT_YVU420M:
859 buf[0][offset] = r_y;
860 if (odd) {
861 buf[1][0] = (buf[1][0] + b_v) / 2;
862 buf[2][0] = (buf[2][0] + g_u) / 2;
863 buf[1][1] = buf[1][0];
864 buf[2][1] = buf[2][0];
865 break;
866 }
867 buf[1][0] = b_v;
868 buf[2][0] = g_u;
869 break;
870
871 case V4L2_PIX_FMT_NV12:
872 case V4L2_PIX_FMT_NV12M:
873 case V4L2_PIX_FMT_NV16:
Hans Verkuil63881df2014-08-25 08:02:14 -0300874 case V4L2_PIX_FMT_NV16M:
875 buf[0][offset] = r_y;
Hans Verkuil1f088dc2015-03-07 14:15:25 -0300876 if (odd) {
877 buf[1][0] = (buf[1][0] + g_u) / 2;
878 buf[1][1] = (buf[1][1] + b_v) / 2;
879 break;
880 }
881 buf[1][0] = g_u;
882 buf[1][1] = b_v;
Hans Verkuil63881df2014-08-25 08:02:14 -0300883 break;
Hans Verkuil68c90d62015-03-07 14:55:09 -0300884 case V4L2_PIX_FMT_NV21:
885 case V4L2_PIX_FMT_NV21M:
886 case V4L2_PIX_FMT_NV61:
Hans Verkuil63881df2014-08-25 08:02:14 -0300887 case V4L2_PIX_FMT_NV61M:
888 buf[0][offset] = r_y;
Hans Verkuil1f088dc2015-03-07 14:15:25 -0300889 if (odd) {
890 buf[1][0] = (buf[1][0] + b_v) / 2;
891 buf[1][1] = (buf[1][1] + g_u) / 2;
892 break;
893 }
894 buf[1][0] = b_v;
895 buf[1][1] = g_u;
Hans Verkuil63881df2014-08-25 08:02:14 -0300896 break;
897
Hans Verkuildde72bd2015-03-13 05:51:21 -0300898 case V4L2_PIX_FMT_NV24:
899 buf[0][offset] = r_y;
900 buf[1][2 * offset] = g_u;
901 buf[1][2 * offset + 1] = b_v;
902 break;
903
904 case V4L2_PIX_FMT_NV42:
905 buf[0][offset] = r_y;
906 buf[1][2 * offset] = b_v;
907 buf[1][2 * offset + 1] = g_u;
908 break;
909
Hans Verkuil63881df2014-08-25 08:02:14 -0300910 case V4L2_PIX_FMT_YUYV:
911 buf[0][offset] = r_y;
Hans Verkuil1f088dc2015-03-07 14:15:25 -0300912 if (odd) {
913 buf[0][1] = (buf[0][1] + g_u) / 2;
914 buf[0][3] = (buf[0][3] + b_v) / 2;
915 break;
916 }
917 buf[0][1] = g_u;
918 buf[0][3] = b_v;
Hans Verkuil63881df2014-08-25 08:02:14 -0300919 break;
920 case V4L2_PIX_FMT_UYVY:
Hans Verkuil63881df2014-08-25 08:02:14 -0300921 buf[0][offset + 1] = r_y;
Hans Verkuil1f088dc2015-03-07 14:15:25 -0300922 if (odd) {
923 buf[0][0] = (buf[0][0] + g_u) / 2;
924 buf[0][2] = (buf[0][2] + b_v) / 2;
925 break;
926 }
927 buf[0][0] = g_u;
928 buf[0][2] = b_v;
Hans Verkuil63881df2014-08-25 08:02:14 -0300929 break;
930 case V4L2_PIX_FMT_YVYU:
931 buf[0][offset] = r_y;
Hans Verkuil1f088dc2015-03-07 14:15:25 -0300932 if (odd) {
933 buf[0][1] = (buf[0][1] + b_v) / 2;
934 buf[0][3] = (buf[0][3] + g_u) / 2;
935 break;
936 }
937 buf[0][1] = b_v;
938 buf[0][3] = g_u;
Hans Verkuil63881df2014-08-25 08:02:14 -0300939 break;
940 case V4L2_PIX_FMT_VYUY:
Hans Verkuil63881df2014-08-25 08:02:14 -0300941 buf[0][offset + 1] = r_y;
Hans Verkuil1f088dc2015-03-07 14:15:25 -0300942 if (odd) {
943 buf[0][0] = (buf[0][0] + b_v) / 2;
944 buf[0][2] = (buf[0][2] + g_u) / 2;
945 break;
946 }
947 buf[0][0] = b_v;
948 buf[0][2] = g_u;
Hans Verkuil63881df2014-08-25 08:02:14 -0300949 break;
Hans Verkuil71491062015-03-12 15:40:36 -0300950 case V4L2_PIX_FMT_RGB332:
951 buf[0][offset] = (r_y << 5) | (g_u << 2) | b_v;
952 break;
Hans Verkuil628821c2015-03-13 06:35:40 -0300953 case V4L2_PIX_FMT_YUV565:
Hans Verkuil63881df2014-08-25 08:02:14 -0300954 case V4L2_PIX_FMT_RGB565:
955 buf[0][offset] = (g_u << 5) | b_v;
956 buf[0][offset + 1] = (r_y << 3) | (g_u >> 3);
957 break;
958 case V4L2_PIX_FMT_RGB565X:
959 buf[0][offset] = (r_y << 3) | (g_u >> 3);
960 buf[0][offset + 1] = (g_u << 5) | b_v;
961 break;
Hans Verkuil8aca2302015-03-11 08:14:34 -0300962 case V4L2_PIX_FMT_RGB444:
963 case V4L2_PIX_FMT_XRGB444:
964 alpha = 0;
965 /* fall through */
Hans Verkuil628821c2015-03-13 06:35:40 -0300966 case V4L2_PIX_FMT_YUV444:
Hans Verkuil8aca2302015-03-11 08:14:34 -0300967 case V4L2_PIX_FMT_ARGB444:
968 buf[0][offset] = (g_u << 4) | b_v;
969 buf[0][offset + 1] = (alpha & 0xf0) | r_y;
970 break;
Hans Verkuil63881df2014-08-25 08:02:14 -0300971 case V4L2_PIX_FMT_RGB555:
972 case V4L2_PIX_FMT_XRGB555:
973 alpha = 0;
974 /* fall through */
Hans Verkuil628821c2015-03-13 06:35:40 -0300975 case V4L2_PIX_FMT_YUV555:
Hans Verkuil63881df2014-08-25 08:02:14 -0300976 case V4L2_PIX_FMT_ARGB555:
977 buf[0][offset] = (g_u << 5) | b_v;
978 buf[0][offset + 1] = (alpha & 0x80) | (r_y << 2) | (g_u >> 3);
979 break;
980 case V4L2_PIX_FMT_RGB555X:
Hans Verkuil8f1ff542015-03-12 05:08:01 -0300981 case V4L2_PIX_FMT_XRGB555X:
982 alpha = 0;
983 /* fall through */
984 case V4L2_PIX_FMT_ARGB555X:
Hans Verkuil63881df2014-08-25 08:02:14 -0300985 buf[0][offset] = (alpha & 0x80) | (r_y << 2) | (g_u >> 3);
986 buf[0][offset + 1] = (g_u << 5) | b_v;
987 break;
988 case V4L2_PIX_FMT_RGB24:
989 buf[0][offset] = r_y;
990 buf[0][offset + 1] = g_u;
991 buf[0][offset + 2] = b_v;
992 break;
993 case V4L2_PIX_FMT_BGR24:
994 buf[0][offset] = b_v;
995 buf[0][offset + 1] = g_u;
996 buf[0][offset + 2] = r_y;
997 break;
Hans Verkuil68cd4e92015-03-13 05:36:08 -0300998 case V4L2_PIX_FMT_BGR666:
999 buf[0][offset] = (b_v << 2) | (g_u >> 4);
1000 buf[0][offset + 1] = (g_u << 4) | (r_y >> 2);
1001 buf[0][offset + 2] = r_y << 6;
1002 buf[0][offset + 3] = 0;
1003 break;
Hans Verkuil63881df2014-08-25 08:02:14 -03001004 case V4L2_PIX_FMT_RGB32:
1005 case V4L2_PIX_FMT_XRGB32:
1006 alpha = 0;
1007 /* fall through */
Hans Verkuil628821c2015-03-13 06:35:40 -03001008 case V4L2_PIX_FMT_YUV32:
Hans Verkuil63881df2014-08-25 08:02:14 -03001009 case V4L2_PIX_FMT_ARGB32:
1010 buf[0][offset] = alpha;
1011 buf[0][offset + 1] = r_y;
1012 buf[0][offset + 2] = g_u;
1013 buf[0][offset + 3] = b_v;
1014 break;
1015 case V4L2_PIX_FMT_BGR32:
1016 case V4L2_PIX_FMT_XBGR32:
1017 alpha = 0;
1018 /* fall through */
1019 case V4L2_PIX_FMT_ABGR32:
1020 buf[0][offset] = b_v;
1021 buf[0][offset + 1] = g_u;
1022 buf[0][offset + 2] = r_y;
1023 buf[0][offset + 3] = alpha;
1024 break;
Hans Verkuil02aa7692015-03-14 08:01:50 -03001025 case V4L2_PIX_FMT_SBGGR8:
1026 buf[0][offset] = odd ? g_u : b_v;
1027 buf[1][offset] = odd ? r_y : g_u;
1028 break;
1029 case V4L2_PIX_FMT_SGBRG8:
1030 buf[0][offset] = odd ? b_v : g_u;
1031 buf[1][offset] = odd ? g_u : r_y;
1032 break;
1033 case V4L2_PIX_FMT_SGRBG8:
1034 buf[0][offset] = odd ? r_y : g_u;
1035 buf[1][offset] = odd ? g_u : b_v;
1036 break;
1037 case V4L2_PIX_FMT_SRGGB8:
1038 buf[0][offset] = odd ? g_u : r_y;
1039 buf[1][offset] = odd ? b_v : g_u;
1040 break;
1041 }
1042}
1043
1044unsigned tpg_g_interleaved_plane(const struct tpg_data *tpg, unsigned buf_line)
1045{
1046 switch (tpg->fourcc) {
1047 case V4L2_PIX_FMT_SBGGR8:
1048 case V4L2_PIX_FMT_SGBRG8:
1049 case V4L2_PIX_FMT_SGRBG8:
1050 case V4L2_PIX_FMT_SRGGB8:
1051 return buf_line & 1;
1052 default:
1053 return 0;
Hans Verkuil63881df2014-08-25 08:02:14 -03001054 }
1055}
1056
1057/* Return how many pattern lines are used by the current pattern. */
Hans Verkuil1a05d312015-03-07 12:49:57 -03001058static unsigned tpg_get_pat_lines(const struct tpg_data *tpg)
Hans Verkuil63881df2014-08-25 08:02:14 -03001059{
1060 switch (tpg->pattern) {
1061 case TPG_PAT_CHECKERS_16X16:
Hans Verkuil1a05d312015-03-07 12:49:57 -03001062 case TPG_PAT_CHECKERS_2X2:
Hans Verkuil63881df2014-08-25 08:02:14 -03001063 case TPG_PAT_CHECKERS_1X1:
Hans Verkuil1a05d312015-03-07 12:49:57 -03001064 case TPG_PAT_COLOR_CHECKERS_2X2:
1065 case TPG_PAT_COLOR_CHECKERS_1X1:
Hans Verkuil63881df2014-08-25 08:02:14 -03001066 case TPG_PAT_ALTERNATING_HLINES:
1067 case TPG_PAT_CROSS_1_PIXEL:
1068 case TPG_PAT_CROSS_2_PIXELS:
1069 case TPG_PAT_CROSS_10_PIXELS:
1070 return 2;
1071 case TPG_PAT_100_COLORSQUARES:
1072 case TPG_PAT_100_HCOLORBAR:
1073 return 8;
1074 default:
1075 return 1;
1076 }
1077}
1078
1079/* Which pattern line should be used for the given frame line. */
Hans Verkuil1a05d312015-03-07 12:49:57 -03001080static unsigned tpg_get_pat_line(const struct tpg_data *tpg, unsigned line)
Hans Verkuil63881df2014-08-25 08:02:14 -03001081{
1082 switch (tpg->pattern) {
1083 case TPG_PAT_CHECKERS_16X16:
1084 return (line >> 4) & 1;
1085 case TPG_PAT_CHECKERS_1X1:
Hans Verkuil1a05d312015-03-07 12:49:57 -03001086 case TPG_PAT_COLOR_CHECKERS_1X1:
Hans Verkuil63881df2014-08-25 08:02:14 -03001087 case TPG_PAT_ALTERNATING_HLINES:
1088 return line & 1;
Hans Verkuil1a05d312015-03-07 12:49:57 -03001089 case TPG_PAT_CHECKERS_2X2:
1090 case TPG_PAT_COLOR_CHECKERS_2X2:
1091 return (line & 2) >> 1;
Hans Verkuil63881df2014-08-25 08:02:14 -03001092 case TPG_PAT_100_COLORSQUARES:
1093 case TPG_PAT_100_HCOLORBAR:
1094 return (line * 8) / tpg->src_height;
1095 case TPG_PAT_CROSS_1_PIXEL:
1096 return line == tpg->src_height / 2;
1097 case TPG_PAT_CROSS_2_PIXELS:
1098 return (line + 1) / 2 == tpg->src_height / 4;
1099 case TPG_PAT_CROSS_10_PIXELS:
1100 return (line + 10) / 20 == tpg->src_height / 40;
1101 default:
1102 return 0;
1103 }
1104}
1105
1106/*
1107 * Which color should be used for the given pattern line and X coordinate.
1108 * Note: x is in the range 0 to 2 * tpg->src_width.
1109 */
Hans Verkuil1a05d312015-03-07 12:49:57 -03001110static enum tpg_color tpg_get_color(const struct tpg_data *tpg,
1111 unsigned pat_line, unsigned x)
Hans Verkuil63881df2014-08-25 08:02:14 -03001112{
1113 /* Maximum number of bars are TPG_COLOR_MAX - otherwise, the input print code
1114 should be modified */
1115 static const enum tpg_color bars[3][8] = {
1116 /* Standard ITU-R 75% color bar sequence */
1117 { TPG_COLOR_CSC_WHITE, TPG_COLOR_75_YELLOW,
1118 TPG_COLOR_75_CYAN, TPG_COLOR_75_GREEN,
1119 TPG_COLOR_75_MAGENTA, TPG_COLOR_75_RED,
1120 TPG_COLOR_75_BLUE, TPG_COLOR_100_BLACK, },
1121 /* Standard ITU-R 100% color bar sequence */
1122 { TPG_COLOR_100_WHITE, TPG_COLOR_100_YELLOW,
1123 TPG_COLOR_100_CYAN, TPG_COLOR_100_GREEN,
1124 TPG_COLOR_100_MAGENTA, TPG_COLOR_100_RED,
1125 TPG_COLOR_100_BLUE, TPG_COLOR_100_BLACK, },
1126 /* Color bar sequence suitable to test CSC */
1127 { TPG_COLOR_CSC_WHITE, TPG_COLOR_CSC_YELLOW,
1128 TPG_COLOR_CSC_CYAN, TPG_COLOR_CSC_GREEN,
1129 TPG_COLOR_CSC_MAGENTA, TPG_COLOR_CSC_RED,
1130 TPG_COLOR_CSC_BLUE, TPG_COLOR_CSC_BLACK, },
1131 };
1132
1133 switch (tpg->pattern) {
1134 case TPG_PAT_75_COLORBAR:
1135 case TPG_PAT_100_COLORBAR:
1136 case TPG_PAT_CSC_COLORBAR:
1137 return bars[tpg->pattern][((x * 8) / tpg->src_width) % 8];
1138 case TPG_PAT_100_COLORSQUARES:
1139 return bars[1][(pat_line + (x * 8) / tpg->src_width) % 8];
1140 case TPG_PAT_100_HCOLORBAR:
1141 return bars[1][pat_line];
1142 case TPG_PAT_BLACK:
1143 return TPG_COLOR_100_BLACK;
1144 case TPG_PAT_WHITE:
1145 return TPG_COLOR_100_WHITE;
1146 case TPG_PAT_RED:
1147 return TPG_COLOR_100_RED;
1148 case TPG_PAT_GREEN:
1149 return TPG_COLOR_100_GREEN;
1150 case TPG_PAT_BLUE:
1151 return TPG_COLOR_100_BLUE;
1152 case TPG_PAT_CHECKERS_16X16:
1153 return (((x >> 4) & 1) ^ (pat_line & 1)) ?
1154 TPG_COLOR_100_BLACK : TPG_COLOR_100_WHITE;
1155 case TPG_PAT_CHECKERS_1X1:
1156 return ((x & 1) ^ (pat_line & 1)) ?
1157 TPG_COLOR_100_WHITE : TPG_COLOR_100_BLACK;
Hans Verkuil1a05d312015-03-07 12:49:57 -03001158 case TPG_PAT_COLOR_CHECKERS_1X1:
1159 return ((x & 1) ^ (pat_line & 1)) ?
1160 TPG_COLOR_100_RED : TPG_COLOR_100_BLUE;
1161 case TPG_PAT_CHECKERS_2X2:
1162 return (((x >> 1) & 1) ^ (pat_line & 1)) ?
1163 TPG_COLOR_100_WHITE : TPG_COLOR_100_BLACK;
1164 case TPG_PAT_COLOR_CHECKERS_2X2:
1165 return (((x >> 1) & 1) ^ (pat_line & 1)) ?
1166 TPG_COLOR_100_RED : TPG_COLOR_100_BLUE;
Hans Verkuil63881df2014-08-25 08:02:14 -03001167 case TPG_PAT_ALTERNATING_HLINES:
1168 return pat_line ? TPG_COLOR_100_WHITE : TPG_COLOR_100_BLACK;
1169 case TPG_PAT_ALTERNATING_VLINES:
1170 return (x & 1) ? TPG_COLOR_100_WHITE : TPG_COLOR_100_BLACK;
1171 case TPG_PAT_CROSS_1_PIXEL:
1172 if (pat_line || (x % tpg->src_width) == tpg->src_width / 2)
1173 return TPG_COLOR_100_BLACK;
1174 return TPG_COLOR_100_WHITE;
1175 case TPG_PAT_CROSS_2_PIXELS:
1176 if (pat_line || ((x % tpg->src_width) + 1) / 2 == tpg->src_width / 4)
1177 return TPG_COLOR_100_BLACK;
1178 return TPG_COLOR_100_WHITE;
1179 case TPG_PAT_CROSS_10_PIXELS:
1180 if (pat_line || ((x % tpg->src_width) + 10) / 20 == tpg->src_width / 40)
1181 return TPG_COLOR_100_BLACK;
1182 return TPG_COLOR_100_WHITE;
1183 case TPG_PAT_GRAY_RAMP:
1184 return TPG_COLOR_RAMP + ((x % tpg->src_width) * 256) / tpg->src_width;
1185 default:
1186 return TPG_COLOR_100_RED;
1187 }
1188}
1189
1190/*
1191 * Given the pixel aspect ratio and video aspect ratio calculate the
1192 * coordinates of a centered square and the coordinates of the border of
1193 * the active video area. The coordinates are relative to the source
1194 * frame rectangle.
1195 */
1196static void tpg_calculate_square_border(struct tpg_data *tpg)
1197{
1198 unsigned w = tpg->src_width;
1199 unsigned h = tpg->src_height;
1200 unsigned sq_w, sq_h;
1201
1202 sq_w = (w * 2 / 5) & ~1;
1203 if (((w - sq_w) / 2) & 1)
1204 sq_w += 2;
1205 sq_h = sq_w;
1206 tpg->square.width = sq_w;
1207 if (tpg->vid_aspect == TPG_VIDEO_ASPECT_16X9_ANAMORPHIC) {
1208 unsigned ana_sq_w = (sq_w / 4) * 3;
1209
1210 if (((w - ana_sq_w) / 2) & 1)
1211 ana_sq_w += 2;
1212 tpg->square.width = ana_sq_w;
1213 }
1214 tpg->square.left = (w - tpg->square.width) / 2;
1215 if (tpg->pix_aspect == TPG_PIXEL_ASPECT_NTSC)
1216 sq_h = sq_w * 10 / 11;
1217 else if (tpg->pix_aspect == TPG_PIXEL_ASPECT_PAL)
1218 sq_h = sq_w * 59 / 54;
1219 tpg->square.height = sq_h;
1220 tpg->square.top = (h - sq_h) / 2;
1221 tpg->border.left = 0;
1222 tpg->border.width = w;
1223 tpg->border.top = 0;
1224 tpg->border.height = h;
1225 switch (tpg->vid_aspect) {
1226 case TPG_VIDEO_ASPECT_4X3:
1227 if (tpg->pix_aspect)
1228 return;
1229 if (3 * w >= 4 * h) {
1230 tpg->border.width = ((4 * h) / 3) & ~1;
1231 if (((w - tpg->border.width) / 2) & ~1)
1232 tpg->border.width -= 2;
1233 tpg->border.left = (w - tpg->border.width) / 2;
1234 break;
1235 }
1236 tpg->border.height = ((3 * w) / 4) & ~1;
1237 tpg->border.top = (h - tpg->border.height) / 2;
1238 break;
1239 case TPG_VIDEO_ASPECT_14X9_CENTRE:
1240 if (tpg->pix_aspect) {
1241 tpg->border.height = tpg->pix_aspect == TPG_PIXEL_ASPECT_NTSC ? 420 : 506;
1242 tpg->border.top = (h - tpg->border.height) / 2;
1243 break;
1244 }
1245 if (9 * w >= 14 * h) {
1246 tpg->border.width = ((14 * h) / 9) & ~1;
1247 if (((w - tpg->border.width) / 2) & ~1)
1248 tpg->border.width -= 2;
1249 tpg->border.left = (w - tpg->border.width) / 2;
1250 break;
1251 }
1252 tpg->border.height = ((9 * w) / 14) & ~1;
1253 tpg->border.top = (h - tpg->border.height) / 2;
1254 break;
1255 case TPG_VIDEO_ASPECT_16X9_CENTRE:
1256 if (tpg->pix_aspect) {
1257 tpg->border.height = tpg->pix_aspect == TPG_PIXEL_ASPECT_NTSC ? 368 : 442;
1258 tpg->border.top = (h - tpg->border.height) / 2;
1259 break;
1260 }
1261 if (9 * w >= 16 * h) {
1262 tpg->border.width = ((16 * h) / 9) & ~1;
1263 if (((w - tpg->border.width) / 2) & ~1)
1264 tpg->border.width -= 2;
1265 tpg->border.left = (w - tpg->border.width) / 2;
1266 break;
1267 }
1268 tpg->border.height = ((9 * w) / 16) & ~1;
1269 tpg->border.top = (h - tpg->border.height) / 2;
1270 break;
1271 default:
1272 break;
1273 }
1274}
1275
1276static void tpg_precalculate_line(struct tpg_data *tpg)
1277{
1278 enum tpg_color contrast;
Hans Verkuil9991def2015-03-08 05:53:10 -03001279 u8 pix[TPG_MAX_PLANES][8];
Hans Verkuil63881df2014-08-25 08:02:14 -03001280 unsigned pat;
1281 unsigned p;
1282 unsigned x;
1283
1284 switch (tpg->pattern) {
1285 case TPG_PAT_GREEN:
1286 contrast = TPG_COLOR_100_RED;
1287 break;
1288 case TPG_PAT_CSC_COLORBAR:
1289 contrast = TPG_COLOR_CSC_GREEN;
1290 break;
1291 default:
1292 contrast = TPG_COLOR_100_GREEN;
1293 break;
1294 }
1295
1296 for (pat = 0; pat < tpg_get_pat_lines(tpg); pat++) {
1297 /* Coarse scaling with Bresenham */
1298 unsigned int_part = tpg->src_width / tpg->scaled_width;
1299 unsigned fract_part = tpg->src_width % tpg->scaled_width;
1300 unsigned src_x = 0;
1301 unsigned error = 0;
1302
1303 for (x = 0; x < tpg->scaled_width * 2; x += 2) {
1304 unsigned real_x = src_x;
1305 enum tpg_color color1, color2;
Hans Verkuil63881df2014-08-25 08:02:14 -03001306
1307 real_x = tpg->hflip ? tpg->src_width * 2 - real_x - 2 : real_x;
1308 color1 = tpg_get_color(tpg, pat, real_x);
1309
1310 src_x += int_part;
1311 error += fract_part;
1312 if (error >= tpg->scaled_width) {
1313 error -= tpg->scaled_width;
1314 src_x++;
1315 }
1316
1317 real_x = src_x;
1318 real_x = tpg->hflip ? tpg->src_width * 2 - real_x - 2 : real_x;
1319 color2 = tpg_get_color(tpg, pat, real_x);
1320
1321 src_x += int_part;
1322 error += fract_part;
1323 if (error >= tpg->scaled_width) {
1324 error -= tpg->scaled_width;
1325 src_x++;
1326 }
1327
1328 gen_twopix(tpg, pix, tpg->hflip ? color2 : color1, 0);
1329 gen_twopix(tpg, pix, tpg->hflip ? color1 : color2, 1);
1330 for (p = 0; p < tpg->planes; p++) {
1331 unsigned twopixsize = tpg->twopixelsize[p];
Hans Verkuil5d7c5392015-03-07 14:06:43 -03001332 unsigned hdiv = tpg->hdownsampling[p];
Hans Verkuil9991def2015-03-08 05:53:10 -03001333 u8 *pos = tpg->lines[pat][p] + tpg_hdiv(tpg, p, x);
Hans Verkuil63881df2014-08-25 08:02:14 -03001334
Hans Verkuil5d7c5392015-03-07 14:06:43 -03001335 memcpy(pos, pix[p], twopixsize / hdiv);
Hans Verkuil63881df2014-08-25 08:02:14 -03001336 }
1337 }
1338 }
Hans Verkuil5d7c5392015-03-07 14:06:43 -03001339
1340 if (tpg->vdownsampling[tpg->planes - 1] > 1) {
1341 unsigned pat_lines = tpg_get_pat_lines(tpg);
1342
1343 for (pat = 0; pat < pat_lines; pat++) {
1344 unsigned next_pat = (pat + 1) % pat_lines;
1345
1346 for (p = 1; p < tpg->planes; p++) {
Hans Verkuil9991def2015-03-08 05:53:10 -03001347 unsigned w = tpg_hdiv(tpg, p, tpg->scaled_width * 2);
1348 u8 *pos1 = tpg->lines[pat][p];
1349 u8 *pos2 = tpg->lines[next_pat][p];
1350 u8 *dest = tpg->downsampled_lines[pat][p];
Hans Verkuil5d7c5392015-03-07 14:06:43 -03001351
Hans Verkuil9991def2015-03-08 05:53:10 -03001352 for (x = 0; x < w; x++, pos1++, pos2++, dest++)
1353 *dest = ((u16)*pos1 + (u16)*pos2) / 2;
Hans Verkuil5d7c5392015-03-07 14:06:43 -03001354 }
1355 }
1356 }
1357
Hans Verkuil9991def2015-03-08 05:53:10 -03001358 gen_twopix(tpg, pix, contrast, 0);
1359 gen_twopix(tpg, pix, contrast, 1);
1360 for (p = 0; p < tpg->planes; p++) {
1361 unsigned twopixsize = tpg->twopixelsize[p];
1362 u8 *pos = tpg->contrast_line[p];
Hans Verkuil63881df2014-08-25 08:02:14 -03001363
Hans Verkuil9991def2015-03-08 05:53:10 -03001364 for (x = 0; x < tpg->scaled_width; x += 2, pos += twopixsize)
Hans Verkuil63881df2014-08-25 08:02:14 -03001365 memcpy(pos, pix[p], twopixsize);
Hans Verkuil63881df2014-08-25 08:02:14 -03001366 }
Hans Verkuil63881df2014-08-25 08:02:14 -03001367
Hans Verkuil9991def2015-03-08 05:53:10 -03001368 gen_twopix(tpg, pix, TPG_COLOR_100_BLACK, 0);
1369 gen_twopix(tpg, pix, TPG_COLOR_100_BLACK, 1);
1370 for (p = 0; p < tpg->planes; p++) {
1371 unsigned twopixsize = tpg->twopixelsize[p];
1372 u8 *pos = tpg->black_line[p];
Hans Verkuil63881df2014-08-25 08:02:14 -03001373
Hans Verkuil9991def2015-03-08 05:53:10 -03001374 for (x = 0; x < tpg->scaled_width; x += 2, pos += twopixsize)
Hans Verkuil63881df2014-08-25 08:02:14 -03001375 memcpy(pos, pix[p], twopixsize);
Hans Verkuil63881df2014-08-25 08:02:14 -03001376 }
Hans Verkuil9991def2015-03-08 05:53:10 -03001377
Hans Verkuil63881df2014-08-25 08:02:14 -03001378 for (x = 0; x < tpg->scaled_width * 2; x += 2) {
Hans Verkuil63881df2014-08-25 08:02:14 -03001379 gen_twopix(tpg, pix, TPG_COLOR_RANDOM, 0);
1380 gen_twopix(tpg, pix, TPG_COLOR_RANDOM, 1);
1381 for (p = 0; p < tpg->planes; p++) {
1382 unsigned twopixsize = tpg->twopixelsize[p];
1383 u8 *pos = tpg->random_line[p] + x * twopixsize / 2;
1384
1385 memcpy(pos, pix[p], twopixsize);
1386 }
1387 }
Hans Verkuil9991def2015-03-08 05:53:10 -03001388
Hans Verkuil63881df2014-08-25 08:02:14 -03001389 gen_twopix(tpg, tpg->textbg, TPG_COLOR_TEXTBG, 0);
1390 gen_twopix(tpg, tpg->textbg, TPG_COLOR_TEXTBG, 1);
1391 gen_twopix(tpg, tpg->textfg, TPG_COLOR_TEXTFG, 0);
1392 gen_twopix(tpg, tpg->textfg, TPG_COLOR_TEXTFG, 1);
1393}
1394
1395/* need this to do rgb24 rendering */
1396typedef struct { u16 __; u8 _; } __packed x24;
1397
Hans Verkuildfff0482015-03-09 11:04:02 -03001398void tpg_gen_text(const struct tpg_data *tpg, u8 *basep[TPG_MAX_PLANES][2],
1399 int y, int x, char *text)
Hans Verkuil63881df2014-08-25 08:02:14 -03001400{
1401 int line;
1402 unsigned step = V4L2_FIELD_HAS_T_OR_B(tpg->field) ? 2 : 1;
1403 unsigned div = step;
1404 unsigned first = 0;
1405 unsigned len = strlen(text);
1406 unsigned p;
1407
1408 if (font8x16 == NULL || basep == NULL)
1409 return;
1410
1411 /* Checks if it is possible to show string */
1412 if (y + 16 >= tpg->compose.height || x + 8 >= tpg->compose.width)
1413 return;
1414
1415 if (len > (tpg->compose.width - x) / 8)
1416 len = (tpg->compose.width - x) / 8;
1417 if (tpg->vflip)
1418 y = tpg->compose.height - y - 16;
1419 if (tpg->hflip)
1420 x = tpg->compose.width - x - 8;
1421 y += tpg->compose.top;
1422 x += tpg->compose.left;
1423 if (tpg->field == V4L2_FIELD_BOTTOM)
1424 first = 1;
1425 else if (tpg->field == V4L2_FIELD_SEQ_TB || tpg->field == V4L2_FIELD_SEQ_BT)
1426 div = 2;
1427
1428 for (p = 0; p < tpg->planes; p++) {
Hans Verkuil3e14e7a82015-03-07 14:23:16 -03001429 unsigned vdiv = tpg->vdownsampling[p];
1430 unsigned hdiv = tpg->hdownsampling[p];
1431
1432 /* Print text */
Hans Verkuil63881df2014-08-25 08:02:14 -03001433#define PRINTSTR(PIXTYPE) do { \
1434 PIXTYPE fg; \
1435 PIXTYPE bg; \
1436 memcpy(&fg, tpg->textfg[p], sizeof(PIXTYPE)); \
1437 memcpy(&bg, tpg->textbg[p], sizeof(PIXTYPE)); \
1438 \
Hans Verkuil3e14e7a82015-03-07 14:23:16 -03001439 for (line = first; line < 16; line += vdiv * step) { \
Hans Verkuil63881df2014-08-25 08:02:14 -03001440 int l = tpg->vflip ? 15 - line : line; \
Hans Verkuil3e14e7a82015-03-07 14:23:16 -03001441 PIXTYPE *pos = (PIXTYPE *)(basep[p][(line / vdiv) & 1] + \
1442 ((y * step + l) / (vdiv * div)) * tpg->bytesperline[p] + \
1443 (x / hdiv) * sizeof(PIXTYPE)); \
Hans Verkuil63881df2014-08-25 08:02:14 -03001444 unsigned s; \
1445 \
1446 for (s = 0; s < len; s++) { \
1447 u8 chr = font8x16[text[s] * 16 + line]; \
1448 \
Hans Verkuil3e14e7a82015-03-07 14:23:16 -03001449 if (hdiv == 2 && tpg->hflip) { \
1450 pos[3] = (chr & (0x01 << 6) ? fg : bg); \
1451 pos[2] = (chr & (0x01 << 4) ? fg : bg); \
1452 pos[1] = (chr & (0x01 << 2) ? fg : bg); \
1453 pos[0] = (chr & (0x01 << 0) ? fg : bg); \
1454 } else if (hdiv == 2) { \
1455 pos[0] = (chr & (0x01 << 7) ? fg : bg); \
1456 pos[1] = (chr & (0x01 << 5) ? fg : bg); \
1457 pos[2] = (chr & (0x01 << 3) ? fg : bg); \
1458 pos[3] = (chr & (0x01 << 1) ? fg : bg); \
1459 } else if (tpg->hflip) { \
Hans Verkuil63881df2014-08-25 08:02:14 -03001460 pos[7] = (chr & (0x01 << 7) ? fg : bg); \
1461 pos[6] = (chr & (0x01 << 6) ? fg : bg); \
1462 pos[5] = (chr & (0x01 << 5) ? fg : bg); \
1463 pos[4] = (chr & (0x01 << 4) ? fg : bg); \
1464 pos[3] = (chr & (0x01 << 3) ? fg : bg); \
1465 pos[2] = (chr & (0x01 << 2) ? fg : bg); \
1466 pos[1] = (chr & (0x01 << 1) ? fg : bg); \
1467 pos[0] = (chr & (0x01 << 0) ? fg : bg); \
1468 } else { \
1469 pos[0] = (chr & (0x01 << 7) ? fg : bg); \
1470 pos[1] = (chr & (0x01 << 6) ? fg : bg); \
1471 pos[2] = (chr & (0x01 << 5) ? fg : bg); \
1472 pos[3] = (chr & (0x01 << 4) ? fg : bg); \
1473 pos[4] = (chr & (0x01 << 3) ? fg : bg); \
1474 pos[5] = (chr & (0x01 << 2) ? fg : bg); \
1475 pos[6] = (chr & (0x01 << 1) ? fg : bg); \
1476 pos[7] = (chr & (0x01 << 0) ? fg : bg); \
1477 } \
1478 \
Hans Verkuil3e14e7a82015-03-07 14:23:16 -03001479 pos += (tpg->hflip ? -8 : 8) / hdiv; \
Hans Verkuil63881df2014-08-25 08:02:14 -03001480 } \
1481 } \
1482} while (0)
1483
1484 switch (tpg->twopixelsize[p]) {
1485 case 2:
1486 PRINTSTR(u8); break;
1487 case 4:
1488 PRINTSTR(u16); break;
1489 case 6:
1490 PRINTSTR(x24); break;
1491 case 8:
1492 PRINTSTR(u32); break;
1493 }
1494 }
1495}
1496
1497void tpg_update_mv_step(struct tpg_data *tpg)
1498{
1499 int factor = tpg->mv_hor_mode > TPG_MOVE_NONE ? -1 : 1;
1500
1501 if (tpg->hflip)
1502 factor = -factor;
1503 switch (tpg->mv_hor_mode) {
1504 case TPG_MOVE_NEG_FAST:
1505 case TPG_MOVE_POS_FAST:
1506 tpg->mv_hor_step = ((tpg->src_width + 319) / 320) * 4;
1507 break;
1508 case TPG_MOVE_NEG:
1509 case TPG_MOVE_POS:
1510 tpg->mv_hor_step = ((tpg->src_width + 639) / 640) * 4;
1511 break;
1512 case TPG_MOVE_NEG_SLOW:
1513 case TPG_MOVE_POS_SLOW:
1514 tpg->mv_hor_step = 2;
1515 break;
1516 case TPG_MOVE_NONE:
1517 tpg->mv_hor_step = 0;
1518 break;
1519 }
1520 if (factor < 0)
1521 tpg->mv_hor_step = tpg->src_width - tpg->mv_hor_step;
1522
1523 factor = tpg->mv_vert_mode > TPG_MOVE_NONE ? -1 : 1;
1524 switch (tpg->mv_vert_mode) {
1525 case TPG_MOVE_NEG_FAST:
1526 case TPG_MOVE_POS_FAST:
1527 tpg->mv_vert_step = ((tpg->src_width + 319) / 320) * 4;
1528 break;
1529 case TPG_MOVE_NEG:
1530 case TPG_MOVE_POS:
1531 tpg->mv_vert_step = ((tpg->src_width + 639) / 640) * 4;
1532 break;
1533 case TPG_MOVE_NEG_SLOW:
1534 case TPG_MOVE_POS_SLOW:
1535 tpg->mv_vert_step = 1;
1536 break;
1537 case TPG_MOVE_NONE:
1538 tpg->mv_vert_step = 0;
1539 break;
1540 }
1541 if (factor < 0)
1542 tpg->mv_vert_step = tpg->src_height - tpg->mv_vert_step;
1543}
1544
1545/* Map the line number relative to the crop rectangle to a frame line number */
Hans Verkuildfff0482015-03-09 11:04:02 -03001546static unsigned tpg_calc_frameline(const struct tpg_data *tpg, unsigned src_y,
Hans Verkuil63881df2014-08-25 08:02:14 -03001547 unsigned field)
1548{
1549 switch (field) {
1550 case V4L2_FIELD_TOP:
1551 return tpg->crop.top + src_y * 2;
1552 case V4L2_FIELD_BOTTOM:
1553 return tpg->crop.top + src_y * 2 + 1;
1554 default:
1555 return src_y + tpg->crop.top;
1556 }
1557}
1558
1559/*
1560 * Map the line number relative to the compose rectangle to a destination
1561 * buffer line number.
1562 */
Hans Verkuildfff0482015-03-09 11:04:02 -03001563static unsigned tpg_calc_buffer_line(const struct tpg_data *tpg, unsigned y,
Hans Verkuil63881df2014-08-25 08:02:14 -03001564 unsigned field)
1565{
1566 y += tpg->compose.top;
1567 switch (field) {
1568 case V4L2_FIELD_SEQ_TB:
1569 if (y & 1)
1570 return tpg->buf_height / 2 + y / 2;
1571 return y / 2;
1572 case V4L2_FIELD_SEQ_BT:
1573 if (y & 1)
1574 return y / 2;
1575 return tpg->buf_height / 2 + y / 2;
1576 default:
1577 return y;
1578 }
1579}
1580
1581static void tpg_recalc(struct tpg_data *tpg)
1582{
1583 if (tpg->recalc_colors) {
1584 tpg->recalc_colors = false;
1585 tpg->recalc_lines = true;
Hans Verkuil481b97a2014-11-17 10:14:32 -03001586 tpg->real_ycbcr_enc = tpg->ycbcr_enc;
1587 tpg->real_quantization = tpg->quantization;
1588 if (tpg->ycbcr_enc == V4L2_YCBCR_ENC_DEFAULT) {
1589 switch (tpg->colorspace) {
1590 case V4L2_COLORSPACE_REC709:
1591 tpg->real_ycbcr_enc = V4L2_YCBCR_ENC_709;
1592 break;
1593 case V4L2_COLORSPACE_SRGB:
1594 tpg->real_ycbcr_enc = V4L2_YCBCR_ENC_SYCC;
1595 break;
1596 case V4L2_COLORSPACE_BT2020:
1597 tpg->real_ycbcr_enc = V4L2_YCBCR_ENC_BT2020;
1598 break;
1599 case V4L2_COLORSPACE_SMPTE240M:
1600 tpg->real_ycbcr_enc = V4L2_YCBCR_ENC_SMPTE240M;
1601 break;
1602 case V4L2_COLORSPACE_SMPTE170M:
1603 case V4L2_COLORSPACE_470_SYSTEM_M:
1604 case V4L2_COLORSPACE_470_SYSTEM_BG:
1605 case V4L2_COLORSPACE_ADOBERGB:
1606 default:
1607 tpg->real_ycbcr_enc = V4L2_YCBCR_ENC_601;
1608 break;
1609 }
1610 }
1611 if (tpg->quantization == V4L2_QUANTIZATION_DEFAULT) {
1612 tpg->real_quantization = V4L2_QUANTIZATION_FULL_RANGE;
1613 if (tpg->is_yuv) {
1614 switch (tpg->real_ycbcr_enc) {
1615 case V4L2_YCBCR_ENC_SYCC:
1616 case V4L2_YCBCR_ENC_XV601:
1617 case V4L2_YCBCR_ENC_XV709:
1618 break;
1619 default:
1620 tpg->real_quantization =
1621 V4L2_QUANTIZATION_LIM_RANGE;
1622 break;
1623 }
Hans Verkuilc0b50d92015-03-08 04:53:33 -03001624 } else if (tpg->colorspace == V4L2_COLORSPACE_BT2020) {
1625 /* R'G'B' BT.2020 is limited range */
1626 tpg->real_quantization =
1627 V4L2_QUANTIZATION_LIM_RANGE;
Hans Verkuil481b97a2014-11-17 10:14:32 -03001628 }
1629 }
Hans Verkuil63881df2014-08-25 08:02:14 -03001630 tpg_precalculate_colors(tpg);
1631 }
1632 if (tpg->recalc_square_border) {
1633 tpg->recalc_square_border = false;
1634 tpg_calculate_square_border(tpg);
1635 }
1636 if (tpg->recalc_lines) {
1637 tpg->recalc_lines = false;
1638 tpg_precalculate_line(tpg);
1639 }
1640}
1641
1642void tpg_calc_text_basep(struct tpg_data *tpg,
1643 u8 *basep[TPG_MAX_PLANES][2], unsigned p, u8 *vbuf)
1644{
1645 unsigned stride = tpg->bytesperline[p];
Hans Verkuil280abe42015-03-07 14:50:41 -03001646 unsigned h = tpg->buf_height;
Hans Verkuil63881df2014-08-25 08:02:14 -03001647
1648 tpg_recalc(tpg);
1649
1650 basep[p][0] = vbuf;
1651 basep[p][1] = vbuf;
Hans Verkuil280abe42015-03-07 14:50:41 -03001652 h /= tpg->vdownsampling[p];
Hans Verkuil63881df2014-08-25 08:02:14 -03001653 if (tpg->field == V4L2_FIELD_SEQ_TB)
Hans Verkuil280abe42015-03-07 14:50:41 -03001654 basep[p][1] += h * stride / 2;
Hans Verkuil63881df2014-08-25 08:02:14 -03001655 else if (tpg->field == V4L2_FIELD_SEQ_BT)
Hans Verkuil280abe42015-03-07 14:50:41 -03001656 basep[p][0] += h * stride / 2;
Hans Verkuil02aa7692015-03-14 08:01:50 -03001657 if (p == 0 && tpg->interleaved)
1658 tpg_calc_text_basep(tpg, basep, 1, vbuf);
Hans Verkuil280abe42015-03-07 14:50:41 -03001659}
1660
1661static int tpg_pattern_avg(const struct tpg_data *tpg,
1662 unsigned pat1, unsigned pat2)
1663{
1664 unsigned pat_lines = tpg_get_pat_lines(tpg);
1665
1666 if (pat1 == (pat2 + 1) % pat_lines)
1667 return pat2;
1668 if (pat2 == (pat1 + 1) % pat_lines)
1669 return pat1;
1670 return -1;
Hans Verkuil63881df2014-08-25 08:02:14 -03001671}
1672
Hans Verkuile76036d2015-03-09 11:07:23 -03001673/*
1674 * This struct contains common parameters used by both the drawing of the
1675 * test pattern and the drawing of the extras (borders, square, etc.)
1676 */
1677struct tpg_draw_params {
1678 /* common data */
1679 bool is_tv;
1680 bool is_60hz;
1681 unsigned twopixsize;
1682 unsigned img_width;
1683 unsigned stride;
1684 unsigned hmax;
1685 unsigned frame_line;
1686 unsigned frame_line_next;
1687
1688 /* test pattern */
1689 unsigned mv_hor_old;
1690 unsigned mv_hor_new;
1691 unsigned mv_vert_old;
1692 unsigned mv_vert_new;
1693
1694 /* extras */
1695 unsigned wss_width;
1696 unsigned wss_random_offset;
1697 unsigned sav_eav_f;
1698 unsigned left_pillar_width;
1699 unsigned right_pillar_start;
1700};
1701
Hans Verkuilf0ce4fd2015-03-09 11:30:05 -03001702static void tpg_fill_params_pattern(const struct tpg_data *tpg, unsigned p,
1703 struct tpg_draw_params *params)
1704{
1705 params->mv_hor_old =
1706 tpg_hscale_div(tpg, p, tpg->mv_hor_count % tpg->src_width);
1707 params->mv_hor_new =
1708 tpg_hscale_div(tpg, p, (tpg->mv_hor_count + tpg->mv_hor_step) %
1709 tpg->src_width);
1710 params->mv_vert_old = tpg->mv_vert_count % tpg->src_height;
1711 params->mv_vert_new =
1712 (tpg->mv_vert_count + tpg->mv_vert_step) % tpg->src_height;
1713}
1714
Hans Verkuil07386b92015-03-09 11:39:19 -03001715static void tpg_fill_params_extras(const struct tpg_data *tpg,
1716 unsigned p,
1717 struct tpg_draw_params *params)
1718{
1719 unsigned left_pillar_width = 0;
1720 unsigned right_pillar_start = params->img_width;
1721
1722 params->wss_width = tpg->crop.left < tpg->src_width / 2 ?
1723 tpg->src_width / 2 - tpg->crop.left : 0;
1724 if (params->wss_width > tpg->crop.width)
1725 params->wss_width = tpg->crop.width;
1726 params->wss_width = tpg_hscale_div(tpg, p, params->wss_width);
1727 params->wss_random_offset =
1728 params->twopixsize * prandom_u32_max(tpg->src_width / 2);
1729
1730 if (tpg->crop.left < tpg->border.left) {
1731 left_pillar_width = tpg->border.left - tpg->crop.left;
1732 if (left_pillar_width > tpg->crop.width)
1733 left_pillar_width = tpg->crop.width;
1734 left_pillar_width = tpg_hscale_div(tpg, p, left_pillar_width);
1735 }
1736 params->left_pillar_width = left_pillar_width;
1737
1738 if (tpg->crop.left + tpg->crop.width >
1739 tpg->border.left + tpg->border.width) {
1740 right_pillar_start =
1741 tpg->border.left + tpg->border.width - tpg->crop.left;
1742 right_pillar_start =
1743 tpg_hscale_div(tpg, p, right_pillar_start);
1744 if (right_pillar_start > params->img_width)
1745 right_pillar_start = params->img_width;
1746 }
1747 params->right_pillar_start = right_pillar_start;
1748
1749 params->sav_eav_f = tpg->field ==
1750 (params->is_60hz ? V4L2_FIELD_TOP : V4L2_FIELD_BOTTOM);
1751}
1752
Hans Verkuilc6ff1c12015-03-09 11:47:48 -03001753static void tpg_fill_plane_extras(const struct tpg_data *tpg,
1754 const struct tpg_draw_params *params,
1755 unsigned p, unsigned h, u8 *vbuf)
1756{
1757 unsigned twopixsize = params->twopixsize;
1758 unsigned img_width = params->img_width;
1759 unsigned frame_line = params->frame_line;
1760 const struct v4l2_rect *sq = &tpg->square;
1761 const struct v4l2_rect *b = &tpg->border;
1762 const struct v4l2_rect *c = &tpg->crop;
1763
1764 if (params->is_tv && !params->is_60hz &&
1765 frame_line == 0 && params->wss_width) {
1766 /*
1767 * Replace the first half of the top line of a 50 Hz frame
1768 * with random data to simulate a WSS signal.
1769 */
1770 u8 *wss = tpg->random_line[p] + params->wss_random_offset;
1771
1772 memcpy(vbuf, wss, params->wss_width);
1773 }
1774
1775 if (tpg->show_border && frame_line >= b->top &&
1776 frame_line < b->top + b->height) {
1777 unsigned bottom = b->top + b->height - 1;
1778 unsigned left = params->left_pillar_width;
1779 unsigned right = params->right_pillar_start;
1780
1781 if (frame_line == b->top || frame_line == b->top + 1 ||
1782 frame_line == bottom || frame_line == bottom - 1) {
1783 memcpy(vbuf + left, tpg->contrast_line[p],
1784 right - left);
1785 } else {
1786 if (b->left >= c->left &&
1787 b->left < c->left + c->width)
1788 memcpy(vbuf + left,
1789 tpg->contrast_line[p], twopixsize);
1790 if (b->left + b->width > c->left &&
1791 b->left + b->width <= c->left + c->width)
1792 memcpy(vbuf + right - twopixsize,
1793 tpg->contrast_line[p], twopixsize);
1794 }
1795 }
1796 if (tpg->qual != TPG_QUAL_NOISE && frame_line >= b->top &&
1797 frame_line < b->top + b->height) {
1798 memcpy(vbuf, tpg->black_line[p], params->left_pillar_width);
1799 memcpy(vbuf + params->right_pillar_start, tpg->black_line[p],
1800 img_width - params->right_pillar_start);
1801 }
1802 if (tpg->show_square && frame_line >= sq->top &&
1803 frame_line < sq->top + sq->height &&
1804 sq->left < c->left + c->width &&
1805 sq->left + sq->width >= c->left) {
1806 unsigned left = sq->left;
1807 unsigned width = sq->width;
1808
1809 if (c->left > left) {
1810 width -= c->left - left;
1811 left = c->left;
1812 }
1813 if (c->left + c->width < left + width)
1814 width -= left + width - c->left - c->width;
1815 left -= c->left;
1816 left = tpg_hscale_div(tpg, p, left);
1817 width = tpg_hscale_div(tpg, p, width);
1818 memcpy(vbuf + left, tpg->contrast_line[p], width);
1819 }
1820 if (tpg->insert_sav) {
1821 unsigned offset = tpg_hdiv(tpg, p, tpg->compose.width / 3);
1822 u8 *p = vbuf + offset;
1823 unsigned vact = 0, hact = 0;
1824
1825 p[0] = 0xff;
1826 p[1] = 0;
1827 p[2] = 0;
1828 p[3] = 0x80 | (params->sav_eav_f << 6) |
1829 (vact << 5) | (hact << 4) |
1830 ((hact ^ vact) << 3) |
1831 ((hact ^ params->sav_eav_f) << 2) |
1832 ((params->sav_eav_f ^ vact) << 1) |
1833 (hact ^ vact ^ params->sav_eav_f);
1834 }
1835 if (tpg->insert_eav) {
1836 unsigned offset = tpg_hdiv(tpg, p, tpg->compose.width * 2 / 3);
1837 u8 *p = vbuf + offset;
1838 unsigned vact = 0, hact = 1;
1839
1840 p[0] = 0xff;
1841 p[1] = 0;
1842 p[2] = 0;
1843 p[3] = 0x80 | (params->sav_eav_f << 6) |
1844 (vact << 5) | (hact << 4) |
1845 ((hact ^ vact) << 3) |
1846 ((hact ^ params->sav_eav_f) << 2) |
1847 ((params->sav_eav_f ^ vact) << 1) |
1848 (hact ^ vact ^ params->sav_eav_f);
1849 }
1850}
1851
Hans Verkuilecb9e912015-03-09 11:52:43 -03001852static void tpg_fill_plane_pattern(const struct tpg_data *tpg,
1853 const struct tpg_draw_params *params,
1854 unsigned p, unsigned h, u8 *vbuf)
1855{
1856 unsigned twopixsize = params->twopixsize;
1857 unsigned img_width = params->img_width;
1858 unsigned mv_hor_old = params->mv_hor_old;
1859 unsigned mv_hor_new = params->mv_hor_new;
1860 unsigned mv_vert_old = params->mv_vert_old;
1861 unsigned mv_vert_new = params->mv_vert_new;
1862 unsigned frame_line = params->frame_line;
1863 unsigned frame_line_next = params->frame_line_next;
1864 unsigned line_offset = tpg_hscale_div(tpg, p, tpg->crop.left);
1865 bool even;
1866 bool fill_blank = false;
1867 unsigned pat_line_old;
1868 unsigned pat_line_new;
1869 u8 *linestart_older;
1870 u8 *linestart_newer;
1871 u8 *linestart_top;
1872 u8 *linestart_bottom;
1873
1874 even = !(frame_line & 1);
1875
1876 if (h >= params->hmax) {
1877 if (params->hmax == tpg->compose.height)
1878 return;
1879 if (!tpg->perc_fill_blank)
1880 return;
1881 fill_blank = true;
1882 }
1883
1884 if (tpg->vflip) {
1885 frame_line = tpg->src_height - frame_line - 1;
1886 frame_line_next = tpg->src_height - frame_line_next - 1;
1887 }
1888
1889 if (fill_blank) {
1890 linestart_older = tpg->contrast_line[p];
1891 linestart_newer = tpg->contrast_line[p];
1892 } else if (tpg->qual != TPG_QUAL_NOISE &&
1893 (frame_line < tpg->border.top ||
1894 frame_line >= tpg->border.top + tpg->border.height)) {
1895 linestart_older = tpg->black_line[p];
1896 linestart_newer = tpg->black_line[p];
1897 } else if (tpg->pattern == TPG_PAT_NOISE || tpg->qual == TPG_QUAL_NOISE) {
1898 linestart_older = tpg->random_line[p] +
1899 twopixsize * prandom_u32_max(tpg->src_width / 2);
1900 linestart_newer = tpg->random_line[p] +
1901 twopixsize * prandom_u32_max(tpg->src_width / 2);
1902 } else {
1903 unsigned frame_line_old =
1904 (frame_line + mv_vert_old) % tpg->src_height;
1905 unsigned frame_line_new =
1906 (frame_line + mv_vert_new) % tpg->src_height;
1907 unsigned pat_line_next_old;
1908 unsigned pat_line_next_new;
1909
1910 pat_line_old = tpg_get_pat_line(tpg, frame_line_old);
1911 pat_line_new = tpg_get_pat_line(tpg, frame_line_new);
1912 linestart_older = tpg->lines[pat_line_old][p] + mv_hor_old;
1913 linestart_newer = tpg->lines[pat_line_new][p] + mv_hor_new;
1914
1915 if (tpg->vdownsampling[p] > 1 && frame_line != frame_line_next) {
1916 int avg_pat;
1917
1918 /*
1919 * Now decide whether we need to use downsampled_lines[].
1920 * That's necessary if the two lines use different patterns.
1921 */
1922 pat_line_next_old = tpg_get_pat_line(tpg,
1923 (frame_line_next + mv_vert_old) % tpg->src_height);
1924 pat_line_next_new = tpg_get_pat_line(tpg,
1925 (frame_line_next + mv_vert_new) % tpg->src_height);
1926
1927 switch (tpg->field) {
1928 case V4L2_FIELD_INTERLACED:
1929 case V4L2_FIELD_INTERLACED_BT:
1930 case V4L2_FIELD_INTERLACED_TB:
1931 avg_pat = tpg_pattern_avg(tpg, pat_line_old, pat_line_new);
1932 if (avg_pat < 0)
1933 break;
1934 linestart_older = tpg->downsampled_lines[avg_pat][p] + mv_hor_old;
1935 linestart_newer = linestart_older;
1936 break;
1937 case V4L2_FIELD_NONE:
1938 case V4L2_FIELD_TOP:
1939 case V4L2_FIELD_BOTTOM:
1940 case V4L2_FIELD_SEQ_BT:
1941 case V4L2_FIELD_SEQ_TB:
1942 avg_pat = tpg_pattern_avg(tpg, pat_line_old, pat_line_next_old);
1943 if (avg_pat >= 0)
1944 linestart_older = tpg->downsampled_lines[avg_pat][p] +
1945 mv_hor_old;
1946 avg_pat = tpg_pattern_avg(tpg, pat_line_new, pat_line_next_new);
1947 if (avg_pat >= 0)
1948 linestart_newer = tpg->downsampled_lines[avg_pat][p] +
1949 mv_hor_new;
1950 break;
1951 }
1952 }
1953 linestart_older += line_offset;
1954 linestart_newer += line_offset;
1955 }
1956 if (tpg->field_alternate) {
1957 linestart_top = linestart_bottom = linestart_older;
1958 } else if (params->is_60hz) {
1959 linestart_top = linestart_newer;
1960 linestart_bottom = linestart_older;
1961 } else {
1962 linestart_top = linestart_older;
1963 linestart_bottom = linestart_newer;
1964 }
1965
1966 switch (tpg->field) {
1967 case V4L2_FIELD_INTERLACED:
1968 case V4L2_FIELD_INTERLACED_TB:
1969 case V4L2_FIELD_SEQ_TB:
1970 case V4L2_FIELD_SEQ_BT:
1971 if (even)
1972 memcpy(vbuf, linestart_top, img_width);
1973 else
1974 memcpy(vbuf, linestart_bottom, img_width);
1975 break;
1976 case V4L2_FIELD_INTERLACED_BT:
1977 if (even)
1978 memcpy(vbuf, linestart_bottom, img_width);
1979 else
1980 memcpy(vbuf, linestart_top, img_width);
1981 break;
1982 case V4L2_FIELD_TOP:
1983 memcpy(vbuf, linestart_top, img_width);
1984 break;
1985 case V4L2_FIELD_BOTTOM:
1986 memcpy(vbuf, linestart_bottom, img_width);
1987 break;
1988 case V4L2_FIELD_NONE:
1989 default:
1990 memcpy(vbuf, linestart_older, img_width);
1991 break;
1992 }
1993}
1994
1995void tpg_fill_plane_buffer(struct tpg_data *tpg, v4l2_std_id std,
1996 unsigned p, u8 *vbuf)
Hans Verkuil63881df2014-08-25 08:02:14 -03001997{
Hans Verkuil5e729392015-03-09 11:26:43 -03001998 struct tpg_draw_params params;
Hans Verkuil63881df2014-08-25 08:02:14 -03001999 unsigned factor = V4L2_FIELD_HAS_T_OR_B(tpg->field) ? 2 : 1;
Hans Verkuil63881df2014-08-25 08:02:14 -03002000
2001 /* Coarse scaling with Bresenham */
2002 unsigned int_part = (tpg->crop.height / factor) / tpg->compose.height;
2003 unsigned fract_part = (tpg->crop.height / factor) % tpg->compose.height;
2004 unsigned src_y = 0;
2005 unsigned error = 0;
Hans Verkuilecb9e912015-03-09 11:52:43 -03002006 unsigned h;
Hans Verkuil63881df2014-08-25 08:02:14 -03002007
2008 tpg_recalc(tpg);
2009
Hans Verkuil5e729392015-03-09 11:26:43 -03002010 params.is_tv = std;
2011 params.is_60hz = std & V4L2_STD_525_60;
2012 params.twopixsize = tpg->twopixelsize[p];
2013 params.img_width = tpg_hdiv(tpg, p, tpg->compose.width);
2014 params.stride = tpg->bytesperline[p];
2015 params.hmax = (tpg->compose.height * tpg->perc_fill) / 100;
2016
Hans Verkuilf0ce4fd2015-03-09 11:30:05 -03002017 tpg_fill_params_pattern(tpg, p, &params);
Hans Verkuil07386b92015-03-09 11:39:19 -03002018 tpg_fill_params_extras(tpg, p, &params);
2019
Hans Verkuil9991def2015-03-08 05:53:10 -03002020 vbuf += tpg_hdiv(tpg, p, tpg->compose.left);
Hans Verkuil63881df2014-08-25 08:02:14 -03002021
2022 for (h = 0; h < tpg->compose.height; h++) {
Hans Verkuil63881df2014-08-25 08:02:14 -03002023 unsigned buf_line;
Hans Verkuil63881df2014-08-25 08:02:14 -03002024
Hans Verkuilc6ff1c12015-03-09 11:47:48 -03002025 params.frame_line = tpg_calc_frameline(tpg, src_y, tpg->field);
2026 params.frame_line_next = params.frame_line;
Hans Verkuil63881df2014-08-25 08:02:14 -03002027 buf_line = tpg_calc_buffer_line(tpg, h, tpg->field);
2028 src_y += int_part;
2029 error += fract_part;
2030 if (error >= tpg->compose.height) {
2031 error -= tpg->compose.height;
2032 src_y++;
2033 }
2034
Hans Verkuil02aa7692015-03-14 08:01:50 -03002035 /*
2036 * For line-interleaved formats determine the 'plane'
2037 * based on the buffer line.
2038 */
2039 if (tpg_g_interleaved(tpg))
2040 p = tpg_g_interleaved_plane(tpg, buf_line);
2041
Hans Verkuilecb9e912015-03-09 11:52:43 -03002042 if (tpg->vdownsampling[p] > 1) {
Hans Verkuil280abe42015-03-07 14:50:41 -03002043 /*
2044 * When doing vertical downsampling the field setting
2045 * matters: for SEQ_BT/TB we downsample each field
2046 * separately (i.e. lines 0+2 are combined, as are
2047 * lines 1+3), for the other field settings we combine
2048 * odd and even lines. Doing that for SEQ_BT/TB would
2049 * be really weird.
2050 */
2051 if (tpg->field == V4L2_FIELD_SEQ_BT ||
2052 tpg->field == V4L2_FIELD_SEQ_TB) {
Hans Verkuilecb9e912015-03-09 11:52:43 -03002053 unsigned next_src_y = src_y;
2054
Hans Verkuil280abe42015-03-07 14:50:41 -03002055 if ((h & 3) >= 2)
2056 continue;
Hans Verkuilecb9e912015-03-09 11:52:43 -03002057 next_src_y += int_part;
2058 if (error + fract_part >= tpg->compose.height)
2059 next_src_y++;
2060 params.frame_line_next =
2061 tpg_calc_frameline(tpg, next_src_y, tpg->field);
2062 } else {
2063 if (h & 1)
2064 continue;
2065 params.frame_line_next =
2066 tpg_calc_frameline(tpg, src_y, tpg->field);
Hans Verkuil280abe42015-03-07 14:50:41 -03002067 }
2068
Hans Verkuilecb9e912015-03-09 11:52:43 -03002069 buf_line /= tpg->vdownsampling[p];
Hans Verkuil280abe42015-03-07 14:50:41 -03002070 }
Hans Verkuilecb9e912015-03-09 11:52:43 -03002071 tpg_fill_plane_pattern(tpg, &params, p, h,
2072 vbuf + buf_line * params.stride);
Hans Verkuilc6ff1c12015-03-09 11:47:48 -03002073 tpg_fill_plane_extras(tpg, &params, p, h,
2074 vbuf + buf_line * params.stride);
Hans Verkuil63881df2014-08-25 08:02:14 -03002075 }
2076}
Hans Verkuil4db22042015-03-07 13:39:01 -03002077
2078void tpg_fillbuffer(struct tpg_data *tpg, v4l2_std_id std, unsigned p, u8 *vbuf)
2079{
2080 unsigned offset = 0;
2081 unsigned i;
2082
2083 if (tpg->buffers > 1) {
2084 tpg_fill_plane_buffer(tpg, std, p, vbuf);
2085 return;
2086 }
2087
Hans Verkuil02aa7692015-03-14 08:01:50 -03002088 for (i = 0; i < tpg_g_planes(tpg); i++) {
Hans Verkuil4db22042015-03-07 13:39:01 -03002089 tpg_fill_plane_buffer(tpg, std, i, vbuf + offset);
2090 offset += tpg_calc_plane_size(tpg, i);
2091 }
2092}