blob: da862bb2e5f86141a7ec15016928f322a5c04e1d [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:
Hans Verkuilb96c5442015-09-21 05:31:19 -0300196 case V4L2_PIX_FMT_SBGGR10:
197 case V4L2_PIX_FMT_SGBRG10:
198 case V4L2_PIX_FMT_SGRBG10:
199 case V4L2_PIX_FMT_SRGGB10:
200 case V4L2_PIX_FMT_SBGGR12:
201 case V4L2_PIX_FMT_SGBRG12:
202 case V4L2_PIX_FMT_SGRBG12:
203 case V4L2_PIX_FMT_SRGGB12:
Hans Verkuil02aa7692015-03-14 08:01:50 -0300204 tpg->interleaved = true;
205 tpg->vdownsampling[1] = 1;
206 tpg->hdownsampling[1] = 1;
207 tpg->planes = 2;
208 /* fall through */
Hans Verkuil71491062015-03-12 15:40:36 -0300209 case V4L2_PIX_FMT_RGB332:
Hans Verkuil63881df2014-08-25 08:02:14 -0300210 case V4L2_PIX_FMT_RGB565:
211 case V4L2_PIX_FMT_RGB565X:
Hans Verkuil8aca2302015-03-11 08:14:34 -0300212 case V4L2_PIX_FMT_RGB444:
213 case V4L2_PIX_FMT_XRGB444:
214 case V4L2_PIX_FMT_ARGB444:
Hans Verkuil63881df2014-08-25 08:02:14 -0300215 case V4L2_PIX_FMT_RGB555:
216 case V4L2_PIX_FMT_XRGB555:
217 case V4L2_PIX_FMT_ARGB555:
218 case V4L2_PIX_FMT_RGB555X:
Hans Verkuil8f1ff542015-03-12 05:08:01 -0300219 case V4L2_PIX_FMT_XRGB555X:
220 case V4L2_PIX_FMT_ARGB555X:
Hans Verkuil68cd4e92015-03-13 05:36:08 -0300221 case V4L2_PIX_FMT_BGR666:
Hans Verkuil63881df2014-08-25 08:02:14 -0300222 case V4L2_PIX_FMT_RGB24:
223 case V4L2_PIX_FMT_BGR24:
224 case V4L2_PIX_FMT_RGB32:
225 case V4L2_PIX_FMT_BGR32:
226 case V4L2_PIX_FMT_XRGB32:
227 case V4L2_PIX_FMT_XBGR32:
228 case V4L2_PIX_FMT_ARGB32:
229 case V4L2_PIX_FMT_ABGR32:
Hans Verkuil51f30962015-03-07 14:57:50 -0300230 case V4L2_PIX_FMT_GREY:
Ricardo Ribalda18b3b3b2015-05-04 05:07:29 -0300231 case V4L2_PIX_FMT_Y16:
Ricardo Ribaldab0ce23f2015-05-04 05:07:31 -0300232 case V4L2_PIX_FMT_Y16_BE:
Mauro Carvalho Chehab6c515a42014-09-03 15:53:45 -0300233 tpg->is_yuv = false;
Hans Verkuil63881df2014-08-25 08:02:14 -0300234 break;
Hans Verkuil628821c2015-03-13 06:35:40 -0300235 case V4L2_PIX_FMT_YUV444:
236 case V4L2_PIX_FMT_YUV555:
237 case V4L2_PIX_FMT_YUV565:
238 case V4L2_PIX_FMT_YUV32:
239 tpg->is_yuv = true;
240 break;
Hans Verkuil68c90d62015-03-07 14:55:09 -0300241 case V4L2_PIX_FMT_YUV420M:
242 case V4L2_PIX_FMT_YVU420M:
243 tpg->buffers = 3;
244 /* fall through */
245 case V4L2_PIX_FMT_YUV420:
246 case V4L2_PIX_FMT_YVU420:
247 tpg->vdownsampling[1] = 2;
248 tpg->vdownsampling[2] = 2;
249 tpg->hdownsampling[1] = 2;
250 tpg->hdownsampling[2] = 2;
251 tpg->planes = 3;
252 tpg->is_yuv = true;
253 break;
Hans Verkuil00036b32016-02-20 06:57:38 -0200254 case V4L2_PIX_FMT_YUV422M:
255 case V4L2_PIX_FMT_YVU422M:
256 tpg->buffers = 3;
257 /* fall through */
Hans Verkuil68c90d62015-03-07 14:55:09 -0300258 case V4L2_PIX_FMT_YUV422P:
259 tpg->vdownsampling[1] = 1;
260 tpg->vdownsampling[2] = 1;
261 tpg->hdownsampling[1] = 2;
262 tpg->hdownsampling[2] = 2;
263 tpg->planes = 3;
264 tpg->is_yuv = true;
265 break;
Hans Verkuil63881df2014-08-25 08:02:14 -0300266 case V4L2_PIX_FMT_NV16M:
267 case V4L2_PIX_FMT_NV61M:
Hans Verkuil68c90d62015-03-07 14:55:09 -0300268 tpg->buffers = 2;
269 /* fall through */
270 case V4L2_PIX_FMT_NV16:
271 case V4L2_PIX_FMT_NV61:
Hans Verkuilba01f672015-03-07 13:57:27 -0300272 tpg->vdownsampling[1] = 1;
273 tpg->hdownsampling[1] = 1;
Hans Verkuil9991def2015-03-08 05:53:10 -0300274 tpg->hmask[1] = ~1;
Hans Verkuil63881df2014-08-25 08:02:14 -0300275 tpg->planes = 2;
Hans Verkuil68c90d62015-03-07 14:55:09 -0300276 tpg->is_yuv = true;
277 break;
278 case V4L2_PIX_FMT_NV12M:
279 case V4L2_PIX_FMT_NV21M:
280 tpg->buffers = 2;
281 /* fall through */
282 case V4L2_PIX_FMT_NV12:
283 case V4L2_PIX_FMT_NV21:
284 tpg->vdownsampling[1] = 2;
285 tpg->hdownsampling[1] = 1;
Hans Verkuil9991def2015-03-08 05:53:10 -0300286 tpg->hmask[1] = ~1;
Hans Verkuil68c90d62015-03-07 14:55:09 -0300287 tpg->planes = 2;
288 tpg->is_yuv = true;
289 break;
Hans Verkuil00036b32016-02-20 06:57:38 -0200290 case V4L2_PIX_FMT_YUV444M:
291 case V4L2_PIX_FMT_YVU444M:
292 tpg->buffers = 3;
293 tpg->planes = 3;
294 tpg->vdownsampling[1] = 1;
295 tpg->vdownsampling[2] = 1;
296 tpg->hdownsampling[1] = 1;
297 tpg->hdownsampling[2] = 1;
298 tpg->is_yuv = true;
299 break;
Hans Verkuildde72bd2015-03-13 05:51:21 -0300300 case V4L2_PIX_FMT_NV24:
301 case V4L2_PIX_FMT_NV42:
302 tpg->vdownsampling[1] = 1;
303 tpg->hdownsampling[1] = 1;
304 tpg->planes = 2;
305 tpg->is_yuv = true;
306 break;
Hans Verkuil63881df2014-08-25 08:02:14 -0300307 case V4L2_PIX_FMT_YUYV:
308 case V4L2_PIX_FMT_UYVY:
309 case V4L2_PIX_FMT_YVYU:
310 case V4L2_PIX_FMT_VYUY:
Hans Verkuil9991def2015-03-08 05:53:10 -0300311 tpg->hmask[0] = ~1;
Mauro Carvalho Chehab6c515a42014-09-03 15:53:45 -0300312 tpg->is_yuv = true;
Hans Verkuil63881df2014-08-25 08:02:14 -0300313 break;
314 default:
315 return false;
316 }
317
318 switch (fourcc) {
Ricardo Ribaldaed1bc6642015-05-04 05:07:32 -0300319 case V4L2_PIX_FMT_GREY:
Hans Verkuil71491062015-03-12 15:40:36 -0300320 case V4L2_PIX_FMT_RGB332:
321 tpg->twopixelsize[0] = 2;
322 break;
Hans Verkuil63881df2014-08-25 08:02:14 -0300323 case V4L2_PIX_FMT_RGB565:
324 case V4L2_PIX_FMT_RGB565X:
Hans Verkuil8aca2302015-03-11 08:14:34 -0300325 case V4L2_PIX_FMT_RGB444:
326 case V4L2_PIX_FMT_XRGB444:
327 case V4L2_PIX_FMT_ARGB444:
Hans Verkuil63881df2014-08-25 08:02:14 -0300328 case V4L2_PIX_FMT_RGB555:
329 case V4L2_PIX_FMT_XRGB555:
330 case V4L2_PIX_FMT_ARGB555:
331 case V4L2_PIX_FMT_RGB555X:
Hans Verkuil8f1ff542015-03-12 05:08:01 -0300332 case V4L2_PIX_FMT_XRGB555X:
333 case V4L2_PIX_FMT_ARGB555X:
Hans Verkuil63881df2014-08-25 08:02:14 -0300334 case V4L2_PIX_FMT_YUYV:
335 case V4L2_PIX_FMT_UYVY:
336 case V4L2_PIX_FMT_YVYU:
337 case V4L2_PIX_FMT_VYUY:
Hans Verkuil628821c2015-03-13 06:35:40 -0300338 case V4L2_PIX_FMT_YUV444:
339 case V4L2_PIX_FMT_YUV555:
340 case V4L2_PIX_FMT_YUV565:
Ricardo Ribalda18b3b3b2015-05-04 05:07:29 -0300341 case V4L2_PIX_FMT_Y16:
Ricardo Ribaldab0ce23f2015-05-04 05:07:31 -0300342 case V4L2_PIX_FMT_Y16_BE:
Hans Verkuil63881df2014-08-25 08:02:14 -0300343 tpg->twopixelsize[0] = 2 * 2;
344 break;
345 case V4L2_PIX_FMT_RGB24:
346 case V4L2_PIX_FMT_BGR24:
347 tpg->twopixelsize[0] = 2 * 3;
348 break;
Hans Verkuil68cd4e92015-03-13 05:36:08 -0300349 case V4L2_PIX_FMT_BGR666:
Hans Verkuil63881df2014-08-25 08:02:14 -0300350 case V4L2_PIX_FMT_RGB32:
351 case V4L2_PIX_FMT_BGR32:
352 case V4L2_PIX_FMT_XRGB32:
353 case V4L2_PIX_FMT_XBGR32:
354 case V4L2_PIX_FMT_ARGB32:
355 case V4L2_PIX_FMT_ABGR32:
Hans Verkuil628821c2015-03-13 06:35:40 -0300356 case V4L2_PIX_FMT_YUV32:
Hans Verkuil63881df2014-08-25 08:02:14 -0300357 tpg->twopixelsize[0] = 2 * 4;
358 break;
Hans Verkuil68c90d62015-03-07 14:55:09 -0300359 case V4L2_PIX_FMT_NV12:
360 case V4L2_PIX_FMT_NV21:
361 case V4L2_PIX_FMT_NV12M:
362 case V4L2_PIX_FMT_NV21M:
Hans Verkuil68c90d62015-03-07 14:55:09 -0300363 case V4L2_PIX_FMT_NV16:
364 case V4L2_PIX_FMT_NV61:
Hans Verkuil63881df2014-08-25 08:02:14 -0300365 case V4L2_PIX_FMT_NV16M:
366 case V4L2_PIX_FMT_NV61M:
Hans Verkuil02aa7692015-03-14 08:01:50 -0300367 case V4L2_PIX_FMT_SBGGR8:
368 case V4L2_PIX_FMT_SGBRG8:
369 case V4L2_PIX_FMT_SGRBG8:
370 case V4L2_PIX_FMT_SRGGB8:
Hans Verkuil63881df2014-08-25 08:02:14 -0300371 tpg->twopixelsize[0] = 2;
372 tpg->twopixelsize[1] = 2;
373 break;
Hans Verkuilb96c5442015-09-21 05:31:19 -0300374 case V4L2_PIX_FMT_SRGGB10:
375 case V4L2_PIX_FMT_SGRBG10:
376 case V4L2_PIX_FMT_SGBRG10:
377 case V4L2_PIX_FMT_SBGGR10:
378 case V4L2_PIX_FMT_SRGGB12:
379 case V4L2_PIX_FMT_SGRBG12:
380 case V4L2_PIX_FMT_SGBRG12:
381 case V4L2_PIX_FMT_SBGGR12:
382 tpg->twopixelsize[0] = 4;
383 tpg->twopixelsize[1] = 4;
384 break;
Hans Verkuil00036b32016-02-20 06:57:38 -0200385 case V4L2_PIX_FMT_YUV444M:
386 case V4L2_PIX_FMT_YVU444M:
387 case V4L2_PIX_FMT_YUV422M:
388 case V4L2_PIX_FMT_YVU422M:
Hans Verkuil68c90d62015-03-07 14:55:09 -0300389 case V4L2_PIX_FMT_YUV422P:
390 case V4L2_PIX_FMT_YUV420:
391 case V4L2_PIX_FMT_YVU420:
392 case V4L2_PIX_FMT_YUV420M:
393 case V4L2_PIX_FMT_YVU420M:
394 tpg->twopixelsize[0] = 2;
395 tpg->twopixelsize[1] = 2;
396 tpg->twopixelsize[2] = 2;
397 break;
Hans Verkuildde72bd2015-03-13 05:51:21 -0300398 case V4L2_PIX_FMT_NV24:
399 case V4L2_PIX_FMT_NV42:
400 tpg->twopixelsize[0] = 2;
401 tpg->twopixelsize[1] = 4;
402 break;
Hans Verkuil63881df2014-08-25 08:02:14 -0300403 }
404 return true;
405}
406
407void tpg_s_crop_compose(struct tpg_data *tpg, const struct v4l2_rect *crop,
408 const struct v4l2_rect *compose)
409{
410 tpg->crop = *crop;
411 tpg->compose = *compose;
412 tpg->scaled_width = (tpg->src_width * tpg->compose.width +
413 tpg->crop.width - 1) / tpg->crop.width;
414 tpg->scaled_width &= ~1;
415 if (tpg->scaled_width > tpg->max_line_width)
416 tpg->scaled_width = tpg->max_line_width;
417 if (tpg->scaled_width < 2)
418 tpg->scaled_width = 2;
419 tpg->recalc_lines = true;
420}
421
422void tpg_reset_source(struct tpg_data *tpg, unsigned width, unsigned height,
Hans Verkuil73d81022014-09-03 10:18:57 -0300423 u32 field)
Hans Verkuil63881df2014-08-25 08:02:14 -0300424{
425 unsigned p;
426
427 tpg->src_width = width;
428 tpg->src_height = height;
429 tpg->field = field;
430 tpg->buf_height = height;
431 if (V4L2_FIELD_HAS_T_OR_B(field))
432 tpg->buf_height /= 2;
433 tpg->scaled_width = width;
434 tpg->crop.top = tpg->crop.left = 0;
435 tpg->crop.width = width;
436 tpg->crop.height = height;
437 tpg->compose.top = tpg->compose.left = 0;
438 tpg->compose.width = width;
439 tpg->compose.height = tpg->buf_height;
440 for (p = 0; p < tpg->planes; p++)
Hans Verkuilba01f672015-03-07 13:57:27 -0300441 tpg->bytesperline[p] = (width * tpg->twopixelsize[p]) /
442 (2 * tpg->hdownsampling[p]);
Hans Verkuil63881df2014-08-25 08:02:14 -0300443 tpg->recalc_square_border = true;
444}
445
446static enum tpg_color tpg_get_textbg_color(struct tpg_data *tpg)
447{
448 switch (tpg->pattern) {
449 case TPG_PAT_BLACK:
450 return TPG_COLOR_100_WHITE;
451 case TPG_PAT_CSC_COLORBAR:
452 return TPG_COLOR_CSC_BLACK;
453 default:
454 return TPG_COLOR_100_BLACK;
455 }
456}
457
458static enum tpg_color tpg_get_textfg_color(struct tpg_data *tpg)
459{
460 switch (tpg->pattern) {
461 case TPG_PAT_75_COLORBAR:
462 case TPG_PAT_CSC_COLORBAR:
463 return TPG_COLOR_CSC_WHITE;
464 case TPG_PAT_BLACK:
465 return TPG_COLOR_100_BLACK;
466 default:
467 return TPG_COLOR_100_WHITE;
468 }
469}
470
Hans Verkuil481b97a2014-11-17 10:14:32 -0300471static inline int rec709_to_linear(int v)
Hans Verkuil63881df2014-08-25 08:02:14 -0300472{
Hans Verkuil481b97a2014-11-17 10:14:32 -0300473 v = clamp(v, 0, 0xff0);
474 return tpg_rec709_to_linear[v];
475}
476
477static inline int linear_to_rec709(int v)
478{
479 v = clamp(v, 0, 0xff0);
480 return tpg_linear_to_rec709[v];
481}
482
483static void rgb2ycbcr(const int m[3][3], int r, int g, int b,
484 int y_offset, int *y, int *cb, int *cr)
485{
486 *y = ((m[0][0] * r + m[0][1] * g + m[0][2] * b) >> 16) + (y_offset << 4);
487 *cb = ((m[1][0] * r + m[1][1] * g + m[1][2] * b) >> 16) + (128 << 4);
488 *cr = ((m[2][0] * r + m[2][1] * g + m[2][2] * b) >> 16) + (128 << 4);
489}
490
491static void color_to_ycbcr(struct tpg_data *tpg, int r, int g, int b,
492 int *y, int *cb, int *cr)
493{
494#define COEFF(v, r) ((int)(0.5 + (v) * (r) * 256.0))
495
496 static const int bt601[3][3] = {
497 { COEFF(0.299, 219), COEFF(0.587, 219), COEFF(0.114, 219) },
498 { COEFF(-0.169, 224), COEFF(-0.331, 224), COEFF(0.5, 224) },
499 { COEFF(0.5, 224), COEFF(-0.419, 224), COEFF(-0.081, 224) },
500 };
501 static const int bt601_full[3][3] = {
502 { COEFF(0.299, 255), COEFF(0.587, 255), COEFF(0.114, 255) },
503 { COEFF(-0.169, 255), COEFF(-0.331, 255), COEFF(0.5, 255) },
504 { COEFF(0.5, 255), COEFF(-0.419, 255), COEFF(-0.081, 255) },
505 };
506 static const int rec709[3][3] = {
507 { COEFF(0.2126, 219), COEFF(0.7152, 219), COEFF(0.0722, 219) },
508 { COEFF(-0.1146, 224), COEFF(-0.3854, 224), COEFF(0.5, 224) },
509 { COEFF(0.5, 224), COEFF(-0.4542, 224), COEFF(-0.0458, 224) },
510 };
511 static const int rec709_full[3][3] = {
512 { COEFF(0.2126, 255), COEFF(0.7152, 255), COEFF(0.0722, 255) },
513 { COEFF(-0.1146, 255), COEFF(-0.3854, 255), COEFF(0.5, 255) },
514 { COEFF(0.5, 255), COEFF(-0.4542, 255), COEFF(-0.0458, 255) },
515 };
516 static const int smpte240m[3][3] = {
517 { COEFF(0.212, 219), COEFF(0.701, 219), COEFF(0.087, 219) },
518 { COEFF(-0.116, 224), COEFF(-0.384, 224), COEFF(0.5, 224) },
519 { COEFF(0.5, 224), COEFF(-0.445, 224), COEFF(-0.055, 224) },
520 };
Hans Verkuilc702f682015-04-24 11:16:23 -0300521 static const int smpte240m_full[3][3] = {
522 { COEFF(0.212, 255), COEFF(0.701, 255), COEFF(0.087, 255) },
523 { COEFF(-0.116, 255), COEFF(-0.384, 255), COEFF(0.5, 255) },
524 { COEFF(0.5, 255), COEFF(-0.445, 255), COEFF(-0.055, 255) },
525 };
Hans Verkuil481b97a2014-11-17 10:14:32 -0300526 static const int bt2020[3][3] = {
Hans Verkuile202e512015-03-20 13:23:06 -0300527 { COEFF(0.2627, 219), COEFF(0.6780, 219), COEFF(0.0593, 219) },
Hans Verkuil481b97a2014-11-17 10:14:32 -0300528 { COEFF(-0.1396, 224), COEFF(-0.3604, 224), COEFF(0.5, 224) },
Hans Verkuile202e512015-03-20 13:23:06 -0300529 { COEFF(0.5, 224), COEFF(-0.4598, 224), COEFF(-0.0402, 224) },
Hans Verkuil481b97a2014-11-17 10:14:32 -0300530 };
Hans Verkuilcf73b712015-04-24 11:16:24 -0300531 static const int bt2020_full[3][3] = {
532 { COEFF(0.2627, 255), COEFF(0.6780, 255), COEFF(0.0593, 255) },
533 { COEFF(-0.1396, 255), COEFF(-0.3604, 255), COEFF(0.5, 255) },
534 { COEFF(0.5, 255), COEFF(-0.4698, 255), COEFF(-0.0402, 255) },
535 };
Hans Verkuilbbfef492015-04-24 11:16:25 -0300536 static const int bt2020c[4] = {
537 COEFF(1.0 / 1.9404, 224), COEFF(1.0 / 1.5816, 224),
538 COEFF(1.0 / 1.7184, 224), COEFF(1.0 / 0.9936, 224),
539 };
540 static const int bt2020c_full[4] = {
541 COEFF(1.0 / 1.9404, 255), COEFF(1.0 / 1.5816, 255),
542 COEFF(1.0 / 1.7184, 255), COEFF(1.0 / 0.9936, 255),
543 };
Hans Verkuilcf73b712015-04-24 11:16:24 -0300544
Hans Verkuil481b97a2014-11-17 10:14:32 -0300545 bool full = tpg->real_quantization == V4L2_QUANTIZATION_FULL_RANGE;
Hans Verkuilafad4dd2015-01-27 13:46:17 -0300546 unsigned y_offset = full ? 0 : 16;
Hans Verkuil481b97a2014-11-17 10:14:32 -0300547 int lin_y, yc;
548
549 switch (tpg->real_ycbcr_enc) {
550 case V4L2_YCBCR_ENC_601:
Hans Verkuil481b97a2014-11-17 10:14:32 -0300551 case V4L2_YCBCR_ENC_SYCC:
Hans Verkuilafad4dd2015-01-27 13:46:17 -0300552 rgb2ycbcr(full ? bt601_full : bt601, r, g, b, y_offset, y, cb, cr);
Hans Verkuil481b97a2014-11-17 10:14:32 -0300553 break;
Hans Verkuilf6b8af22015-04-24 11:16:26 -0300554 case V4L2_YCBCR_ENC_XV601:
555 /* Ignore quantization range, there is only one possible
556 * Y'CbCr encoding. */
557 rgb2ycbcr(bt601, r, g, b, 16, y, cb, cr);
558 break;
559 case V4L2_YCBCR_ENC_XV709:
560 /* Ignore quantization range, there is only one possible
561 * Y'CbCr encoding. */
562 rgb2ycbcr(rec709, r, g, b, 16, y, cb, cr);
563 break;
Hans Verkuil481b97a2014-11-17 10:14:32 -0300564 case V4L2_YCBCR_ENC_BT2020:
Hans Verkuilcf73b712015-04-24 11:16:24 -0300565 rgb2ycbcr(full ? bt2020_full : bt2020, r, g, b, y_offset, y, cb, cr);
Hans Verkuil481b97a2014-11-17 10:14:32 -0300566 break;
567 case V4L2_YCBCR_ENC_BT2020_CONST_LUM:
568 lin_y = (COEFF(0.2627, 255) * rec709_to_linear(r) +
569 COEFF(0.6780, 255) * rec709_to_linear(g) +
570 COEFF(0.0593, 255) * rec709_to_linear(b)) >> 16;
571 yc = linear_to_rec709(lin_y);
Hans Verkuilbbfef492015-04-24 11:16:25 -0300572 *y = full ? yc : (yc * 219) / 255 + (16 << 4);
Hans Verkuil481b97a2014-11-17 10:14:32 -0300573 if (b <= yc)
Hans Verkuilbbfef492015-04-24 11:16:25 -0300574 *cb = (((b - yc) * (full ? bt2020c_full[0] : bt2020c[0])) >> 16) + (128 << 4);
Hans Verkuil481b97a2014-11-17 10:14:32 -0300575 else
Hans Verkuilbbfef492015-04-24 11:16:25 -0300576 *cb = (((b - yc) * (full ? bt2020c_full[1] : bt2020c[1])) >> 16) + (128 << 4);
Hans Verkuil481b97a2014-11-17 10:14:32 -0300577 if (r <= yc)
Hans Verkuilbbfef492015-04-24 11:16:25 -0300578 *cr = (((r - yc) * (full ? bt2020c_full[2] : bt2020c[2])) >> 16) + (128 << 4);
Hans Verkuil481b97a2014-11-17 10:14:32 -0300579 else
Hans Verkuilbbfef492015-04-24 11:16:25 -0300580 *cr = (((r - yc) * (full ? bt2020c_full[3] : bt2020c[3])) >> 16) + (128 << 4);
Hans Verkuil481b97a2014-11-17 10:14:32 -0300581 break;
582 case V4L2_YCBCR_ENC_SMPTE240M:
Hans Verkuilc702f682015-04-24 11:16:23 -0300583 rgb2ycbcr(full ? smpte240m_full : smpte240m, r, g, b, y_offset, y, cb, cr);
Hans Verkuil481b97a2014-11-17 10:14:32 -0300584 break;
585 case V4L2_YCBCR_ENC_709:
Hans Verkuil63881df2014-08-25 08:02:14 -0300586 default:
Hans Verkuilafad4dd2015-01-27 13:46:17 -0300587 rgb2ycbcr(full ? rec709_full : rec709, r, g, b, y_offset, y, cb, cr);
Hans Verkuil481b97a2014-11-17 10:14:32 -0300588 break;
Hans Verkuil63881df2014-08-25 08:02:14 -0300589 }
590}
591
Hans Verkuil481b97a2014-11-17 10:14:32 -0300592static void ycbcr2rgb(const int m[3][3], int y, int cb, int cr,
593 int y_offset, int *r, int *g, int *b)
Hans Verkuil63881df2014-08-25 08:02:14 -0300594{
Hans Verkuil481b97a2014-11-17 10:14:32 -0300595 y -= y_offset << 4;
Hans Verkuil63881df2014-08-25 08:02:14 -0300596 cb -= 128 << 4;
597 cr -= 128 << 4;
Hans Verkuil481b97a2014-11-17 10:14:32 -0300598 *r = m[0][0] * y + m[0][1] * cb + m[0][2] * cr;
599 *g = m[1][0] * y + m[1][1] * cb + m[1][2] * cr;
600 *b = m[2][0] * y + m[2][1] * cb + m[2][2] * cr;
601 *r = clamp(*r >> 12, 0, 0xff0);
602 *g = clamp(*g >> 12, 0, 0xff0);
603 *b = clamp(*b >> 12, 0, 0xff0);
Hans Verkuil63881df2014-08-25 08:02:14 -0300604}
605
Hans Verkuil481b97a2014-11-17 10:14:32 -0300606static void ycbcr_to_color(struct tpg_data *tpg, int y, int cb, int cr,
607 int *r, int *g, int *b)
Hans Verkuil63881df2014-08-25 08:02:14 -0300608{
Hans Verkuil481b97a2014-11-17 10:14:32 -0300609#undef COEFF
610#define COEFF(v, r) ((int)(0.5 + (v) * ((255.0 * 255.0 * 16.0) / (r))))
611 static const int bt601[3][3] = {
612 { COEFF(1, 219), COEFF(0, 224), COEFF(1.4020, 224) },
613 { COEFF(1, 219), COEFF(-0.3441, 224), COEFF(-0.7141, 224) },
614 { COEFF(1, 219), COEFF(1.7720, 224), COEFF(0, 224) },
615 };
616 static const int bt601_full[3][3] = {
617 { COEFF(1, 255), COEFF(0, 255), COEFF(1.4020, 255) },
618 { COEFF(1, 255), COEFF(-0.3441, 255), COEFF(-0.7141, 255) },
619 { COEFF(1, 255), COEFF(1.7720, 255), COEFF(0, 255) },
620 };
621 static const int rec709[3][3] = {
622 { COEFF(1, 219), COEFF(0, 224), COEFF(1.5748, 224) },
623 { COEFF(1, 219), COEFF(-0.1873, 224), COEFF(-0.4681, 224) },
624 { COEFF(1, 219), COEFF(1.8556, 224), COEFF(0, 224) },
625 };
626 static const int rec709_full[3][3] = {
627 { COEFF(1, 255), COEFF(0, 255), COEFF(1.5748, 255) },
628 { COEFF(1, 255), COEFF(-0.1873, 255), COEFF(-0.4681, 255) },
629 { COEFF(1, 255), COEFF(1.8556, 255), COEFF(0, 255) },
630 };
631 static const int smpte240m[3][3] = {
632 { COEFF(1, 219), COEFF(0, 224), COEFF(1.5756, 224) },
633 { COEFF(1, 219), COEFF(-0.2253, 224), COEFF(-0.4767, 224) },
634 { COEFF(1, 219), COEFF(1.8270, 224), COEFF(0, 224) },
635 };
Hans Verkuilc702f682015-04-24 11:16:23 -0300636 static const int smpte240m_full[3][3] = {
637 { COEFF(1, 255), COEFF(0, 255), COEFF(1.5756, 255) },
638 { COEFF(1, 255), COEFF(-0.2253, 255), COEFF(-0.4767, 255) },
639 { COEFF(1, 255), COEFF(1.8270, 255), COEFF(0, 255) },
640 };
Hans Verkuil481b97a2014-11-17 10:14:32 -0300641 static const int bt2020[3][3] = {
642 { COEFF(1, 219), COEFF(0, 224), COEFF(1.4746, 224) },
643 { COEFF(1, 219), COEFF(-0.1646, 224), COEFF(-0.5714, 224) },
644 { COEFF(1, 219), COEFF(1.8814, 224), COEFF(0, 224) },
645 };
Hans Verkuilcf73b712015-04-24 11:16:24 -0300646 static const int bt2020_full[3][3] = {
647 { COEFF(1, 255), COEFF(0, 255), COEFF(1.4746, 255) },
648 { COEFF(1, 255), COEFF(-0.1646, 255), COEFF(-0.5714, 255) },
649 { COEFF(1, 255), COEFF(1.8814, 255), COEFF(0, 255) },
650 };
Hans Verkuilbbfef492015-04-24 11:16:25 -0300651 static const int bt2020c[4] = {
652 COEFF(1.9404, 224), COEFF(1.5816, 224),
653 COEFF(1.7184, 224), COEFF(0.9936, 224),
654 };
655 static const int bt2020c_full[4] = {
656 COEFF(1.9404, 255), COEFF(1.5816, 255),
657 COEFF(1.7184, 255), COEFF(0.9936, 255),
658 };
659
Hans Verkuil481b97a2014-11-17 10:14:32 -0300660 bool full = tpg->real_quantization == V4L2_QUANTIZATION_FULL_RANGE;
Hans Verkuilafad4dd2015-01-27 13:46:17 -0300661 unsigned y_offset = full ? 0 : 16;
Hans Verkuilbbfef492015-04-24 11:16:25 -0300662 int y_fac = full ? COEFF(1.0, 255) : COEFF(1.0, 219);
Hans Verkuil481b97a2014-11-17 10:14:32 -0300663 int lin_r, lin_g, lin_b, lin_y;
Hans Verkuil63881df2014-08-25 08:02:14 -0300664
Hans Verkuil481b97a2014-11-17 10:14:32 -0300665 switch (tpg->real_ycbcr_enc) {
666 case V4L2_YCBCR_ENC_601:
Hans Verkuil481b97a2014-11-17 10:14:32 -0300667 case V4L2_YCBCR_ENC_SYCC:
Hans Verkuilafad4dd2015-01-27 13:46:17 -0300668 ycbcr2rgb(full ? bt601_full : bt601, y, cb, cr, y_offset, r, g, b);
Hans Verkuil63881df2014-08-25 08:02:14 -0300669 break;
Hans Verkuilf6b8af22015-04-24 11:16:26 -0300670 case V4L2_YCBCR_ENC_XV601:
671 /* Ignore quantization range, there is only one possible
672 * Y'CbCr encoding. */
673 ycbcr2rgb(bt601, y, cb, cr, 16, r, g, b);
674 break;
675 case V4L2_YCBCR_ENC_XV709:
676 /* Ignore quantization range, there is only one possible
677 * Y'CbCr encoding. */
678 ycbcr2rgb(rec709, y, cb, cr, 16, r, g, b);
679 break;
Hans Verkuil481b97a2014-11-17 10:14:32 -0300680 case V4L2_YCBCR_ENC_BT2020:
Hans Verkuilcf73b712015-04-24 11:16:24 -0300681 ycbcr2rgb(full ? bt2020_full : bt2020, y, cb, cr, y_offset, r, g, b);
Hans Verkuil63881df2014-08-25 08:02:14 -0300682 break;
Hans Verkuil481b97a2014-11-17 10:14:32 -0300683 case V4L2_YCBCR_ENC_BT2020_CONST_LUM:
Hans Verkuilbbfef492015-04-24 11:16:25 -0300684 y -= full ? 0 : 16 << 4;
Hans Verkuil481b97a2014-11-17 10:14:32 -0300685 cb -= 128 << 4;
686 cr -= 128 << 4;
687
688 if (cb <= 0)
Hans Verkuilbbfef492015-04-24 11:16:25 -0300689 *b = y_fac * y + (full ? bt2020c_full[0] : bt2020c[0]) * cb;
Hans Verkuil481b97a2014-11-17 10:14:32 -0300690 else
Hans Verkuilbbfef492015-04-24 11:16:25 -0300691 *b = y_fac * y + (full ? bt2020c_full[1] : bt2020c[1]) * cb;
Hans Verkuil481b97a2014-11-17 10:14:32 -0300692 *b = *b >> 12;
693 if (cr <= 0)
Hans Verkuilbbfef492015-04-24 11:16:25 -0300694 *r = y_fac * y + (full ? bt2020c_full[2] : bt2020c[2]) * cr;
Hans Verkuil481b97a2014-11-17 10:14:32 -0300695 else
Hans Verkuilbbfef492015-04-24 11:16:25 -0300696 *r = y_fac * y + (full ? bt2020c_full[3] : bt2020c[3]) * cr;
Hans Verkuil481b97a2014-11-17 10:14:32 -0300697 *r = *r >> 12;
698 lin_r = rec709_to_linear(*r);
699 lin_b = rec709_to_linear(*b);
Hans Verkuilbbfef492015-04-24 11:16:25 -0300700 lin_y = rec709_to_linear((y * 255) / (full ? 255 : 219));
Hans Verkuil481b97a2014-11-17 10:14:32 -0300701
702 lin_g = COEFF(1.0 / 0.6780, 255) * lin_y -
703 COEFF(0.2627 / 0.6780, 255) * lin_r -
704 COEFF(0.0593 / 0.6780, 255) * lin_b;
705 *g = linear_to_rec709(lin_g >> 12);
706 break;
707 case V4L2_YCBCR_ENC_SMPTE240M:
Hans Verkuilc702f682015-04-24 11:16:23 -0300708 ycbcr2rgb(full ? smpte240m_full : smpte240m, y, cb, cr, y_offset, r, g, b);
Hans Verkuil481b97a2014-11-17 10:14:32 -0300709 break;
710 case V4L2_YCBCR_ENC_709:
Hans Verkuil63881df2014-08-25 08:02:14 -0300711 default:
Hans Verkuilafad4dd2015-01-27 13:46:17 -0300712 ycbcr2rgb(full ? rec709_full : rec709, y, cb, cr, y_offset, r, g, b);
Hans Verkuil63881df2014-08-25 08:02:14 -0300713 break;
714 }
Hans Verkuil63881df2014-08-25 08:02:14 -0300715}
716
717/* precalculate color bar values to speed up rendering */
718static void precalculate_color(struct tpg_data *tpg, int k)
719{
720 int col = k;
721 int r = tpg_colors[col].r;
722 int g = tpg_colors[col].g;
723 int b = tpg_colors[col].b;
724
725 if (k == TPG_COLOR_TEXTBG) {
726 col = tpg_get_textbg_color(tpg);
727
728 r = tpg_colors[col].r;
729 g = tpg_colors[col].g;
730 b = tpg_colors[col].b;
731 } else if (k == TPG_COLOR_TEXTFG) {
732 col = tpg_get_textfg_color(tpg);
733
734 r = tpg_colors[col].r;
735 g = tpg_colors[col].g;
736 b = tpg_colors[col].b;
737 } else if (tpg->pattern == TPG_PAT_NOISE) {
738 r = g = b = prandom_u32_max(256);
739 } else if (k == TPG_COLOR_RANDOM) {
740 r = g = b = tpg->qual_offset + prandom_u32_max(196);
741 } else if (k >= TPG_COLOR_RAMP) {
742 r = g = b = k - TPG_COLOR_RAMP;
743 }
744
745 if (tpg->pattern == TPG_PAT_CSC_COLORBAR && col <= TPG_COLOR_CSC_BLACK) {
Hans Verkuil78aad7f2015-04-28 10:08:43 -0300746 r = tpg_csc_colors[tpg->colorspace][tpg->real_xfer_func][col].r;
747 g = tpg_csc_colors[tpg->colorspace][tpg->real_xfer_func][col].g;
748 b = tpg_csc_colors[tpg->colorspace][tpg->real_xfer_func][col].b;
Hans Verkuil63881df2014-08-25 08:02:14 -0300749 } else {
750 r <<= 4;
751 g <<= 4;
752 b <<= 4;
753 }
Ricardo Ribalda18b3b3b2015-05-04 05:07:29 -0300754 if (tpg->qual == TPG_QUAL_GRAY || tpg->fourcc == V4L2_PIX_FMT_GREY ||
Ricardo Ribaldab0ce23f2015-05-04 05:07:31 -0300755 tpg->fourcc == V4L2_PIX_FMT_Y16 ||
756 tpg->fourcc == V4L2_PIX_FMT_Y16_BE) {
Hans Verkuil481b97a2014-11-17 10:14:32 -0300757 /* Rec. 709 Luma function */
758 /* (0.2126, 0.7152, 0.0722) * (255 * 256) */
Hans Verkuil9c35bd42015-03-07 12:53:39 -0300759 r = g = b = (13879 * r + 46688 * g + 4713 * b) >> 16;
Hans Verkuil481b97a2014-11-17 10:14:32 -0300760 }
Hans Verkuil63881df2014-08-25 08:02:14 -0300761
762 /*
763 * The assumption is that the RGB output is always full range,
764 * so only if the rgb_range overrides the 'real' rgb range do
765 * we need to convert the RGB values.
766 *
Hans Verkuil63881df2014-08-25 08:02:14 -0300767 * Remember that r, g and b are still in the 0 - 0xff0 range.
768 */
769 if (tpg->real_rgb_range == V4L2_DV_RGB_RANGE_LIMITED &&
770 tpg->rgb_range == V4L2_DV_RGB_RANGE_FULL) {
771 /*
772 * Convert from full range (which is what r, g and b are)
773 * to limited range (which is the 'real' RGB range), which
774 * is then interpreted as full range.
775 */
776 r = (r * 219) / 255 + (16 << 4);
777 g = (g * 219) / 255 + (16 << 4);
778 b = (b * 219) / 255 + (16 << 4);
779 } else if (tpg->real_rgb_range != V4L2_DV_RGB_RANGE_LIMITED &&
780 tpg->rgb_range == V4L2_DV_RGB_RANGE_LIMITED) {
781 /*
782 * Clamp r, g and b to the limited range and convert to full
783 * range since that's what we deliver.
784 */
785 r = clamp(r, 16 << 4, 235 << 4);
786 g = clamp(g, 16 << 4, 235 << 4);
787 b = clamp(b, 16 << 4, 235 << 4);
788 r = (r - (16 << 4)) * 255 / 219;
789 g = (g - (16 << 4)) * 255 / 219;
790 b = (b - (16 << 4)) * 255 / 219;
791 }
792
793 if (tpg->brightness != 128 || tpg->contrast != 128 ||
794 tpg->saturation != 128 || tpg->hue) {
795 /* Implement these operations */
Hans Verkuil481b97a2014-11-17 10:14:32 -0300796 int y, cb, cr;
797 int tmp_cb, tmp_cr;
Hans Verkuil63881df2014-08-25 08:02:14 -0300798
799 /* First convert to YCbCr */
Hans Verkuil481b97a2014-11-17 10:14:32 -0300800
801 color_to_ycbcr(tpg, r, g, b, &y, &cb, &cr);
Hans Verkuil63881df2014-08-25 08:02:14 -0300802
803 y = (16 << 4) + ((y - (16 << 4)) * tpg->contrast) / 128;
804 y += (tpg->brightness << 4) - (128 << 4);
805
806 cb -= 128 << 4;
807 cr -= 128 << 4;
808 tmp_cb = (cb * cos(128 + tpg->hue)) / 127 + (cr * sin[128 + tpg->hue]) / 127;
809 tmp_cr = (cr * cos(128 + tpg->hue)) / 127 - (cb * sin[128 + tpg->hue]) / 127;
810
811 cb = (128 << 4) + (tmp_cb * tpg->contrast * tpg->saturation) / (128 * 128);
812 cr = (128 << 4) + (tmp_cr * tpg->contrast * tpg->saturation) / (128 * 128);
813 if (tpg->is_yuv) {
814 tpg->colors[k][0] = clamp(y >> 4, 1, 254);
815 tpg->colors[k][1] = clamp(cb >> 4, 1, 254);
816 tpg->colors[k][2] = clamp(cr >> 4, 1, 254);
817 return;
818 }
Hans Verkuil481b97a2014-11-17 10:14:32 -0300819 ycbcr_to_color(tpg, y, cb, cr, &r, &g, &b);
Hans Verkuil63881df2014-08-25 08:02:14 -0300820 }
821
822 if (tpg->is_yuv) {
823 /* Convert to YCbCr */
Hans Verkuil481b97a2014-11-17 10:14:32 -0300824 int y, cb, cr;
Hans Verkuil63881df2014-08-25 08:02:14 -0300825
Hans Verkuil481b97a2014-11-17 10:14:32 -0300826 color_to_ycbcr(tpg, r, g, b, &y, &cb, &cr);
827
828 if (tpg->real_quantization == V4L2_QUANTIZATION_LIM_RANGE) {
829 y = clamp(y, 16 << 4, 235 << 4);
830 cb = clamp(cb, 16 << 4, 240 << 4);
831 cr = clamp(cr, 16 << 4, 240 << 4);
832 }
Hans Verkuil628821c2015-03-13 06:35:40 -0300833 y = clamp(y >> 4, 1, 254);
834 cb = clamp(cb >> 4, 1, 254);
835 cr = clamp(cr >> 4, 1, 254);
836 switch (tpg->fourcc) {
837 case V4L2_PIX_FMT_YUV444:
838 y >>= 4;
839 cb >>= 4;
840 cr >>= 4;
841 break;
842 case V4L2_PIX_FMT_YUV555:
843 y >>= 3;
844 cb >>= 3;
845 cr >>= 3;
846 break;
847 case V4L2_PIX_FMT_YUV565:
848 y >>= 3;
849 cb >>= 2;
850 cr >>= 3;
851 break;
852 }
853 tpg->colors[k][0] = y;
854 tpg->colors[k][1] = cb;
855 tpg->colors[k][2] = cr;
Hans Verkuil63881df2014-08-25 08:02:14 -0300856 } else {
Hans Verkuil481b97a2014-11-17 10:14:32 -0300857 if (tpg->real_quantization == V4L2_QUANTIZATION_LIM_RANGE) {
858 r = (r * 219) / 255 + (16 << 4);
859 g = (g * 219) / 255 + (16 << 4);
860 b = (b * 219) / 255 + (16 << 4);
861 }
Hans Verkuil63881df2014-08-25 08:02:14 -0300862 switch (tpg->fourcc) {
Hans Verkuil71491062015-03-12 15:40:36 -0300863 case V4L2_PIX_FMT_RGB332:
864 r >>= 9;
865 g >>= 9;
866 b >>= 10;
867 break;
Hans Verkuil63881df2014-08-25 08:02:14 -0300868 case V4L2_PIX_FMT_RGB565:
869 case V4L2_PIX_FMT_RGB565X:
870 r >>= 7;
871 g >>= 6;
872 b >>= 7;
873 break;
Hans Verkuil8aca2302015-03-11 08:14:34 -0300874 case V4L2_PIX_FMT_RGB444:
875 case V4L2_PIX_FMT_XRGB444:
876 case V4L2_PIX_FMT_ARGB444:
877 r >>= 8;
878 g >>= 8;
879 b >>= 8;
880 break;
Hans Verkuil63881df2014-08-25 08:02:14 -0300881 case V4L2_PIX_FMT_RGB555:
882 case V4L2_PIX_FMT_XRGB555:
883 case V4L2_PIX_FMT_ARGB555:
884 case V4L2_PIX_FMT_RGB555X:
Hans Verkuil8f1ff542015-03-12 05:08:01 -0300885 case V4L2_PIX_FMT_XRGB555X:
886 case V4L2_PIX_FMT_ARGB555X:
Hans Verkuil63881df2014-08-25 08:02:14 -0300887 r >>= 7;
888 g >>= 7;
889 b >>= 7;
890 break;
Hans Verkuil68cd4e92015-03-13 05:36:08 -0300891 case V4L2_PIX_FMT_BGR666:
892 r >>= 6;
893 g >>= 6;
894 b >>= 6;
895 break;
Hans Verkuil63881df2014-08-25 08:02:14 -0300896 default:
897 r >>= 4;
898 g >>= 4;
899 b >>= 4;
900 break;
901 }
902
903 tpg->colors[k][0] = r;
904 tpg->colors[k][1] = g;
905 tpg->colors[k][2] = b;
906 }
907}
908
909static void tpg_precalculate_colors(struct tpg_data *tpg)
910{
911 int k;
912
913 for (k = 0; k < TPG_COLOR_MAX; k++)
914 precalculate_color(tpg, k);
915}
916
917/* 'odd' is true for pixels 1, 3, 5, etc. and false for pixels 0, 2, 4, etc. */
918static void gen_twopix(struct tpg_data *tpg,
919 u8 buf[TPG_MAX_PLANES][8], int color, bool odd)
920{
921 unsigned offset = odd * tpg->twopixelsize[0] / 2;
922 u8 alpha = tpg->alpha_component;
923 u8 r_y, g_u, b_v;
924
925 if (tpg->alpha_red_only && color != TPG_COLOR_CSC_RED &&
926 color != TPG_COLOR_100_RED &&
927 color != TPG_COLOR_75_RED)
928 alpha = 0;
929 if (color == TPG_COLOR_RANDOM)
930 precalculate_color(tpg, color);
931 r_y = tpg->colors[color][0]; /* R or precalculated Y */
932 g_u = tpg->colors[color][1]; /* G or precalculated U */
933 b_v = tpg->colors[color][2]; /* B or precalculated V */
934
935 switch (tpg->fourcc) {
Hans Verkuil51f30962015-03-07 14:57:50 -0300936 case V4L2_PIX_FMT_GREY:
937 buf[0][offset] = r_y;
938 break;
Ricardo Ribalda18b3b3b2015-05-04 05:07:29 -0300939 case V4L2_PIX_FMT_Y16:
Hans Verkuilafeef4e2015-06-05 03:45:38 -0300940 /*
941 * Ideally both bytes should be set to r_y, but then you won't
942 * be able to detect endian problems. So keep it 0 except for
943 * the corner case where r_y is 0xff so white really will be
944 * white (0xffff).
945 */
946 buf[0][offset] = r_y == 0xff ? r_y : 0;
Ricardo Ribalda18b3b3b2015-05-04 05:07:29 -0300947 buf[0][offset+1] = r_y;
948 break;
Ricardo Ribaldab0ce23f2015-05-04 05:07:31 -0300949 case V4L2_PIX_FMT_Y16_BE:
Hans Verkuilafeef4e2015-06-05 03:45:38 -0300950 /* See comment for V4L2_PIX_FMT_Y16 above */
Ricardo Ribaldab0ce23f2015-05-04 05:07:31 -0300951 buf[0][offset] = r_y;
Hans Verkuilafeef4e2015-06-05 03:45:38 -0300952 buf[0][offset+1] = r_y == 0xff ? r_y : 0;
Ricardo Ribaldab0ce23f2015-05-04 05:07:31 -0300953 break;
Hans Verkuil00036b32016-02-20 06:57:38 -0200954 case V4L2_PIX_FMT_YUV422M:
Hans Verkuil68c90d62015-03-07 14:55:09 -0300955 case V4L2_PIX_FMT_YUV422P:
956 case V4L2_PIX_FMT_YUV420:
957 case V4L2_PIX_FMT_YUV420M:
958 buf[0][offset] = r_y;
959 if (odd) {
960 buf[1][0] = (buf[1][0] + g_u) / 2;
961 buf[2][0] = (buf[2][0] + b_v) / 2;
962 buf[1][1] = buf[1][0];
963 buf[2][1] = buf[2][0];
964 break;
965 }
966 buf[1][0] = g_u;
967 buf[2][0] = b_v;
968 break;
Hans Verkuil00036b32016-02-20 06:57:38 -0200969 case V4L2_PIX_FMT_YVU422M:
Hans Verkuil68c90d62015-03-07 14:55:09 -0300970 case V4L2_PIX_FMT_YVU420:
971 case V4L2_PIX_FMT_YVU420M:
972 buf[0][offset] = r_y;
973 if (odd) {
974 buf[1][0] = (buf[1][0] + b_v) / 2;
975 buf[2][0] = (buf[2][0] + g_u) / 2;
976 buf[1][1] = buf[1][0];
977 buf[2][1] = buf[2][0];
978 break;
979 }
980 buf[1][0] = b_v;
981 buf[2][0] = g_u;
982 break;
983
984 case V4L2_PIX_FMT_NV12:
985 case V4L2_PIX_FMT_NV12M:
986 case V4L2_PIX_FMT_NV16:
Hans Verkuil63881df2014-08-25 08:02:14 -0300987 case V4L2_PIX_FMT_NV16M:
988 buf[0][offset] = r_y;
Hans Verkuil1f088dc2015-03-07 14:15:25 -0300989 if (odd) {
990 buf[1][0] = (buf[1][0] + g_u) / 2;
991 buf[1][1] = (buf[1][1] + b_v) / 2;
992 break;
993 }
994 buf[1][0] = g_u;
995 buf[1][1] = b_v;
Hans Verkuil63881df2014-08-25 08:02:14 -0300996 break;
Hans Verkuil68c90d62015-03-07 14:55:09 -0300997 case V4L2_PIX_FMT_NV21:
998 case V4L2_PIX_FMT_NV21M:
999 case V4L2_PIX_FMT_NV61:
Hans Verkuil63881df2014-08-25 08:02:14 -03001000 case V4L2_PIX_FMT_NV61M:
1001 buf[0][offset] = r_y;
Hans Verkuil1f088dc2015-03-07 14:15:25 -03001002 if (odd) {
1003 buf[1][0] = (buf[1][0] + b_v) / 2;
1004 buf[1][1] = (buf[1][1] + g_u) / 2;
1005 break;
1006 }
1007 buf[1][0] = b_v;
1008 buf[1][1] = g_u;
Hans Verkuil63881df2014-08-25 08:02:14 -03001009 break;
1010
Hans Verkuil00036b32016-02-20 06:57:38 -02001011 case V4L2_PIX_FMT_YUV444M:
1012 buf[0][offset] = r_y;
1013 buf[1][offset] = g_u;
1014 buf[2][offset] = b_v;
1015 break;
1016
1017 case V4L2_PIX_FMT_YVU444M:
1018 buf[0][offset] = r_y;
1019 buf[1][offset] = b_v;
1020 buf[2][offset] = g_u;
1021 break;
1022
Hans Verkuildde72bd2015-03-13 05:51:21 -03001023 case V4L2_PIX_FMT_NV24:
1024 buf[0][offset] = r_y;
1025 buf[1][2 * offset] = g_u;
1026 buf[1][2 * offset + 1] = b_v;
1027 break;
1028
1029 case V4L2_PIX_FMT_NV42:
1030 buf[0][offset] = r_y;
1031 buf[1][2 * offset] = b_v;
1032 buf[1][2 * offset + 1] = g_u;
1033 break;
1034
Hans Verkuil63881df2014-08-25 08:02:14 -03001035 case V4L2_PIX_FMT_YUYV:
1036 buf[0][offset] = r_y;
Hans Verkuil1f088dc2015-03-07 14:15:25 -03001037 if (odd) {
1038 buf[0][1] = (buf[0][1] + g_u) / 2;
1039 buf[0][3] = (buf[0][3] + b_v) / 2;
1040 break;
1041 }
1042 buf[0][1] = g_u;
1043 buf[0][3] = b_v;
Hans Verkuil63881df2014-08-25 08:02:14 -03001044 break;
1045 case V4L2_PIX_FMT_UYVY:
Hans Verkuil63881df2014-08-25 08:02:14 -03001046 buf[0][offset + 1] = r_y;
Hans Verkuil1f088dc2015-03-07 14:15:25 -03001047 if (odd) {
1048 buf[0][0] = (buf[0][0] + g_u) / 2;
1049 buf[0][2] = (buf[0][2] + b_v) / 2;
1050 break;
1051 }
1052 buf[0][0] = g_u;
1053 buf[0][2] = b_v;
Hans Verkuil63881df2014-08-25 08:02:14 -03001054 break;
1055 case V4L2_PIX_FMT_YVYU:
1056 buf[0][offset] = r_y;
Hans Verkuil1f088dc2015-03-07 14:15:25 -03001057 if (odd) {
1058 buf[0][1] = (buf[0][1] + b_v) / 2;
1059 buf[0][3] = (buf[0][3] + g_u) / 2;
1060 break;
1061 }
1062 buf[0][1] = b_v;
1063 buf[0][3] = g_u;
Hans Verkuil63881df2014-08-25 08:02:14 -03001064 break;
1065 case V4L2_PIX_FMT_VYUY:
Hans Verkuil63881df2014-08-25 08:02:14 -03001066 buf[0][offset + 1] = r_y;
Hans Verkuil1f088dc2015-03-07 14:15:25 -03001067 if (odd) {
1068 buf[0][0] = (buf[0][0] + b_v) / 2;
1069 buf[0][2] = (buf[0][2] + g_u) / 2;
1070 break;
1071 }
1072 buf[0][0] = b_v;
1073 buf[0][2] = g_u;
Hans Verkuil63881df2014-08-25 08:02:14 -03001074 break;
Hans Verkuil71491062015-03-12 15:40:36 -03001075 case V4L2_PIX_FMT_RGB332:
1076 buf[0][offset] = (r_y << 5) | (g_u << 2) | b_v;
1077 break;
Hans Verkuil628821c2015-03-13 06:35:40 -03001078 case V4L2_PIX_FMT_YUV565:
Hans Verkuil63881df2014-08-25 08:02:14 -03001079 case V4L2_PIX_FMT_RGB565:
1080 buf[0][offset] = (g_u << 5) | b_v;
1081 buf[0][offset + 1] = (r_y << 3) | (g_u >> 3);
1082 break;
1083 case V4L2_PIX_FMT_RGB565X:
1084 buf[0][offset] = (r_y << 3) | (g_u >> 3);
1085 buf[0][offset + 1] = (g_u << 5) | b_v;
1086 break;
Hans Verkuil8aca2302015-03-11 08:14:34 -03001087 case V4L2_PIX_FMT_RGB444:
1088 case V4L2_PIX_FMT_XRGB444:
1089 alpha = 0;
1090 /* fall through */
Hans Verkuil628821c2015-03-13 06:35:40 -03001091 case V4L2_PIX_FMT_YUV444:
Hans Verkuil8aca2302015-03-11 08:14:34 -03001092 case V4L2_PIX_FMT_ARGB444:
1093 buf[0][offset] = (g_u << 4) | b_v;
1094 buf[0][offset + 1] = (alpha & 0xf0) | r_y;
1095 break;
Hans Verkuil63881df2014-08-25 08:02:14 -03001096 case V4L2_PIX_FMT_RGB555:
1097 case V4L2_PIX_FMT_XRGB555:
1098 alpha = 0;
1099 /* fall through */
Hans Verkuil628821c2015-03-13 06:35:40 -03001100 case V4L2_PIX_FMT_YUV555:
Hans Verkuil63881df2014-08-25 08:02:14 -03001101 case V4L2_PIX_FMT_ARGB555:
1102 buf[0][offset] = (g_u << 5) | b_v;
1103 buf[0][offset + 1] = (alpha & 0x80) | (r_y << 2) | (g_u >> 3);
1104 break;
1105 case V4L2_PIX_FMT_RGB555X:
Hans Verkuil8f1ff542015-03-12 05:08:01 -03001106 case V4L2_PIX_FMT_XRGB555X:
1107 alpha = 0;
1108 /* fall through */
1109 case V4L2_PIX_FMT_ARGB555X:
Hans Verkuil63881df2014-08-25 08:02:14 -03001110 buf[0][offset] = (alpha & 0x80) | (r_y << 2) | (g_u >> 3);
1111 buf[0][offset + 1] = (g_u << 5) | b_v;
1112 break;
1113 case V4L2_PIX_FMT_RGB24:
1114 buf[0][offset] = r_y;
1115 buf[0][offset + 1] = g_u;
1116 buf[0][offset + 2] = b_v;
1117 break;
1118 case V4L2_PIX_FMT_BGR24:
1119 buf[0][offset] = b_v;
1120 buf[0][offset + 1] = g_u;
1121 buf[0][offset + 2] = r_y;
1122 break;
Hans Verkuil68cd4e92015-03-13 05:36:08 -03001123 case V4L2_PIX_FMT_BGR666:
1124 buf[0][offset] = (b_v << 2) | (g_u >> 4);
1125 buf[0][offset + 1] = (g_u << 4) | (r_y >> 2);
1126 buf[0][offset + 2] = r_y << 6;
1127 buf[0][offset + 3] = 0;
1128 break;
Hans Verkuil63881df2014-08-25 08:02:14 -03001129 case V4L2_PIX_FMT_RGB32:
1130 case V4L2_PIX_FMT_XRGB32:
1131 alpha = 0;
1132 /* fall through */
Hans Verkuil628821c2015-03-13 06:35:40 -03001133 case V4L2_PIX_FMT_YUV32:
Hans Verkuil63881df2014-08-25 08:02:14 -03001134 case V4L2_PIX_FMT_ARGB32:
1135 buf[0][offset] = alpha;
1136 buf[0][offset + 1] = r_y;
1137 buf[0][offset + 2] = g_u;
1138 buf[0][offset + 3] = b_v;
1139 break;
1140 case V4L2_PIX_FMT_BGR32:
1141 case V4L2_PIX_FMT_XBGR32:
1142 alpha = 0;
1143 /* fall through */
1144 case V4L2_PIX_FMT_ABGR32:
1145 buf[0][offset] = b_v;
1146 buf[0][offset + 1] = g_u;
1147 buf[0][offset + 2] = r_y;
1148 buf[0][offset + 3] = alpha;
1149 break;
Hans Verkuil02aa7692015-03-14 08:01:50 -03001150 case V4L2_PIX_FMT_SBGGR8:
1151 buf[0][offset] = odd ? g_u : b_v;
1152 buf[1][offset] = odd ? r_y : g_u;
1153 break;
1154 case V4L2_PIX_FMT_SGBRG8:
1155 buf[0][offset] = odd ? b_v : g_u;
1156 buf[1][offset] = odd ? g_u : r_y;
1157 break;
1158 case V4L2_PIX_FMT_SGRBG8:
1159 buf[0][offset] = odd ? r_y : g_u;
1160 buf[1][offset] = odd ? g_u : b_v;
1161 break;
1162 case V4L2_PIX_FMT_SRGGB8:
1163 buf[0][offset] = odd ? g_u : r_y;
1164 buf[1][offset] = odd ? b_v : g_u;
1165 break;
Hans Verkuilb96c5442015-09-21 05:31:19 -03001166 case V4L2_PIX_FMT_SBGGR10:
1167 buf[0][offset] = odd ? g_u << 2 : b_v << 2;
1168 buf[0][offset + 1] = odd ? g_u >> 6 : b_v >> 6;
1169 buf[1][offset] = odd ? r_y << 2 : g_u << 2;
1170 buf[1][offset + 1] = odd ? r_y >> 6 : g_u >> 6;
1171 buf[0][offset] |= (buf[0][offset] >> 2) & 3;
1172 buf[1][offset] |= (buf[1][offset] >> 2) & 3;
1173 break;
1174 case V4L2_PIX_FMT_SGBRG10:
1175 buf[0][offset] = odd ? b_v << 2 : g_u << 2;
1176 buf[0][offset + 1] = odd ? b_v >> 6 : g_u >> 6;
1177 buf[1][offset] = odd ? g_u << 2 : r_y << 2;
1178 buf[1][offset + 1] = odd ? g_u >> 6 : r_y >> 6;
1179 buf[0][offset] |= (buf[0][offset] >> 2) & 3;
1180 buf[1][offset] |= (buf[1][offset] >> 2) & 3;
1181 break;
1182 case V4L2_PIX_FMT_SGRBG10:
1183 buf[0][offset] = odd ? r_y << 2 : g_u << 2;
1184 buf[0][offset + 1] = odd ? r_y >> 6 : g_u >> 6;
1185 buf[1][offset] = odd ? g_u << 2 : b_v << 2;
1186 buf[1][offset + 1] = odd ? g_u >> 6 : b_v >> 6;
1187 buf[0][offset] |= (buf[0][offset] >> 2) & 3;
1188 buf[1][offset] |= (buf[1][offset] >> 2) & 3;
1189 break;
1190 case V4L2_PIX_FMT_SRGGB10:
1191 buf[0][offset] = odd ? g_u << 2 : r_y << 2;
1192 buf[0][offset + 1] = odd ? g_u >> 6 : r_y >> 6;
1193 buf[1][offset] = odd ? b_v << 2 : g_u << 2;
1194 buf[1][offset + 1] = odd ? b_v >> 6 : g_u >> 6;
1195 buf[0][offset] |= (buf[0][offset] >> 2) & 3;
1196 buf[1][offset] |= (buf[1][offset] >> 2) & 3;
1197 break;
1198 case V4L2_PIX_FMT_SBGGR12:
1199 buf[0][offset] = odd ? g_u << 4 : b_v << 4;
1200 buf[0][offset + 1] = odd ? g_u >> 4 : b_v >> 4;
1201 buf[1][offset] = odd ? r_y << 4 : g_u << 4;
1202 buf[1][offset + 1] = odd ? r_y >> 4 : g_u >> 4;
1203 buf[0][offset] |= (buf[0][offset] >> 4) & 0xf;
1204 buf[1][offset] |= (buf[1][offset] >> 4) & 0xf;
1205 break;
1206 case V4L2_PIX_FMT_SGBRG12:
1207 buf[0][offset] = odd ? b_v << 4 : g_u << 4;
1208 buf[0][offset + 1] = odd ? b_v >> 4 : g_u >> 4;
1209 buf[1][offset] = odd ? g_u << 4 : r_y << 4;
1210 buf[1][offset + 1] = odd ? g_u >> 4 : r_y >> 4;
1211 buf[0][offset] |= (buf[0][offset] >> 4) & 0xf;
1212 buf[1][offset] |= (buf[1][offset] >> 4) & 0xf;
1213 break;
1214 case V4L2_PIX_FMT_SGRBG12:
1215 buf[0][offset] = odd ? r_y << 4 : g_u << 4;
1216 buf[0][offset + 1] = odd ? r_y >> 4 : g_u >> 4;
1217 buf[1][offset] = odd ? g_u << 4 : b_v << 4;
1218 buf[1][offset + 1] = odd ? g_u >> 4 : b_v >> 4;
1219 buf[0][offset] |= (buf[0][offset] >> 4) & 0xf;
1220 buf[1][offset] |= (buf[1][offset] >> 4) & 0xf;
1221 break;
1222 case V4L2_PIX_FMT_SRGGB12:
1223 buf[0][offset] = odd ? g_u << 4 : r_y << 4;
1224 buf[0][offset + 1] = odd ? g_u >> 4 : r_y >> 4;
1225 buf[1][offset] = odd ? b_v << 4 : g_u << 4;
1226 buf[1][offset + 1] = odd ? b_v >> 4 : g_u >> 4;
1227 buf[0][offset] |= (buf[0][offset] >> 4) & 0xf;
1228 buf[1][offset] |= (buf[1][offset] >> 4) & 0xf;
1229 break;
Hans Verkuil02aa7692015-03-14 08:01:50 -03001230 }
1231}
1232
1233unsigned tpg_g_interleaved_plane(const struct tpg_data *tpg, unsigned buf_line)
1234{
1235 switch (tpg->fourcc) {
1236 case V4L2_PIX_FMT_SBGGR8:
1237 case V4L2_PIX_FMT_SGBRG8:
1238 case V4L2_PIX_FMT_SGRBG8:
1239 case V4L2_PIX_FMT_SRGGB8:
Hans Verkuilb96c5442015-09-21 05:31:19 -03001240 case V4L2_PIX_FMT_SBGGR10:
1241 case V4L2_PIX_FMT_SGBRG10:
1242 case V4L2_PIX_FMT_SGRBG10:
1243 case V4L2_PIX_FMT_SRGGB10:
1244 case V4L2_PIX_FMT_SBGGR12:
1245 case V4L2_PIX_FMT_SGBRG12:
1246 case V4L2_PIX_FMT_SGRBG12:
1247 case V4L2_PIX_FMT_SRGGB12:
Hans Verkuil02aa7692015-03-14 08:01:50 -03001248 return buf_line & 1;
1249 default:
1250 return 0;
Hans Verkuil63881df2014-08-25 08:02:14 -03001251 }
1252}
1253
1254/* Return how many pattern lines are used by the current pattern. */
Hans Verkuil1a05d312015-03-07 12:49:57 -03001255static unsigned tpg_get_pat_lines(const struct tpg_data *tpg)
Hans Verkuil63881df2014-08-25 08:02:14 -03001256{
1257 switch (tpg->pattern) {
1258 case TPG_PAT_CHECKERS_16X16:
Hans Verkuil1a05d312015-03-07 12:49:57 -03001259 case TPG_PAT_CHECKERS_2X2:
Hans Verkuil63881df2014-08-25 08:02:14 -03001260 case TPG_PAT_CHECKERS_1X1:
Hans Verkuil1a05d312015-03-07 12:49:57 -03001261 case TPG_PAT_COLOR_CHECKERS_2X2:
1262 case TPG_PAT_COLOR_CHECKERS_1X1:
Hans Verkuil63881df2014-08-25 08:02:14 -03001263 case TPG_PAT_ALTERNATING_HLINES:
1264 case TPG_PAT_CROSS_1_PIXEL:
1265 case TPG_PAT_CROSS_2_PIXELS:
1266 case TPG_PAT_CROSS_10_PIXELS:
1267 return 2;
1268 case TPG_PAT_100_COLORSQUARES:
1269 case TPG_PAT_100_HCOLORBAR:
1270 return 8;
1271 default:
1272 return 1;
1273 }
1274}
1275
1276/* Which pattern line should be used for the given frame line. */
Hans Verkuil1a05d312015-03-07 12:49:57 -03001277static unsigned tpg_get_pat_line(const struct tpg_data *tpg, unsigned line)
Hans Verkuil63881df2014-08-25 08:02:14 -03001278{
1279 switch (tpg->pattern) {
1280 case TPG_PAT_CHECKERS_16X16:
1281 return (line >> 4) & 1;
1282 case TPG_PAT_CHECKERS_1X1:
Hans Verkuil1a05d312015-03-07 12:49:57 -03001283 case TPG_PAT_COLOR_CHECKERS_1X1:
Hans Verkuil63881df2014-08-25 08:02:14 -03001284 case TPG_PAT_ALTERNATING_HLINES:
1285 return line & 1;
Hans Verkuil1a05d312015-03-07 12:49:57 -03001286 case TPG_PAT_CHECKERS_2X2:
1287 case TPG_PAT_COLOR_CHECKERS_2X2:
1288 return (line & 2) >> 1;
Hans Verkuil63881df2014-08-25 08:02:14 -03001289 case TPG_PAT_100_COLORSQUARES:
1290 case TPG_PAT_100_HCOLORBAR:
1291 return (line * 8) / tpg->src_height;
1292 case TPG_PAT_CROSS_1_PIXEL:
1293 return line == tpg->src_height / 2;
1294 case TPG_PAT_CROSS_2_PIXELS:
1295 return (line + 1) / 2 == tpg->src_height / 4;
1296 case TPG_PAT_CROSS_10_PIXELS:
1297 return (line + 10) / 20 == tpg->src_height / 40;
1298 default:
1299 return 0;
1300 }
1301}
1302
1303/*
1304 * Which color should be used for the given pattern line and X coordinate.
1305 * Note: x is in the range 0 to 2 * tpg->src_width.
1306 */
Hans Verkuil1a05d312015-03-07 12:49:57 -03001307static enum tpg_color tpg_get_color(const struct tpg_data *tpg,
1308 unsigned pat_line, unsigned x)
Hans Verkuil63881df2014-08-25 08:02:14 -03001309{
1310 /* Maximum number of bars are TPG_COLOR_MAX - otherwise, the input print code
1311 should be modified */
1312 static const enum tpg_color bars[3][8] = {
1313 /* Standard ITU-R 75% color bar sequence */
1314 { TPG_COLOR_CSC_WHITE, TPG_COLOR_75_YELLOW,
1315 TPG_COLOR_75_CYAN, TPG_COLOR_75_GREEN,
1316 TPG_COLOR_75_MAGENTA, TPG_COLOR_75_RED,
1317 TPG_COLOR_75_BLUE, TPG_COLOR_100_BLACK, },
1318 /* Standard ITU-R 100% color bar sequence */
1319 { TPG_COLOR_100_WHITE, TPG_COLOR_100_YELLOW,
1320 TPG_COLOR_100_CYAN, TPG_COLOR_100_GREEN,
1321 TPG_COLOR_100_MAGENTA, TPG_COLOR_100_RED,
1322 TPG_COLOR_100_BLUE, TPG_COLOR_100_BLACK, },
1323 /* Color bar sequence suitable to test CSC */
1324 { TPG_COLOR_CSC_WHITE, TPG_COLOR_CSC_YELLOW,
1325 TPG_COLOR_CSC_CYAN, TPG_COLOR_CSC_GREEN,
1326 TPG_COLOR_CSC_MAGENTA, TPG_COLOR_CSC_RED,
1327 TPG_COLOR_CSC_BLUE, TPG_COLOR_CSC_BLACK, },
1328 };
1329
1330 switch (tpg->pattern) {
1331 case TPG_PAT_75_COLORBAR:
1332 case TPG_PAT_100_COLORBAR:
1333 case TPG_PAT_CSC_COLORBAR:
1334 return bars[tpg->pattern][((x * 8) / tpg->src_width) % 8];
1335 case TPG_PAT_100_COLORSQUARES:
1336 return bars[1][(pat_line + (x * 8) / tpg->src_width) % 8];
1337 case TPG_PAT_100_HCOLORBAR:
1338 return bars[1][pat_line];
1339 case TPG_PAT_BLACK:
1340 return TPG_COLOR_100_BLACK;
1341 case TPG_PAT_WHITE:
1342 return TPG_COLOR_100_WHITE;
1343 case TPG_PAT_RED:
1344 return TPG_COLOR_100_RED;
1345 case TPG_PAT_GREEN:
1346 return TPG_COLOR_100_GREEN;
1347 case TPG_PAT_BLUE:
1348 return TPG_COLOR_100_BLUE;
1349 case TPG_PAT_CHECKERS_16X16:
1350 return (((x >> 4) & 1) ^ (pat_line & 1)) ?
1351 TPG_COLOR_100_BLACK : TPG_COLOR_100_WHITE;
1352 case TPG_PAT_CHECKERS_1X1:
1353 return ((x & 1) ^ (pat_line & 1)) ?
1354 TPG_COLOR_100_WHITE : TPG_COLOR_100_BLACK;
Hans Verkuil1a05d312015-03-07 12:49:57 -03001355 case TPG_PAT_COLOR_CHECKERS_1X1:
1356 return ((x & 1) ^ (pat_line & 1)) ?
1357 TPG_COLOR_100_RED : TPG_COLOR_100_BLUE;
1358 case TPG_PAT_CHECKERS_2X2:
1359 return (((x >> 1) & 1) ^ (pat_line & 1)) ?
1360 TPG_COLOR_100_WHITE : TPG_COLOR_100_BLACK;
1361 case TPG_PAT_COLOR_CHECKERS_2X2:
1362 return (((x >> 1) & 1) ^ (pat_line & 1)) ?
1363 TPG_COLOR_100_RED : TPG_COLOR_100_BLUE;
Hans Verkuil63881df2014-08-25 08:02:14 -03001364 case TPG_PAT_ALTERNATING_HLINES:
1365 return pat_line ? TPG_COLOR_100_WHITE : TPG_COLOR_100_BLACK;
1366 case TPG_PAT_ALTERNATING_VLINES:
1367 return (x & 1) ? TPG_COLOR_100_WHITE : TPG_COLOR_100_BLACK;
1368 case TPG_PAT_CROSS_1_PIXEL:
1369 if (pat_line || (x % tpg->src_width) == tpg->src_width / 2)
1370 return TPG_COLOR_100_BLACK;
1371 return TPG_COLOR_100_WHITE;
1372 case TPG_PAT_CROSS_2_PIXELS:
1373 if (pat_line || ((x % tpg->src_width) + 1) / 2 == tpg->src_width / 4)
1374 return TPG_COLOR_100_BLACK;
1375 return TPG_COLOR_100_WHITE;
1376 case TPG_PAT_CROSS_10_PIXELS:
1377 if (pat_line || ((x % tpg->src_width) + 10) / 20 == tpg->src_width / 40)
1378 return TPG_COLOR_100_BLACK;
1379 return TPG_COLOR_100_WHITE;
1380 case TPG_PAT_GRAY_RAMP:
1381 return TPG_COLOR_RAMP + ((x % tpg->src_width) * 256) / tpg->src_width;
1382 default:
1383 return TPG_COLOR_100_RED;
1384 }
1385}
1386
1387/*
1388 * Given the pixel aspect ratio and video aspect ratio calculate the
1389 * coordinates of a centered square and the coordinates of the border of
1390 * the active video area. The coordinates are relative to the source
1391 * frame rectangle.
1392 */
1393static void tpg_calculate_square_border(struct tpg_data *tpg)
1394{
1395 unsigned w = tpg->src_width;
1396 unsigned h = tpg->src_height;
1397 unsigned sq_w, sq_h;
1398
1399 sq_w = (w * 2 / 5) & ~1;
1400 if (((w - sq_w) / 2) & 1)
1401 sq_w += 2;
1402 sq_h = sq_w;
1403 tpg->square.width = sq_w;
1404 if (tpg->vid_aspect == TPG_VIDEO_ASPECT_16X9_ANAMORPHIC) {
1405 unsigned ana_sq_w = (sq_w / 4) * 3;
1406
1407 if (((w - ana_sq_w) / 2) & 1)
1408 ana_sq_w += 2;
1409 tpg->square.width = ana_sq_w;
1410 }
1411 tpg->square.left = (w - tpg->square.width) / 2;
1412 if (tpg->pix_aspect == TPG_PIXEL_ASPECT_NTSC)
1413 sq_h = sq_w * 10 / 11;
1414 else if (tpg->pix_aspect == TPG_PIXEL_ASPECT_PAL)
1415 sq_h = sq_w * 59 / 54;
1416 tpg->square.height = sq_h;
1417 tpg->square.top = (h - sq_h) / 2;
1418 tpg->border.left = 0;
1419 tpg->border.width = w;
1420 tpg->border.top = 0;
1421 tpg->border.height = h;
1422 switch (tpg->vid_aspect) {
1423 case TPG_VIDEO_ASPECT_4X3:
1424 if (tpg->pix_aspect)
1425 return;
1426 if (3 * w >= 4 * h) {
1427 tpg->border.width = ((4 * h) / 3) & ~1;
1428 if (((w - tpg->border.width) / 2) & ~1)
1429 tpg->border.width -= 2;
1430 tpg->border.left = (w - tpg->border.width) / 2;
1431 break;
1432 }
1433 tpg->border.height = ((3 * w) / 4) & ~1;
1434 tpg->border.top = (h - tpg->border.height) / 2;
1435 break;
1436 case TPG_VIDEO_ASPECT_14X9_CENTRE:
1437 if (tpg->pix_aspect) {
1438 tpg->border.height = tpg->pix_aspect == TPG_PIXEL_ASPECT_NTSC ? 420 : 506;
1439 tpg->border.top = (h - tpg->border.height) / 2;
1440 break;
1441 }
1442 if (9 * w >= 14 * h) {
1443 tpg->border.width = ((14 * h) / 9) & ~1;
1444 if (((w - tpg->border.width) / 2) & ~1)
1445 tpg->border.width -= 2;
1446 tpg->border.left = (w - tpg->border.width) / 2;
1447 break;
1448 }
1449 tpg->border.height = ((9 * w) / 14) & ~1;
1450 tpg->border.top = (h - tpg->border.height) / 2;
1451 break;
1452 case TPG_VIDEO_ASPECT_16X9_CENTRE:
1453 if (tpg->pix_aspect) {
1454 tpg->border.height = tpg->pix_aspect == TPG_PIXEL_ASPECT_NTSC ? 368 : 442;
1455 tpg->border.top = (h - tpg->border.height) / 2;
1456 break;
1457 }
1458 if (9 * w >= 16 * h) {
1459 tpg->border.width = ((16 * h) / 9) & ~1;
1460 if (((w - tpg->border.width) / 2) & ~1)
1461 tpg->border.width -= 2;
1462 tpg->border.left = (w - tpg->border.width) / 2;
1463 break;
1464 }
1465 tpg->border.height = ((9 * w) / 16) & ~1;
1466 tpg->border.top = (h - tpg->border.height) / 2;
1467 break;
1468 default:
1469 break;
1470 }
1471}
1472
1473static void tpg_precalculate_line(struct tpg_data *tpg)
1474{
1475 enum tpg_color contrast;
Hans Verkuil9991def2015-03-08 05:53:10 -03001476 u8 pix[TPG_MAX_PLANES][8];
Hans Verkuil63881df2014-08-25 08:02:14 -03001477 unsigned pat;
1478 unsigned p;
1479 unsigned x;
1480
1481 switch (tpg->pattern) {
1482 case TPG_PAT_GREEN:
1483 contrast = TPG_COLOR_100_RED;
1484 break;
1485 case TPG_PAT_CSC_COLORBAR:
1486 contrast = TPG_COLOR_CSC_GREEN;
1487 break;
1488 default:
1489 contrast = TPG_COLOR_100_GREEN;
1490 break;
1491 }
1492
1493 for (pat = 0; pat < tpg_get_pat_lines(tpg); pat++) {
1494 /* Coarse scaling with Bresenham */
1495 unsigned int_part = tpg->src_width / tpg->scaled_width;
1496 unsigned fract_part = tpg->src_width % tpg->scaled_width;
1497 unsigned src_x = 0;
1498 unsigned error = 0;
1499
1500 for (x = 0; x < tpg->scaled_width * 2; x += 2) {
1501 unsigned real_x = src_x;
1502 enum tpg_color color1, color2;
Hans Verkuil63881df2014-08-25 08:02:14 -03001503
1504 real_x = tpg->hflip ? tpg->src_width * 2 - real_x - 2 : real_x;
1505 color1 = tpg_get_color(tpg, pat, real_x);
1506
1507 src_x += int_part;
1508 error += fract_part;
1509 if (error >= tpg->scaled_width) {
1510 error -= tpg->scaled_width;
1511 src_x++;
1512 }
1513
1514 real_x = src_x;
1515 real_x = tpg->hflip ? tpg->src_width * 2 - real_x - 2 : real_x;
1516 color2 = tpg_get_color(tpg, pat, real_x);
1517
1518 src_x += int_part;
1519 error += fract_part;
1520 if (error >= tpg->scaled_width) {
1521 error -= tpg->scaled_width;
1522 src_x++;
1523 }
1524
1525 gen_twopix(tpg, pix, tpg->hflip ? color2 : color1, 0);
1526 gen_twopix(tpg, pix, tpg->hflip ? color1 : color2, 1);
1527 for (p = 0; p < tpg->planes; p++) {
1528 unsigned twopixsize = tpg->twopixelsize[p];
Hans Verkuil5d7c5392015-03-07 14:06:43 -03001529 unsigned hdiv = tpg->hdownsampling[p];
Hans Verkuil9991def2015-03-08 05:53:10 -03001530 u8 *pos = tpg->lines[pat][p] + tpg_hdiv(tpg, p, x);
Hans Verkuil63881df2014-08-25 08:02:14 -03001531
Hans Verkuil5d7c5392015-03-07 14:06:43 -03001532 memcpy(pos, pix[p], twopixsize / hdiv);
Hans Verkuil63881df2014-08-25 08:02:14 -03001533 }
1534 }
1535 }
Hans Verkuil5d7c5392015-03-07 14:06:43 -03001536
1537 if (tpg->vdownsampling[tpg->planes - 1] > 1) {
1538 unsigned pat_lines = tpg_get_pat_lines(tpg);
1539
1540 for (pat = 0; pat < pat_lines; pat++) {
1541 unsigned next_pat = (pat + 1) % pat_lines;
1542
1543 for (p = 1; p < tpg->planes; p++) {
Hans Verkuil9991def2015-03-08 05:53:10 -03001544 unsigned w = tpg_hdiv(tpg, p, tpg->scaled_width * 2);
1545 u8 *pos1 = tpg->lines[pat][p];
1546 u8 *pos2 = tpg->lines[next_pat][p];
1547 u8 *dest = tpg->downsampled_lines[pat][p];
Hans Verkuil5d7c5392015-03-07 14:06:43 -03001548
Hans Verkuil9991def2015-03-08 05:53:10 -03001549 for (x = 0; x < w; x++, pos1++, pos2++, dest++)
1550 *dest = ((u16)*pos1 + (u16)*pos2) / 2;
Hans Verkuil5d7c5392015-03-07 14:06:43 -03001551 }
1552 }
1553 }
1554
Hans Verkuil9991def2015-03-08 05:53:10 -03001555 gen_twopix(tpg, pix, contrast, 0);
1556 gen_twopix(tpg, pix, contrast, 1);
1557 for (p = 0; p < tpg->planes; p++) {
1558 unsigned twopixsize = tpg->twopixelsize[p];
1559 u8 *pos = tpg->contrast_line[p];
Hans Verkuil63881df2014-08-25 08:02:14 -03001560
Hans Verkuil9991def2015-03-08 05:53:10 -03001561 for (x = 0; x < tpg->scaled_width; x += 2, pos += twopixsize)
Hans Verkuil63881df2014-08-25 08:02:14 -03001562 memcpy(pos, pix[p], twopixsize);
Hans Verkuil63881df2014-08-25 08:02:14 -03001563 }
Hans Verkuil63881df2014-08-25 08:02:14 -03001564
Hans Verkuil9991def2015-03-08 05:53:10 -03001565 gen_twopix(tpg, pix, TPG_COLOR_100_BLACK, 0);
1566 gen_twopix(tpg, pix, TPG_COLOR_100_BLACK, 1);
1567 for (p = 0; p < tpg->planes; p++) {
1568 unsigned twopixsize = tpg->twopixelsize[p];
1569 u8 *pos = tpg->black_line[p];
Hans Verkuil63881df2014-08-25 08:02:14 -03001570
Hans Verkuil9991def2015-03-08 05:53:10 -03001571 for (x = 0; x < tpg->scaled_width; x += 2, pos += twopixsize)
Hans Verkuil63881df2014-08-25 08:02:14 -03001572 memcpy(pos, pix[p], twopixsize);
Hans Verkuil63881df2014-08-25 08:02:14 -03001573 }
Hans Verkuil9991def2015-03-08 05:53:10 -03001574
Hans Verkuil63881df2014-08-25 08:02:14 -03001575 for (x = 0; x < tpg->scaled_width * 2; x += 2) {
Hans Verkuil63881df2014-08-25 08:02:14 -03001576 gen_twopix(tpg, pix, TPG_COLOR_RANDOM, 0);
1577 gen_twopix(tpg, pix, TPG_COLOR_RANDOM, 1);
1578 for (p = 0; p < tpg->planes; p++) {
1579 unsigned twopixsize = tpg->twopixelsize[p];
1580 u8 *pos = tpg->random_line[p] + x * twopixsize / 2;
1581
1582 memcpy(pos, pix[p], twopixsize);
1583 }
1584 }
Hans Verkuil9991def2015-03-08 05:53:10 -03001585
Hans Verkuil63881df2014-08-25 08:02:14 -03001586 gen_twopix(tpg, tpg->textbg, TPG_COLOR_TEXTBG, 0);
1587 gen_twopix(tpg, tpg->textbg, TPG_COLOR_TEXTBG, 1);
1588 gen_twopix(tpg, tpg->textfg, TPG_COLOR_TEXTFG, 0);
1589 gen_twopix(tpg, tpg->textfg, TPG_COLOR_TEXTFG, 1);
1590}
1591
1592/* need this to do rgb24 rendering */
1593typedef struct { u16 __; u8 _; } __packed x24;
1594
Hans Verkuilc70316f2015-06-05 13:09:31 -03001595#define PRINTSTR(PIXTYPE) do { \
1596 unsigned vdiv = tpg->vdownsampling[p]; \
1597 unsigned hdiv = tpg->hdownsampling[p]; \
1598 int line; \
Hans Verkuil63881df2014-08-25 08:02:14 -03001599 PIXTYPE fg; \
1600 PIXTYPE bg; \
1601 memcpy(&fg, tpg->textfg[p], sizeof(PIXTYPE)); \
1602 memcpy(&bg, tpg->textbg[p], sizeof(PIXTYPE)); \
1603 \
Hans Verkuil3e14e7a82015-03-07 14:23:16 -03001604 for (line = first; line < 16; line += vdiv * step) { \
Hans Verkuil63881df2014-08-25 08:02:14 -03001605 int l = tpg->vflip ? 15 - line : line; \
Hans Verkuil3e14e7a82015-03-07 14:23:16 -03001606 PIXTYPE *pos = (PIXTYPE *)(basep[p][(line / vdiv) & 1] + \
1607 ((y * step + l) / (vdiv * div)) * tpg->bytesperline[p] + \
1608 (x / hdiv) * sizeof(PIXTYPE)); \
Hans Verkuil63881df2014-08-25 08:02:14 -03001609 unsigned s; \
1610 \
1611 for (s = 0; s < len; s++) { \
1612 u8 chr = font8x16[text[s] * 16 + line]; \
1613 \
Hans Verkuil3e14e7a82015-03-07 14:23:16 -03001614 if (hdiv == 2 && tpg->hflip) { \
1615 pos[3] = (chr & (0x01 << 6) ? fg : bg); \
1616 pos[2] = (chr & (0x01 << 4) ? fg : bg); \
1617 pos[1] = (chr & (0x01 << 2) ? fg : bg); \
1618 pos[0] = (chr & (0x01 << 0) ? fg : bg); \
1619 } else if (hdiv == 2) { \
1620 pos[0] = (chr & (0x01 << 7) ? fg : bg); \
1621 pos[1] = (chr & (0x01 << 5) ? fg : bg); \
1622 pos[2] = (chr & (0x01 << 3) ? fg : bg); \
1623 pos[3] = (chr & (0x01 << 1) ? fg : bg); \
1624 } else if (tpg->hflip) { \
Hans Verkuil63881df2014-08-25 08:02:14 -03001625 pos[7] = (chr & (0x01 << 7) ? fg : bg); \
1626 pos[6] = (chr & (0x01 << 6) ? fg : bg); \
1627 pos[5] = (chr & (0x01 << 5) ? fg : bg); \
1628 pos[4] = (chr & (0x01 << 4) ? fg : bg); \
1629 pos[3] = (chr & (0x01 << 3) ? fg : bg); \
1630 pos[2] = (chr & (0x01 << 2) ? fg : bg); \
1631 pos[1] = (chr & (0x01 << 1) ? fg : bg); \
1632 pos[0] = (chr & (0x01 << 0) ? fg : bg); \
1633 } else { \
1634 pos[0] = (chr & (0x01 << 7) ? fg : bg); \
1635 pos[1] = (chr & (0x01 << 6) ? fg : bg); \
1636 pos[2] = (chr & (0x01 << 5) ? fg : bg); \
1637 pos[3] = (chr & (0x01 << 4) ? fg : bg); \
1638 pos[4] = (chr & (0x01 << 3) ? fg : bg); \
1639 pos[5] = (chr & (0x01 << 2) ? fg : bg); \
1640 pos[6] = (chr & (0x01 << 1) ? fg : bg); \
1641 pos[7] = (chr & (0x01 << 0) ? fg : bg); \
1642 } \
1643 \
Hans Verkuil3e14e7a82015-03-07 14:23:16 -03001644 pos += (tpg->hflip ? -8 : 8) / hdiv; \
Hans Verkuil63881df2014-08-25 08:02:14 -03001645 } \
1646 } \
1647} while (0)
1648
Hans Verkuilc70316f2015-06-05 13:09:31 -03001649static noinline void tpg_print_str_2(const struct tpg_data *tpg, u8 *basep[TPG_MAX_PLANES][2],
1650 unsigned p, unsigned first, unsigned div, unsigned step,
1651 int y, int x, char *text, unsigned len)
1652{
1653 PRINTSTR(u8);
1654}
1655
1656static noinline void tpg_print_str_4(const struct tpg_data *tpg, u8 *basep[TPG_MAX_PLANES][2],
1657 unsigned p, unsigned first, unsigned div, unsigned step,
1658 int y, int x, char *text, unsigned len)
1659{
1660 PRINTSTR(u16);
1661}
1662
1663static noinline void tpg_print_str_6(const struct tpg_data *tpg, u8 *basep[TPG_MAX_PLANES][2],
1664 unsigned p, unsigned first, unsigned div, unsigned step,
1665 int y, int x, char *text, unsigned len)
1666{
1667 PRINTSTR(x24);
1668}
1669
1670static noinline void tpg_print_str_8(const struct tpg_data *tpg, u8 *basep[TPG_MAX_PLANES][2],
1671 unsigned p, unsigned first, unsigned div, unsigned step,
1672 int y, int x, char *text, unsigned len)
1673{
1674 PRINTSTR(u32);
1675}
1676
1677void tpg_gen_text(const struct tpg_data *tpg, u8 *basep[TPG_MAX_PLANES][2],
1678 int y, int x, char *text)
1679{
1680 unsigned step = V4L2_FIELD_HAS_T_OR_B(tpg->field) ? 2 : 1;
1681 unsigned div = step;
1682 unsigned first = 0;
1683 unsigned len = strlen(text);
1684 unsigned p;
1685
1686 if (font8x16 == NULL || basep == NULL)
1687 return;
1688
1689 /* Checks if it is possible to show string */
1690 if (y + 16 >= tpg->compose.height || x + 8 >= tpg->compose.width)
1691 return;
1692
1693 if (len > (tpg->compose.width - x) / 8)
1694 len = (tpg->compose.width - x) / 8;
1695 if (tpg->vflip)
1696 y = tpg->compose.height - y - 16;
1697 if (tpg->hflip)
1698 x = tpg->compose.width - x - 8;
1699 y += tpg->compose.top;
1700 x += tpg->compose.left;
1701 if (tpg->field == V4L2_FIELD_BOTTOM)
1702 first = 1;
1703 else if (tpg->field == V4L2_FIELD_SEQ_TB || tpg->field == V4L2_FIELD_SEQ_BT)
1704 div = 2;
1705
1706 for (p = 0; p < tpg->planes; p++) {
1707 /* Print text */
1708 switch (tpg->twopixelsize[p]) {
1709 case 2:
1710 tpg_print_str_2(tpg, basep, p, first, div, step, y, x,
1711 text, len);
1712 break;
1713 case 4:
1714 tpg_print_str_4(tpg, basep, p, first, div, step, y, x,
1715 text, len);
1716 break;
1717 case 6:
1718 tpg_print_str_6(tpg, basep, p, first, div, step, y, x,
1719 text, len);
1720 break;
1721 case 8:
1722 tpg_print_str_8(tpg, basep, p, first, div, step, y, x,
1723 text, len);
1724 break;
1725 }
Hans Verkuil63881df2014-08-25 08:02:14 -03001726 }
1727}
1728
1729void tpg_update_mv_step(struct tpg_data *tpg)
1730{
1731 int factor = tpg->mv_hor_mode > TPG_MOVE_NONE ? -1 : 1;
1732
1733 if (tpg->hflip)
1734 factor = -factor;
1735 switch (tpg->mv_hor_mode) {
1736 case TPG_MOVE_NEG_FAST:
1737 case TPG_MOVE_POS_FAST:
1738 tpg->mv_hor_step = ((tpg->src_width + 319) / 320) * 4;
1739 break;
1740 case TPG_MOVE_NEG:
1741 case TPG_MOVE_POS:
1742 tpg->mv_hor_step = ((tpg->src_width + 639) / 640) * 4;
1743 break;
1744 case TPG_MOVE_NEG_SLOW:
1745 case TPG_MOVE_POS_SLOW:
1746 tpg->mv_hor_step = 2;
1747 break;
1748 case TPG_MOVE_NONE:
1749 tpg->mv_hor_step = 0;
1750 break;
1751 }
1752 if (factor < 0)
1753 tpg->mv_hor_step = tpg->src_width - tpg->mv_hor_step;
1754
1755 factor = tpg->mv_vert_mode > TPG_MOVE_NONE ? -1 : 1;
1756 switch (tpg->mv_vert_mode) {
1757 case TPG_MOVE_NEG_FAST:
1758 case TPG_MOVE_POS_FAST:
1759 tpg->mv_vert_step = ((tpg->src_width + 319) / 320) * 4;
1760 break;
1761 case TPG_MOVE_NEG:
1762 case TPG_MOVE_POS:
1763 tpg->mv_vert_step = ((tpg->src_width + 639) / 640) * 4;
1764 break;
1765 case TPG_MOVE_NEG_SLOW:
1766 case TPG_MOVE_POS_SLOW:
1767 tpg->mv_vert_step = 1;
1768 break;
1769 case TPG_MOVE_NONE:
1770 tpg->mv_vert_step = 0;
1771 break;
1772 }
1773 if (factor < 0)
1774 tpg->mv_vert_step = tpg->src_height - tpg->mv_vert_step;
1775}
1776
1777/* Map the line number relative to the crop rectangle to a frame line number */
Hans Verkuildfff0482015-03-09 11:04:02 -03001778static unsigned tpg_calc_frameline(const struct tpg_data *tpg, unsigned src_y,
Hans Verkuil63881df2014-08-25 08:02:14 -03001779 unsigned field)
1780{
1781 switch (field) {
1782 case V4L2_FIELD_TOP:
1783 return tpg->crop.top + src_y * 2;
1784 case V4L2_FIELD_BOTTOM:
1785 return tpg->crop.top + src_y * 2 + 1;
1786 default:
1787 return src_y + tpg->crop.top;
1788 }
1789}
1790
1791/*
1792 * Map the line number relative to the compose rectangle to a destination
1793 * buffer line number.
1794 */
Hans Verkuildfff0482015-03-09 11:04:02 -03001795static unsigned tpg_calc_buffer_line(const struct tpg_data *tpg, unsigned y,
Hans Verkuil63881df2014-08-25 08:02:14 -03001796 unsigned field)
1797{
1798 y += tpg->compose.top;
1799 switch (field) {
1800 case V4L2_FIELD_SEQ_TB:
1801 if (y & 1)
1802 return tpg->buf_height / 2 + y / 2;
1803 return y / 2;
1804 case V4L2_FIELD_SEQ_BT:
1805 if (y & 1)
1806 return y / 2;
1807 return tpg->buf_height / 2 + y / 2;
1808 default:
1809 return y;
1810 }
1811}
1812
1813static void tpg_recalc(struct tpg_data *tpg)
1814{
1815 if (tpg->recalc_colors) {
1816 tpg->recalc_colors = false;
1817 tpg->recalc_lines = true;
Hans Verkuilca5316d2015-04-28 09:41:37 -03001818 tpg->real_xfer_func = tpg->xfer_func;
Hans Verkuil481b97a2014-11-17 10:14:32 -03001819 tpg->real_ycbcr_enc = tpg->ycbcr_enc;
1820 tpg->real_quantization = tpg->quantization;
Hans Verkuilca5316d2015-04-28 09:41:37 -03001821
1822 if (tpg->xfer_func == V4L2_XFER_FUNC_DEFAULT)
1823 tpg->real_xfer_func =
1824 V4L2_MAP_XFER_FUNC_DEFAULT(tpg->colorspace);
1825
Hans Verkuil9c54fae2015-05-15 09:29:10 -03001826 if (tpg->ycbcr_enc == V4L2_YCBCR_ENC_DEFAULT)
1827 tpg->real_ycbcr_enc =
1828 V4L2_MAP_YCBCR_ENC_DEFAULT(tpg->colorspace);
1829
1830 if (tpg->quantization == V4L2_QUANTIZATION_DEFAULT)
1831 tpg->real_quantization =
1832 V4L2_MAP_QUANTIZATION_DEFAULT(!tpg->is_yuv,
1833 tpg->colorspace, tpg->real_ycbcr_enc);
1834
Hans Verkuil63881df2014-08-25 08:02:14 -03001835 tpg_precalculate_colors(tpg);
1836 }
1837 if (tpg->recalc_square_border) {
1838 tpg->recalc_square_border = false;
1839 tpg_calculate_square_border(tpg);
1840 }
1841 if (tpg->recalc_lines) {
1842 tpg->recalc_lines = false;
1843 tpg_precalculate_line(tpg);
1844 }
1845}
1846
1847void tpg_calc_text_basep(struct tpg_data *tpg,
1848 u8 *basep[TPG_MAX_PLANES][2], unsigned p, u8 *vbuf)
1849{
1850 unsigned stride = tpg->bytesperline[p];
Hans Verkuil280abe42015-03-07 14:50:41 -03001851 unsigned h = tpg->buf_height;
Hans Verkuil63881df2014-08-25 08:02:14 -03001852
1853 tpg_recalc(tpg);
1854
1855 basep[p][0] = vbuf;
1856 basep[p][1] = vbuf;
Hans Verkuil280abe42015-03-07 14:50:41 -03001857 h /= tpg->vdownsampling[p];
Hans Verkuil63881df2014-08-25 08:02:14 -03001858 if (tpg->field == V4L2_FIELD_SEQ_TB)
Hans Verkuil280abe42015-03-07 14:50:41 -03001859 basep[p][1] += h * stride / 2;
Hans Verkuil63881df2014-08-25 08:02:14 -03001860 else if (tpg->field == V4L2_FIELD_SEQ_BT)
Hans Verkuil280abe42015-03-07 14:50:41 -03001861 basep[p][0] += h * stride / 2;
Hans Verkuil02aa7692015-03-14 08:01:50 -03001862 if (p == 0 && tpg->interleaved)
1863 tpg_calc_text_basep(tpg, basep, 1, vbuf);
Hans Verkuil280abe42015-03-07 14:50:41 -03001864}
1865
1866static int tpg_pattern_avg(const struct tpg_data *tpg,
1867 unsigned pat1, unsigned pat2)
1868{
1869 unsigned pat_lines = tpg_get_pat_lines(tpg);
1870
1871 if (pat1 == (pat2 + 1) % pat_lines)
1872 return pat2;
1873 if (pat2 == (pat1 + 1) % pat_lines)
1874 return pat1;
1875 return -1;
Hans Verkuil63881df2014-08-25 08:02:14 -03001876}
1877
Hans Verkuil84b76d72015-04-24 11:16:22 -03001878void tpg_log_status(struct tpg_data *tpg)
1879{
1880 pr_info("tpg source WxH: %ux%u (%s)\n",
1881 tpg->src_width, tpg->src_height,
1882 tpg->is_yuv ? "YCbCr" : "RGB");
1883 pr_info("tpg field: %u\n", tpg->field);
1884 pr_info("tpg crop: %ux%u@%dx%d\n", tpg->crop.width, tpg->crop.height,
1885 tpg->crop.left, tpg->crop.top);
1886 pr_info("tpg compose: %ux%u@%dx%d\n", tpg->compose.width, tpg->compose.height,
1887 tpg->compose.left, tpg->compose.top);
1888 pr_info("tpg colorspace: %d\n", tpg->colorspace);
Hans Verkuilca5316d2015-04-28 09:41:37 -03001889 pr_info("tpg transfer function: %d/%d\n", tpg->xfer_func, tpg->real_xfer_func);
Hans Verkuil84b76d72015-04-24 11:16:22 -03001890 pr_info("tpg Y'CbCr encoding: %d/%d\n", tpg->ycbcr_enc, tpg->real_ycbcr_enc);
1891 pr_info("tpg quantization: %d/%d\n", tpg->quantization, tpg->real_quantization);
1892 pr_info("tpg RGB range: %d/%d\n", tpg->rgb_range, tpg->real_rgb_range);
1893}
1894
Hans Verkuile76036d2015-03-09 11:07:23 -03001895/*
1896 * This struct contains common parameters used by both the drawing of the
1897 * test pattern and the drawing of the extras (borders, square, etc.)
1898 */
1899struct tpg_draw_params {
1900 /* common data */
1901 bool is_tv;
1902 bool is_60hz;
1903 unsigned twopixsize;
1904 unsigned img_width;
1905 unsigned stride;
1906 unsigned hmax;
1907 unsigned frame_line;
1908 unsigned frame_line_next;
1909
1910 /* test pattern */
1911 unsigned mv_hor_old;
1912 unsigned mv_hor_new;
1913 unsigned mv_vert_old;
1914 unsigned mv_vert_new;
1915
1916 /* extras */
1917 unsigned wss_width;
1918 unsigned wss_random_offset;
1919 unsigned sav_eav_f;
1920 unsigned left_pillar_width;
1921 unsigned right_pillar_start;
1922};
1923
Hans Verkuilf0ce4fd2015-03-09 11:30:05 -03001924static void tpg_fill_params_pattern(const struct tpg_data *tpg, unsigned p,
1925 struct tpg_draw_params *params)
1926{
1927 params->mv_hor_old =
1928 tpg_hscale_div(tpg, p, tpg->mv_hor_count % tpg->src_width);
1929 params->mv_hor_new =
1930 tpg_hscale_div(tpg, p, (tpg->mv_hor_count + tpg->mv_hor_step) %
1931 tpg->src_width);
1932 params->mv_vert_old = tpg->mv_vert_count % tpg->src_height;
1933 params->mv_vert_new =
1934 (tpg->mv_vert_count + tpg->mv_vert_step) % tpg->src_height;
1935}
1936
Hans Verkuil07386b92015-03-09 11:39:19 -03001937static void tpg_fill_params_extras(const struct tpg_data *tpg,
1938 unsigned p,
1939 struct tpg_draw_params *params)
1940{
1941 unsigned left_pillar_width = 0;
1942 unsigned right_pillar_start = params->img_width;
1943
1944 params->wss_width = tpg->crop.left < tpg->src_width / 2 ?
1945 tpg->src_width / 2 - tpg->crop.left : 0;
1946 if (params->wss_width > tpg->crop.width)
1947 params->wss_width = tpg->crop.width;
1948 params->wss_width = tpg_hscale_div(tpg, p, params->wss_width);
1949 params->wss_random_offset =
1950 params->twopixsize * prandom_u32_max(tpg->src_width / 2);
1951
1952 if (tpg->crop.left < tpg->border.left) {
1953 left_pillar_width = tpg->border.left - tpg->crop.left;
1954 if (left_pillar_width > tpg->crop.width)
1955 left_pillar_width = tpg->crop.width;
1956 left_pillar_width = tpg_hscale_div(tpg, p, left_pillar_width);
1957 }
1958 params->left_pillar_width = left_pillar_width;
1959
1960 if (tpg->crop.left + tpg->crop.width >
1961 tpg->border.left + tpg->border.width) {
1962 right_pillar_start =
1963 tpg->border.left + tpg->border.width - tpg->crop.left;
1964 right_pillar_start =
1965 tpg_hscale_div(tpg, p, right_pillar_start);
1966 if (right_pillar_start > params->img_width)
1967 right_pillar_start = params->img_width;
1968 }
1969 params->right_pillar_start = right_pillar_start;
1970
1971 params->sav_eav_f = tpg->field ==
1972 (params->is_60hz ? V4L2_FIELD_TOP : V4L2_FIELD_BOTTOM);
1973}
1974
Hans Verkuilc6ff1c12015-03-09 11:47:48 -03001975static void tpg_fill_plane_extras(const struct tpg_data *tpg,
1976 const struct tpg_draw_params *params,
1977 unsigned p, unsigned h, u8 *vbuf)
1978{
1979 unsigned twopixsize = params->twopixsize;
1980 unsigned img_width = params->img_width;
1981 unsigned frame_line = params->frame_line;
1982 const struct v4l2_rect *sq = &tpg->square;
1983 const struct v4l2_rect *b = &tpg->border;
1984 const struct v4l2_rect *c = &tpg->crop;
1985
1986 if (params->is_tv && !params->is_60hz &&
1987 frame_line == 0 && params->wss_width) {
1988 /*
1989 * Replace the first half of the top line of a 50 Hz frame
1990 * with random data to simulate a WSS signal.
1991 */
1992 u8 *wss = tpg->random_line[p] + params->wss_random_offset;
1993
1994 memcpy(vbuf, wss, params->wss_width);
1995 }
1996
1997 if (tpg->show_border && frame_line >= b->top &&
1998 frame_line < b->top + b->height) {
1999 unsigned bottom = b->top + b->height - 1;
2000 unsigned left = params->left_pillar_width;
2001 unsigned right = params->right_pillar_start;
2002
2003 if (frame_line == b->top || frame_line == b->top + 1 ||
2004 frame_line == bottom || frame_line == bottom - 1) {
2005 memcpy(vbuf + left, tpg->contrast_line[p],
2006 right - left);
2007 } else {
2008 if (b->left >= c->left &&
2009 b->left < c->left + c->width)
2010 memcpy(vbuf + left,
2011 tpg->contrast_line[p], twopixsize);
2012 if (b->left + b->width > c->left &&
2013 b->left + b->width <= c->left + c->width)
2014 memcpy(vbuf + right - twopixsize,
2015 tpg->contrast_line[p], twopixsize);
2016 }
2017 }
2018 if (tpg->qual != TPG_QUAL_NOISE && frame_line >= b->top &&
2019 frame_line < b->top + b->height) {
2020 memcpy(vbuf, tpg->black_line[p], params->left_pillar_width);
2021 memcpy(vbuf + params->right_pillar_start, tpg->black_line[p],
2022 img_width - params->right_pillar_start);
2023 }
2024 if (tpg->show_square && frame_line >= sq->top &&
2025 frame_line < sq->top + sq->height &&
2026 sq->left < c->left + c->width &&
2027 sq->left + sq->width >= c->left) {
2028 unsigned left = sq->left;
2029 unsigned width = sq->width;
2030
2031 if (c->left > left) {
2032 width -= c->left - left;
2033 left = c->left;
2034 }
2035 if (c->left + c->width < left + width)
2036 width -= left + width - c->left - c->width;
2037 left -= c->left;
2038 left = tpg_hscale_div(tpg, p, left);
2039 width = tpg_hscale_div(tpg, p, width);
2040 memcpy(vbuf + left, tpg->contrast_line[p], width);
2041 }
2042 if (tpg->insert_sav) {
2043 unsigned offset = tpg_hdiv(tpg, p, tpg->compose.width / 3);
2044 u8 *p = vbuf + offset;
2045 unsigned vact = 0, hact = 0;
2046
2047 p[0] = 0xff;
2048 p[1] = 0;
2049 p[2] = 0;
2050 p[3] = 0x80 | (params->sav_eav_f << 6) |
2051 (vact << 5) | (hact << 4) |
2052 ((hact ^ vact) << 3) |
2053 ((hact ^ params->sav_eav_f) << 2) |
2054 ((params->sav_eav_f ^ vact) << 1) |
2055 (hact ^ vact ^ params->sav_eav_f);
2056 }
2057 if (tpg->insert_eav) {
2058 unsigned offset = tpg_hdiv(tpg, p, tpg->compose.width * 2 / 3);
2059 u8 *p = vbuf + offset;
2060 unsigned vact = 0, hact = 1;
2061
2062 p[0] = 0xff;
2063 p[1] = 0;
2064 p[2] = 0;
2065 p[3] = 0x80 | (params->sav_eav_f << 6) |
2066 (vact << 5) | (hact << 4) |
2067 ((hact ^ vact) << 3) |
2068 ((hact ^ params->sav_eav_f) << 2) |
2069 ((params->sav_eav_f ^ vact) << 1) |
2070 (hact ^ vact ^ params->sav_eav_f);
2071 }
2072}
2073
Hans Verkuilecb9e912015-03-09 11:52:43 -03002074static void tpg_fill_plane_pattern(const struct tpg_data *tpg,
2075 const struct tpg_draw_params *params,
2076 unsigned p, unsigned h, u8 *vbuf)
2077{
2078 unsigned twopixsize = params->twopixsize;
2079 unsigned img_width = params->img_width;
2080 unsigned mv_hor_old = params->mv_hor_old;
2081 unsigned mv_hor_new = params->mv_hor_new;
2082 unsigned mv_vert_old = params->mv_vert_old;
2083 unsigned mv_vert_new = params->mv_vert_new;
2084 unsigned frame_line = params->frame_line;
2085 unsigned frame_line_next = params->frame_line_next;
2086 unsigned line_offset = tpg_hscale_div(tpg, p, tpg->crop.left);
2087 bool even;
2088 bool fill_blank = false;
2089 unsigned pat_line_old;
2090 unsigned pat_line_new;
2091 u8 *linestart_older;
2092 u8 *linestart_newer;
2093 u8 *linestart_top;
2094 u8 *linestart_bottom;
2095
2096 even = !(frame_line & 1);
2097
2098 if (h >= params->hmax) {
2099 if (params->hmax == tpg->compose.height)
2100 return;
2101 if (!tpg->perc_fill_blank)
2102 return;
2103 fill_blank = true;
2104 }
2105
2106 if (tpg->vflip) {
2107 frame_line = tpg->src_height - frame_line - 1;
2108 frame_line_next = tpg->src_height - frame_line_next - 1;
2109 }
2110
2111 if (fill_blank) {
2112 linestart_older = tpg->contrast_line[p];
2113 linestart_newer = tpg->contrast_line[p];
2114 } else if (tpg->qual != TPG_QUAL_NOISE &&
2115 (frame_line < tpg->border.top ||
2116 frame_line >= tpg->border.top + tpg->border.height)) {
2117 linestart_older = tpg->black_line[p];
2118 linestart_newer = tpg->black_line[p];
2119 } else if (tpg->pattern == TPG_PAT_NOISE || tpg->qual == TPG_QUAL_NOISE) {
2120 linestart_older = tpg->random_line[p] +
2121 twopixsize * prandom_u32_max(tpg->src_width / 2);
2122 linestart_newer = tpg->random_line[p] +
2123 twopixsize * prandom_u32_max(tpg->src_width / 2);
2124 } else {
2125 unsigned frame_line_old =
2126 (frame_line + mv_vert_old) % tpg->src_height;
2127 unsigned frame_line_new =
2128 (frame_line + mv_vert_new) % tpg->src_height;
2129 unsigned pat_line_next_old;
2130 unsigned pat_line_next_new;
2131
2132 pat_line_old = tpg_get_pat_line(tpg, frame_line_old);
2133 pat_line_new = tpg_get_pat_line(tpg, frame_line_new);
2134 linestart_older = tpg->lines[pat_line_old][p] + mv_hor_old;
2135 linestart_newer = tpg->lines[pat_line_new][p] + mv_hor_new;
2136
2137 if (tpg->vdownsampling[p] > 1 && frame_line != frame_line_next) {
2138 int avg_pat;
2139
2140 /*
2141 * Now decide whether we need to use downsampled_lines[].
2142 * That's necessary if the two lines use different patterns.
2143 */
2144 pat_line_next_old = tpg_get_pat_line(tpg,
2145 (frame_line_next + mv_vert_old) % tpg->src_height);
2146 pat_line_next_new = tpg_get_pat_line(tpg,
2147 (frame_line_next + mv_vert_new) % tpg->src_height);
2148
2149 switch (tpg->field) {
2150 case V4L2_FIELD_INTERLACED:
2151 case V4L2_FIELD_INTERLACED_BT:
2152 case V4L2_FIELD_INTERLACED_TB:
2153 avg_pat = tpg_pattern_avg(tpg, pat_line_old, pat_line_new);
2154 if (avg_pat < 0)
2155 break;
2156 linestart_older = tpg->downsampled_lines[avg_pat][p] + mv_hor_old;
2157 linestart_newer = linestart_older;
2158 break;
2159 case V4L2_FIELD_NONE:
2160 case V4L2_FIELD_TOP:
2161 case V4L2_FIELD_BOTTOM:
2162 case V4L2_FIELD_SEQ_BT:
2163 case V4L2_FIELD_SEQ_TB:
2164 avg_pat = tpg_pattern_avg(tpg, pat_line_old, pat_line_next_old);
2165 if (avg_pat >= 0)
2166 linestart_older = tpg->downsampled_lines[avg_pat][p] +
2167 mv_hor_old;
2168 avg_pat = tpg_pattern_avg(tpg, pat_line_new, pat_line_next_new);
2169 if (avg_pat >= 0)
2170 linestart_newer = tpg->downsampled_lines[avg_pat][p] +
2171 mv_hor_new;
2172 break;
2173 }
2174 }
2175 linestart_older += line_offset;
2176 linestart_newer += line_offset;
2177 }
2178 if (tpg->field_alternate) {
2179 linestart_top = linestart_bottom = linestart_older;
2180 } else if (params->is_60hz) {
2181 linestart_top = linestart_newer;
2182 linestart_bottom = linestart_older;
2183 } else {
2184 linestart_top = linestart_older;
2185 linestart_bottom = linestart_newer;
2186 }
2187
2188 switch (tpg->field) {
2189 case V4L2_FIELD_INTERLACED:
2190 case V4L2_FIELD_INTERLACED_TB:
2191 case V4L2_FIELD_SEQ_TB:
2192 case V4L2_FIELD_SEQ_BT:
2193 if (even)
2194 memcpy(vbuf, linestart_top, img_width);
2195 else
2196 memcpy(vbuf, linestart_bottom, img_width);
2197 break;
2198 case V4L2_FIELD_INTERLACED_BT:
2199 if (even)
2200 memcpy(vbuf, linestart_bottom, img_width);
2201 else
2202 memcpy(vbuf, linestart_top, img_width);
2203 break;
2204 case V4L2_FIELD_TOP:
2205 memcpy(vbuf, linestart_top, img_width);
2206 break;
2207 case V4L2_FIELD_BOTTOM:
2208 memcpy(vbuf, linestart_bottom, img_width);
2209 break;
2210 case V4L2_FIELD_NONE:
2211 default:
2212 memcpy(vbuf, linestart_older, img_width);
2213 break;
2214 }
2215}
2216
2217void tpg_fill_plane_buffer(struct tpg_data *tpg, v4l2_std_id std,
2218 unsigned p, u8 *vbuf)
Hans Verkuil63881df2014-08-25 08:02:14 -03002219{
Hans Verkuil5e729392015-03-09 11:26:43 -03002220 struct tpg_draw_params params;
Hans Verkuil63881df2014-08-25 08:02:14 -03002221 unsigned factor = V4L2_FIELD_HAS_T_OR_B(tpg->field) ? 2 : 1;
Hans Verkuil63881df2014-08-25 08:02:14 -03002222
2223 /* Coarse scaling with Bresenham */
2224 unsigned int_part = (tpg->crop.height / factor) / tpg->compose.height;
2225 unsigned fract_part = (tpg->crop.height / factor) % tpg->compose.height;
2226 unsigned src_y = 0;
2227 unsigned error = 0;
Hans Verkuilecb9e912015-03-09 11:52:43 -03002228 unsigned h;
Hans Verkuil63881df2014-08-25 08:02:14 -03002229
2230 tpg_recalc(tpg);
2231
Hans Verkuil5e729392015-03-09 11:26:43 -03002232 params.is_tv = std;
2233 params.is_60hz = std & V4L2_STD_525_60;
2234 params.twopixsize = tpg->twopixelsize[p];
2235 params.img_width = tpg_hdiv(tpg, p, tpg->compose.width);
2236 params.stride = tpg->bytesperline[p];
2237 params.hmax = (tpg->compose.height * tpg->perc_fill) / 100;
2238
Hans Verkuilf0ce4fd2015-03-09 11:30:05 -03002239 tpg_fill_params_pattern(tpg, p, &params);
Hans Verkuil07386b92015-03-09 11:39:19 -03002240 tpg_fill_params_extras(tpg, p, &params);
2241
Hans Verkuil9991def2015-03-08 05:53:10 -03002242 vbuf += tpg_hdiv(tpg, p, tpg->compose.left);
Hans Verkuil63881df2014-08-25 08:02:14 -03002243
2244 for (h = 0; h < tpg->compose.height; h++) {
Hans Verkuil63881df2014-08-25 08:02:14 -03002245 unsigned buf_line;
Hans Verkuil63881df2014-08-25 08:02:14 -03002246
Hans Verkuilc6ff1c12015-03-09 11:47:48 -03002247 params.frame_line = tpg_calc_frameline(tpg, src_y, tpg->field);
2248 params.frame_line_next = params.frame_line;
Hans Verkuil63881df2014-08-25 08:02:14 -03002249 buf_line = tpg_calc_buffer_line(tpg, h, tpg->field);
2250 src_y += int_part;
2251 error += fract_part;
2252 if (error >= tpg->compose.height) {
2253 error -= tpg->compose.height;
2254 src_y++;
2255 }
2256
Hans Verkuil02aa7692015-03-14 08:01:50 -03002257 /*
2258 * For line-interleaved formats determine the 'plane'
2259 * based on the buffer line.
2260 */
2261 if (tpg_g_interleaved(tpg))
2262 p = tpg_g_interleaved_plane(tpg, buf_line);
2263
Hans Verkuilecb9e912015-03-09 11:52:43 -03002264 if (tpg->vdownsampling[p] > 1) {
Hans Verkuil280abe42015-03-07 14:50:41 -03002265 /*
2266 * When doing vertical downsampling the field setting
2267 * matters: for SEQ_BT/TB we downsample each field
2268 * separately (i.e. lines 0+2 are combined, as are
2269 * lines 1+3), for the other field settings we combine
2270 * odd and even lines. Doing that for SEQ_BT/TB would
2271 * be really weird.
2272 */
2273 if (tpg->field == V4L2_FIELD_SEQ_BT ||
2274 tpg->field == V4L2_FIELD_SEQ_TB) {
Hans Verkuilecb9e912015-03-09 11:52:43 -03002275 unsigned next_src_y = src_y;
2276
Hans Verkuil280abe42015-03-07 14:50:41 -03002277 if ((h & 3) >= 2)
2278 continue;
Hans Verkuilecb9e912015-03-09 11:52:43 -03002279 next_src_y += int_part;
2280 if (error + fract_part >= tpg->compose.height)
2281 next_src_y++;
2282 params.frame_line_next =
2283 tpg_calc_frameline(tpg, next_src_y, tpg->field);
2284 } else {
2285 if (h & 1)
2286 continue;
2287 params.frame_line_next =
2288 tpg_calc_frameline(tpg, src_y, tpg->field);
Hans Verkuil280abe42015-03-07 14:50:41 -03002289 }
2290
Hans Verkuilecb9e912015-03-09 11:52:43 -03002291 buf_line /= tpg->vdownsampling[p];
Hans Verkuil280abe42015-03-07 14:50:41 -03002292 }
Hans Verkuilecb9e912015-03-09 11:52:43 -03002293 tpg_fill_plane_pattern(tpg, &params, p, h,
2294 vbuf + buf_line * params.stride);
Hans Verkuilc6ff1c12015-03-09 11:47:48 -03002295 tpg_fill_plane_extras(tpg, &params, p, h,
2296 vbuf + buf_line * params.stride);
Hans Verkuil63881df2014-08-25 08:02:14 -03002297 }
2298}
Hans Verkuil4db22042015-03-07 13:39:01 -03002299
2300void tpg_fillbuffer(struct tpg_data *tpg, v4l2_std_id std, unsigned p, u8 *vbuf)
2301{
2302 unsigned offset = 0;
2303 unsigned i;
2304
2305 if (tpg->buffers > 1) {
2306 tpg_fill_plane_buffer(tpg, std, p, vbuf);
2307 return;
2308 }
2309
Hans Verkuil02aa7692015-03-14 08:01:50 -03002310 for (i = 0; i < tpg_g_planes(tpg); i++) {
Hans Verkuil4db22042015-03-07 13:39:01 -03002311 tpg_fill_plane_buffer(tpg, std, i, vbuf + offset);
2312 offset += tpg_calc_plane_size(tpg, i);
2313 }
2314}