[media] vivid-tpg: add full range SMPTE 240M support
[linux-block.git] / drivers / media / platform / vivid / vivid-tpg.c
CommitLineData
63881df9
HV
1/*
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",
1a05d313 38 "2x2 Checkers",
63881df9 39 "1x1 Checkers",
1a05d313
HV
40 "2x2 Red/Green Checkers",
41 "1x1 Red/Green Checkers",
63881df9
HV
42 "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++) {
dde72bd7 126 unsigned pixelsz = plane ? 2 : 4;
63881df9
HV
127
128 tpg->lines[pat][plane] = vzalloc(max_w * 2 * pixelsz);
129 if (!tpg->lines[pat][plane])
130 return -ENOMEM;
5d7c539e
HV
131 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;
63881df9
HV
136 }
137 }
138 for (plane = 0; plane < TPG_MAX_PLANES; plane++) {
dde72bd7 139 unsigned pixelsz = plane ? 2 : 4;
63881df9
HV
140
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;
c204e1fa 147 tpg->random_line[plane] = vzalloc(max_w * 2 * pixelsz);
63881df9
HV
148 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;
5d7c539e
HV
163 if (plane == 0)
164 continue;
165 vfree(tpg->downsampled_lines[pat][plane]);
166 tpg->downsampled_lines[pat][plane] = NULL;
63881df9
HV
167 }
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;
06d1f0c2 182 tpg->buffers = 1;
63881df9 183 tpg->recalc_colors = true;
02aa769d 184 tpg->interleaved = false;
ba01f673
HV
185 tpg->vdownsampling[0] = 1;
186 tpg->hdownsampling[0] = 1;
9991deff
HV
187 tpg->hmask[0] = ~0;
188 tpg->hmask[1] = ~0;
189 tpg->hmask[2] = ~0;
06d1f0c2 190
63881df9 191 switch (fourcc) {
02aa769d
HV
192 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 */
71491063 201 case V4L2_PIX_FMT_RGB332:
63881df9
HV
202 case V4L2_PIX_FMT_RGB565:
203 case V4L2_PIX_FMT_RGB565X:
8aca230b
HV
204 case V4L2_PIX_FMT_RGB444:
205 case V4L2_PIX_FMT_XRGB444:
206 case V4L2_PIX_FMT_ARGB444:
63881df9
HV
207 case V4L2_PIX_FMT_RGB555:
208 case V4L2_PIX_FMT_XRGB555:
209 case V4L2_PIX_FMT_ARGB555:
210 case V4L2_PIX_FMT_RGB555X:
8f1ff543
HV
211 case V4L2_PIX_FMT_XRGB555X:
212 case V4L2_PIX_FMT_ARGB555X:
68cd4e9f 213 case V4L2_PIX_FMT_BGR666:
63881df9
HV
214 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:
51f30968 222 case V4L2_PIX_FMT_GREY:
6c515a44 223 tpg->is_yuv = false;
63881df9 224 break;
628821c8
HV
225 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;
68c90d64
HV
231 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;
63881df9
HV
252 case V4L2_PIX_FMT_NV16M:
253 case V4L2_PIX_FMT_NV61M:
68c90d64
HV
254 tpg->buffers = 2;
255 /* fall through */
256 case V4L2_PIX_FMT_NV16:
257 case V4L2_PIX_FMT_NV61:
ba01f673
HV
258 tpg->vdownsampling[1] = 1;
259 tpg->hdownsampling[1] = 1;
9991deff 260 tpg->hmask[1] = ~1;
68c90d64
HV
261 tpg->planes = 2;
262 tpg->is_yuv = true;
263 break;
264 case V4L2_PIX_FMT_NV12M:
265 case V4L2_PIX_FMT_NV21M:
06d1f0c2 266 tpg->buffers = 2;
68c90d64
HV
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;
9991deff 272 tpg->hmask[1] = ~1;
63881df9 273 tpg->planes = 2;
68c90d64
HV
274 tpg->is_yuv = true;
275 break;
dde72bd7
HV
276 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;
63881df9
HV
283 case V4L2_PIX_FMT_YUYV:
284 case V4L2_PIX_FMT_UYVY:
285 case V4L2_PIX_FMT_YVYU:
286 case V4L2_PIX_FMT_VYUY:
9991deff 287 tpg->hmask[0] = ~1;
6c515a44 288 tpg->is_yuv = true;
63881df9
HV
289 break;
290 default:
291 return false;
292 }
293
294 switch (fourcc) {
71491063
HV
295 case V4L2_PIX_FMT_RGB332:
296 tpg->twopixelsize[0] = 2;
297 break;
63881df9
HV
298 case V4L2_PIX_FMT_RGB565:
299 case V4L2_PIX_FMT_RGB565X:
8aca230b
HV
300 case V4L2_PIX_FMT_RGB444:
301 case V4L2_PIX_FMT_XRGB444:
302 case V4L2_PIX_FMT_ARGB444:
63881df9
HV
303 case V4L2_PIX_FMT_RGB555:
304 case V4L2_PIX_FMT_XRGB555:
305 case V4L2_PIX_FMT_ARGB555:
306 case V4L2_PIX_FMT_RGB555X:
8f1ff543
HV
307 case V4L2_PIX_FMT_XRGB555X:
308 case V4L2_PIX_FMT_ARGB555X:
63881df9
HV
309 case V4L2_PIX_FMT_YUYV:
310 case V4L2_PIX_FMT_UYVY:
311 case V4L2_PIX_FMT_YVYU:
312 case V4L2_PIX_FMT_VYUY:
628821c8
HV
313 case V4L2_PIX_FMT_YUV444:
314 case V4L2_PIX_FMT_YUV555:
315 case V4L2_PIX_FMT_YUV565:
63881df9
HV
316 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;
68cd4e9f 322 case V4L2_PIX_FMT_BGR666:
63881df9
HV
323 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:
628821c8 329 case V4L2_PIX_FMT_YUV32:
63881df9
HV
330 tpg->twopixelsize[0] = 2 * 4;
331 break;
51f30968
HV
332 case V4L2_PIX_FMT_GREY:
333 tpg->twopixelsize[0] = 2;
334 break;
68c90d64
HV
335 case V4L2_PIX_FMT_NV12:
336 case V4L2_PIX_FMT_NV21:
337 case V4L2_PIX_FMT_NV12M:
338 case V4L2_PIX_FMT_NV21M:
68c90d64
HV
339 case V4L2_PIX_FMT_NV16:
340 case V4L2_PIX_FMT_NV61:
63881df9
HV
341 case V4L2_PIX_FMT_NV16M:
342 case V4L2_PIX_FMT_NV61M:
02aa769d
HV
343 case V4L2_PIX_FMT_SBGGR8:
344 case V4L2_PIX_FMT_SGBRG8:
345 case V4L2_PIX_FMT_SGRBG8:
346 case V4L2_PIX_FMT_SRGGB8:
63881df9
HV
347 tpg->twopixelsize[0] = 2;
348 tpg->twopixelsize[1] = 2;
349 break;
68c90d64
HV
350 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;
dde72bd7
HV
359 case V4L2_PIX_FMT_NV24:
360 case V4L2_PIX_FMT_NV42:
361 tpg->twopixelsize[0] = 2;
362 tpg->twopixelsize[1] = 4;
363 break;
63881df9
HV
364 }
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,
73d81022 384 u32 field)
63881df9
HV
385{
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++)
ba01f673
HV
402 tpg->bytesperline[p] = (width * tpg->twopixelsize[p]) /
403 (2 * tpg->hdownsampling[p]);
63881df9
HV
404 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
481b97a1 432static inline int rec709_to_linear(int v)
63881df9 433{
481b97a1
HV
434 v = clamp(v, 0, 0xff0);
435 return tpg_rec709_to_linear[v];
63881df9
HV
436}
437
481b97a1 438static inline int linear_to_rec709(int v)
63881df9 439{
481b97a1
HV
440 v = clamp(v, 0, 0xff0);
441 return tpg_linear_to_rec709[v];
63881df9
HV
442}
443
481b97a1
HV
444static void rgb2ycbcr(const int m[3][3], int r, int g, int b,
445 int y_offset, int *y, int *cb, int *cr)
63881df9 446{
481b97a1
HV
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);
63881df9
HV
450}
451
481b97a1
HV
452static void color_to_ycbcr(struct tpg_data *tpg, int r, int g, int b,
453 int *y, int *cb, int *cr)
63881df9 454{
481b97a1 455#define COEFF(v, r) ((int)(0.5 + (v) * (r) * 256.0))
63881df9 456
481b97a1
HV
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 };
c702f68a
HV
482 static const int smpte240m_full[3][3] = {
483 { COEFF(0.212, 255), COEFF(0.701, 255), COEFF(0.087, 255) },
484 { COEFF(-0.116, 255), COEFF(-0.384, 255), COEFF(0.5, 255) },
485 { COEFF(0.5, 255), COEFF(-0.445, 255), COEFF(-0.055, 255) },
486 };
481b97a1 487 static const int bt2020[3][3] = {
e202e515 488 { COEFF(0.2627, 219), COEFF(0.6780, 219), COEFF(0.0593, 219) },
481b97a1 489 { COEFF(-0.1396, 224), COEFF(-0.3604, 224), COEFF(0.5, 224) },
e202e515 490 { COEFF(0.5, 224), COEFF(-0.4598, 224), COEFF(-0.0402, 224) },
481b97a1
HV
491 };
492 bool full = tpg->real_quantization == V4L2_QUANTIZATION_FULL_RANGE;
afad4dd5 493 unsigned y_offset = full ? 0 : 16;
481b97a1
HV
494 int lin_y, yc;
495
496 switch (tpg->real_ycbcr_enc) {
497 case V4L2_YCBCR_ENC_601:
498 case V4L2_YCBCR_ENC_XV601:
499 case V4L2_YCBCR_ENC_SYCC:
afad4dd5 500 rgb2ycbcr(full ? bt601_full : bt601, r, g, b, y_offset, y, cb, cr);
481b97a1
HV
501 break;
502 case V4L2_YCBCR_ENC_BT2020:
503 rgb2ycbcr(bt2020, r, g, b, 16, y, cb, cr);
63881df9 504 break;
481b97a1
HV
505 case V4L2_YCBCR_ENC_BT2020_CONST_LUM:
506 lin_y = (COEFF(0.2627, 255) * rec709_to_linear(r) +
507 COEFF(0.6780, 255) * rec709_to_linear(g) +
508 COEFF(0.0593, 255) * rec709_to_linear(b)) >> 16;
509 yc = linear_to_rec709(lin_y);
510 *y = (yc * 219) / 255 + (16 << 4);
511 if (b <= yc)
512 *cb = (((b - yc) * COEFF(1.0 / 1.9404, 224)) >> 16) + (128 << 4);
513 else
514 *cb = (((b - yc) * COEFF(1.0 / 1.5816, 224)) >> 16) + (128 << 4);
515 if (r <= yc)
516 *cr = (((r - yc) * COEFF(1.0 / 1.7184, 224)) >> 16) + (128 << 4);
517 else
518 *cr = (((r - yc) * COEFF(1.0 / 0.9936, 224)) >> 16) + (128 << 4);
63881df9 519 break;
481b97a1 520 case V4L2_YCBCR_ENC_SMPTE240M:
c702f68a 521 rgb2ycbcr(full ? smpte240m_full : smpte240m, r, g, b, y_offset, y, cb, cr);
481b97a1
HV
522 break;
523 case V4L2_YCBCR_ENC_709:
524 case V4L2_YCBCR_ENC_XV709:
63881df9 525 default:
afad4dd5 526 rgb2ycbcr(full ? rec709_full : rec709, r, g, b, y_offset, y, cb, cr);
63881df9
HV
527 break;
528 }
63881df9
HV
529}
530
481b97a1
HV
531static void ycbcr2rgb(const int m[3][3], int y, int cb, int cr,
532 int y_offset, int *r, int *g, int *b)
63881df9 533{
481b97a1 534 y -= y_offset << 4;
63881df9
HV
535 cb -= 128 << 4;
536 cr -= 128 << 4;
481b97a1
HV
537 *r = m[0][0] * y + m[0][1] * cb + m[0][2] * cr;
538 *g = m[1][0] * y + m[1][1] * cb + m[1][2] * cr;
539 *b = m[2][0] * y + m[2][1] * cb + m[2][2] * cr;
540 *r = clamp(*r >> 12, 0, 0xff0);
541 *g = clamp(*g >> 12, 0, 0xff0);
542 *b = clamp(*b >> 12, 0, 0xff0);
63881df9
HV
543}
544
481b97a1
HV
545static void ycbcr_to_color(struct tpg_data *tpg, int y, int cb, int cr,
546 int *r, int *g, int *b)
63881df9 547{
481b97a1
HV
548#undef COEFF
549#define COEFF(v, r) ((int)(0.5 + (v) * ((255.0 * 255.0 * 16.0) / (r))))
550 static const int bt601[3][3] = {
551 { COEFF(1, 219), COEFF(0, 224), COEFF(1.4020, 224) },
552 { COEFF(1, 219), COEFF(-0.3441, 224), COEFF(-0.7141, 224) },
553 { COEFF(1, 219), COEFF(1.7720, 224), COEFF(0, 224) },
554 };
555 static const int bt601_full[3][3] = {
556 { COEFF(1, 255), COEFF(0, 255), COEFF(1.4020, 255) },
557 { COEFF(1, 255), COEFF(-0.3441, 255), COEFF(-0.7141, 255) },
558 { COEFF(1, 255), COEFF(1.7720, 255), COEFF(0, 255) },
559 };
560 static const int rec709[3][3] = {
561 { COEFF(1, 219), COEFF(0, 224), COEFF(1.5748, 224) },
562 { COEFF(1, 219), COEFF(-0.1873, 224), COEFF(-0.4681, 224) },
563 { COEFF(1, 219), COEFF(1.8556, 224), COEFF(0, 224) },
564 };
565 static const int rec709_full[3][3] = {
566 { COEFF(1, 255), COEFF(0, 255), COEFF(1.5748, 255) },
567 { COEFF(1, 255), COEFF(-0.1873, 255), COEFF(-0.4681, 255) },
568 { COEFF(1, 255), COEFF(1.8556, 255), COEFF(0, 255) },
569 };
570 static const int smpte240m[3][3] = {
571 { COEFF(1, 219), COEFF(0, 224), COEFF(1.5756, 224) },
572 { COEFF(1, 219), COEFF(-0.2253, 224), COEFF(-0.4767, 224) },
573 { COEFF(1, 219), COEFF(1.8270, 224), COEFF(0, 224) },
574 };
c702f68a
HV
575 static const int smpte240m_full[3][3] = {
576 { COEFF(1, 255), COEFF(0, 255), COEFF(1.5756, 255) },
577 { COEFF(1, 255), COEFF(-0.2253, 255), COEFF(-0.4767, 255) },
578 { COEFF(1, 255), COEFF(1.8270, 255), COEFF(0, 255) },
579 };
481b97a1
HV
580 static const int bt2020[3][3] = {
581 { COEFF(1, 219), COEFF(0, 224), COEFF(1.4746, 224) },
582 { COEFF(1, 219), COEFF(-0.1646, 224), COEFF(-0.5714, 224) },
583 { COEFF(1, 219), COEFF(1.8814, 224), COEFF(0, 224) },
584 };
585 bool full = tpg->real_quantization == V4L2_QUANTIZATION_FULL_RANGE;
afad4dd5 586 unsigned y_offset = full ? 0 : 16;
481b97a1
HV
587 int lin_r, lin_g, lin_b, lin_y;
588
589 switch (tpg->real_ycbcr_enc) {
590 case V4L2_YCBCR_ENC_601:
591 case V4L2_YCBCR_ENC_XV601:
592 case V4L2_YCBCR_ENC_SYCC:
afad4dd5 593 ycbcr2rgb(full ? bt601_full : bt601, y, cb, cr, y_offset, r, g, b);
481b97a1
HV
594 break;
595 case V4L2_YCBCR_ENC_BT2020:
596 ycbcr2rgb(bt2020, y, cb, cr, 16, r, g, b);
597 break;
598 case V4L2_YCBCR_ENC_BT2020_CONST_LUM:
599 y -= 16 << 4;
600 cb -= 128 << 4;
601 cr -= 128 << 4;
63881df9 602
481b97a1
HV
603 if (cb <= 0)
604 *b = COEFF(1.0, 219) * y + COEFF(1.9404, 224) * cb;
605 else
606 *b = COEFF(1.0, 219) * y + COEFF(1.5816, 224) * cb;
607 *b = *b >> 12;
608 if (cr <= 0)
609 *r = COEFF(1.0, 219) * y + COEFF(1.7184, 224) * cr;
610 else
611 *r = COEFF(1.0, 219) * y + COEFF(0.9936, 224) * cr;
612 *r = *r >> 12;
613 lin_r = rec709_to_linear(*r);
614 lin_b = rec709_to_linear(*b);
615 lin_y = rec709_to_linear((y * 255) / 219);
616
617 lin_g = COEFF(1.0 / 0.6780, 255) * lin_y -
618 COEFF(0.2627 / 0.6780, 255) * lin_r -
619 COEFF(0.0593 / 0.6780, 255) * lin_b;
620 *g = linear_to_rec709(lin_g >> 12);
63881df9 621 break;
481b97a1 622 case V4L2_YCBCR_ENC_SMPTE240M:
c702f68a 623 ycbcr2rgb(full ? smpte240m_full : smpte240m, y, cb, cr, y_offset, r, g, b);
63881df9 624 break;
481b97a1
HV
625 case V4L2_YCBCR_ENC_709:
626 case V4L2_YCBCR_ENC_XV709:
63881df9 627 default:
afad4dd5 628 ycbcr2rgb(full ? rec709_full : rec709, y, cb, cr, y_offset, r, g, b);
63881df9
HV
629 break;
630 }
63881df9
HV
631}
632
633/* precalculate color bar values to speed up rendering */
634static void precalculate_color(struct tpg_data *tpg, int k)
635{
636 int col = k;
637 int r = tpg_colors[col].r;
638 int g = tpg_colors[col].g;
639 int b = tpg_colors[col].b;
640
641 if (k == TPG_COLOR_TEXTBG) {
642 col = tpg_get_textbg_color(tpg);
643
644 r = tpg_colors[col].r;
645 g = tpg_colors[col].g;
646 b = tpg_colors[col].b;
647 } else if (k == TPG_COLOR_TEXTFG) {
648 col = tpg_get_textfg_color(tpg);
649
650 r = tpg_colors[col].r;
651 g = tpg_colors[col].g;
652 b = tpg_colors[col].b;
653 } else if (tpg->pattern == TPG_PAT_NOISE) {
654 r = g = b = prandom_u32_max(256);
655 } else if (k == TPG_COLOR_RANDOM) {
656 r = g = b = tpg->qual_offset + prandom_u32_max(196);
657 } else if (k >= TPG_COLOR_RAMP) {
658 r = g = b = k - TPG_COLOR_RAMP;
659 }
660
661 if (tpg->pattern == TPG_PAT_CSC_COLORBAR && col <= TPG_COLOR_CSC_BLACK) {
662 r = tpg_csc_colors[tpg->colorspace][col].r;
663 g = tpg_csc_colors[tpg->colorspace][col].g;
664 b = tpg_csc_colors[tpg->colorspace][col].b;
665 } else {
666 r <<= 4;
667 g <<= 4;
668 b <<= 4;
669 }
51f30968 670 if (tpg->qual == TPG_QUAL_GRAY || tpg->fourcc == V4L2_PIX_FMT_GREY) {
481b97a1
HV
671 /* Rec. 709 Luma function */
672 /* (0.2126, 0.7152, 0.0722) * (255 * 256) */
9c35bd48 673 r = g = b = (13879 * r + 46688 * g + 4713 * b) >> 16;
481b97a1 674 }
63881df9
HV
675
676 /*
677 * The assumption is that the RGB output is always full range,
678 * so only if the rgb_range overrides the 'real' rgb range do
679 * we need to convert the RGB values.
680 *
63881df9
HV
681 * Remember that r, g and b are still in the 0 - 0xff0 range.
682 */
683 if (tpg->real_rgb_range == V4L2_DV_RGB_RANGE_LIMITED &&
684 tpg->rgb_range == V4L2_DV_RGB_RANGE_FULL) {
685 /*
686 * Convert from full range (which is what r, g and b are)
687 * to limited range (which is the 'real' RGB range), which
688 * is then interpreted as full range.
689 */
690 r = (r * 219) / 255 + (16 << 4);
691 g = (g * 219) / 255 + (16 << 4);
692 b = (b * 219) / 255 + (16 << 4);
693 } else if (tpg->real_rgb_range != V4L2_DV_RGB_RANGE_LIMITED &&
694 tpg->rgb_range == V4L2_DV_RGB_RANGE_LIMITED) {
695 /*
696 * Clamp r, g and b to the limited range and convert to full
697 * range since that's what we deliver.
698 */
699 r = clamp(r, 16 << 4, 235 << 4);
700 g = clamp(g, 16 << 4, 235 << 4);
701 b = clamp(b, 16 << 4, 235 << 4);
702 r = (r - (16 << 4)) * 255 / 219;
703 g = (g - (16 << 4)) * 255 / 219;
704 b = (b - (16 << 4)) * 255 / 219;
705 }
706
707 if (tpg->brightness != 128 || tpg->contrast != 128 ||
708 tpg->saturation != 128 || tpg->hue) {
709 /* Implement these operations */
481b97a1
HV
710 int y, cb, cr;
711 int tmp_cb, tmp_cr;
63881df9
HV
712
713 /* First convert to YCbCr */
481b97a1
HV
714
715 color_to_ycbcr(tpg, r, g, b, &y, &cb, &cr);
63881df9
HV
716
717 y = (16 << 4) + ((y - (16 << 4)) * tpg->contrast) / 128;
718 y += (tpg->brightness << 4) - (128 << 4);
719
720 cb -= 128 << 4;
721 cr -= 128 << 4;
722 tmp_cb = (cb * cos(128 + tpg->hue)) / 127 + (cr * sin[128 + tpg->hue]) / 127;
723 tmp_cr = (cr * cos(128 + tpg->hue)) / 127 - (cb * sin[128 + tpg->hue]) / 127;
724
725 cb = (128 << 4) + (tmp_cb * tpg->contrast * tpg->saturation) / (128 * 128);
726 cr = (128 << 4) + (tmp_cr * tpg->contrast * tpg->saturation) / (128 * 128);
727 if (tpg->is_yuv) {
728 tpg->colors[k][0] = clamp(y >> 4, 1, 254);
729 tpg->colors[k][1] = clamp(cb >> 4, 1, 254);
730 tpg->colors[k][2] = clamp(cr >> 4, 1, 254);
731 return;
732 }
481b97a1 733 ycbcr_to_color(tpg, y, cb, cr, &r, &g, &b);
63881df9
HV
734 }
735
736 if (tpg->is_yuv) {
737 /* Convert to YCbCr */
481b97a1
HV
738 int y, cb, cr;
739
740 color_to_ycbcr(tpg, r, g, b, &y, &cb, &cr);
63881df9 741
481b97a1
HV
742 if (tpg->real_quantization == V4L2_QUANTIZATION_LIM_RANGE) {
743 y = clamp(y, 16 << 4, 235 << 4);
744 cb = clamp(cb, 16 << 4, 240 << 4);
745 cr = clamp(cr, 16 << 4, 240 << 4);
746 }
628821c8
HV
747 y = clamp(y >> 4, 1, 254);
748 cb = clamp(cb >> 4, 1, 254);
749 cr = clamp(cr >> 4, 1, 254);
750 switch (tpg->fourcc) {
751 case V4L2_PIX_FMT_YUV444:
752 y >>= 4;
753 cb >>= 4;
754 cr >>= 4;
755 break;
756 case V4L2_PIX_FMT_YUV555:
757 y >>= 3;
758 cb >>= 3;
759 cr >>= 3;
760 break;
761 case V4L2_PIX_FMT_YUV565:
762 y >>= 3;
763 cb >>= 2;
764 cr >>= 3;
765 break;
766 }
767 tpg->colors[k][0] = y;
768 tpg->colors[k][1] = cb;
769 tpg->colors[k][2] = cr;
63881df9 770 } else {
481b97a1
HV
771 if (tpg->real_quantization == V4L2_QUANTIZATION_LIM_RANGE) {
772 r = (r * 219) / 255 + (16 << 4);
773 g = (g * 219) / 255 + (16 << 4);
774 b = (b * 219) / 255 + (16 << 4);
775 }
63881df9 776 switch (tpg->fourcc) {
71491063
HV
777 case V4L2_PIX_FMT_RGB332:
778 r >>= 9;
779 g >>= 9;
780 b >>= 10;
781 break;
63881df9
HV
782 case V4L2_PIX_FMT_RGB565:
783 case V4L2_PIX_FMT_RGB565X:
784 r >>= 7;
785 g >>= 6;
786 b >>= 7;
787 break;
8aca230b
HV
788 case V4L2_PIX_FMT_RGB444:
789 case V4L2_PIX_FMT_XRGB444:
790 case V4L2_PIX_FMT_ARGB444:
791 r >>= 8;
792 g >>= 8;
793 b >>= 8;
794 break;
63881df9
HV
795 case V4L2_PIX_FMT_RGB555:
796 case V4L2_PIX_FMT_XRGB555:
797 case V4L2_PIX_FMT_ARGB555:
798 case V4L2_PIX_FMT_RGB555X:
8f1ff543
HV
799 case V4L2_PIX_FMT_XRGB555X:
800 case V4L2_PIX_FMT_ARGB555X:
63881df9
HV
801 r >>= 7;
802 g >>= 7;
803 b >>= 7;
804 break;
68cd4e9f
HV
805 case V4L2_PIX_FMT_BGR666:
806 r >>= 6;
807 g >>= 6;
808 b >>= 6;
809 break;
63881df9
HV
810 default:
811 r >>= 4;
812 g >>= 4;
813 b >>= 4;
814 break;
815 }
816
817 tpg->colors[k][0] = r;
818 tpg->colors[k][1] = g;
819 tpg->colors[k][2] = b;
820 }
821}
822
823static void tpg_precalculate_colors(struct tpg_data *tpg)
824{
825 int k;
826
827 for (k = 0; k < TPG_COLOR_MAX; k++)
828 precalculate_color(tpg, k);
829}
830
831/* 'odd' is true for pixels 1, 3, 5, etc. and false for pixels 0, 2, 4, etc. */
832static void gen_twopix(struct tpg_data *tpg,
833 u8 buf[TPG_MAX_PLANES][8], int color, bool odd)
834{
835 unsigned offset = odd * tpg->twopixelsize[0] / 2;
836 u8 alpha = tpg->alpha_component;
837 u8 r_y, g_u, b_v;
838
839 if (tpg->alpha_red_only && color != TPG_COLOR_CSC_RED &&
840 color != TPG_COLOR_100_RED &&
841 color != TPG_COLOR_75_RED)
842 alpha = 0;
843 if (color == TPG_COLOR_RANDOM)
844 precalculate_color(tpg, color);
845 r_y = tpg->colors[color][0]; /* R or precalculated Y */
846 g_u = tpg->colors[color][1]; /* G or precalculated U */
847 b_v = tpg->colors[color][2]; /* B or precalculated V */
848
849 switch (tpg->fourcc) {
51f30968
HV
850 case V4L2_PIX_FMT_GREY:
851 buf[0][offset] = r_y;
852 break;
68c90d64
HV
853 case V4L2_PIX_FMT_YUV422P:
854 case V4L2_PIX_FMT_YUV420:
855 case V4L2_PIX_FMT_YUV420M:
856 buf[0][offset] = r_y;
857 if (odd) {
858 buf[1][0] = (buf[1][0] + g_u) / 2;
859 buf[2][0] = (buf[2][0] + b_v) / 2;
860 buf[1][1] = buf[1][0];
861 buf[2][1] = buf[2][0];
862 break;
863 }
864 buf[1][0] = g_u;
865 buf[2][0] = b_v;
866 break;
867 case V4L2_PIX_FMT_YVU420:
868 case V4L2_PIX_FMT_YVU420M:
869 buf[0][offset] = r_y;
870 if (odd) {
871 buf[1][0] = (buf[1][0] + b_v) / 2;
872 buf[2][0] = (buf[2][0] + g_u) / 2;
873 buf[1][1] = buf[1][0];
874 buf[2][1] = buf[2][0];
875 break;
876 }
877 buf[1][0] = b_v;
878 buf[2][0] = g_u;
879 break;
880
881 case V4L2_PIX_FMT_NV12:
882 case V4L2_PIX_FMT_NV12M:
883 case V4L2_PIX_FMT_NV16:
63881df9
HV
884 case V4L2_PIX_FMT_NV16M:
885 buf[0][offset] = r_y;
1f088dc1
HV
886 if (odd) {
887 buf[1][0] = (buf[1][0] + g_u) / 2;
888 buf[1][1] = (buf[1][1] + b_v) / 2;
889 break;
890 }
891 buf[1][0] = g_u;
892 buf[1][1] = b_v;
63881df9 893 break;
68c90d64
HV
894 case V4L2_PIX_FMT_NV21:
895 case V4L2_PIX_FMT_NV21M:
896 case V4L2_PIX_FMT_NV61:
63881df9
HV
897 case V4L2_PIX_FMT_NV61M:
898 buf[0][offset] = r_y;
1f088dc1
HV
899 if (odd) {
900 buf[1][0] = (buf[1][0] + b_v) / 2;
901 buf[1][1] = (buf[1][1] + g_u) / 2;
902 break;
903 }
904 buf[1][0] = b_v;
905 buf[1][1] = g_u;
63881df9
HV
906 break;
907
dde72bd7
HV
908 case V4L2_PIX_FMT_NV24:
909 buf[0][offset] = r_y;
910 buf[1][2 * offset] = g_u;
911 buf[1][2 * offset + 1] = b_v;
912 break;
913
914 case V4L2_PIX_FMT_NV42:
915 buf[0][offset] = r_y;
916 buf[1][2 * offset] = b_v;
917 buf[1][2 * offset + 1] = g_u;
918 break;
919
63881df9
HV
920 case V4L2_PIX_FMT_YUYV:
921 buf[0][offset] = r_y;
1f088dc1
HV
922 if (odd) {
923 buf[0][1] = (buf[0][1] + g_u) / 2;
924 buf[0][3] = (buf[0][3] + b_v) / 2;
925 break;
926 }
927 buf[0][1] = g_u;
928 buf[0][3] = b_v;
63881df9
HV
929 break;
930 case V4L2_PIX_FMT_UYVY:
63881df9 931 buf[0][offset + 1] = r_y;
1f088dc1
HV
932 if (odd) {
933 buf[0][0] = (buf[0][0] + g_u) / 2;
934 buf[0][2] = (buf[0][2] + b_v) / 2;
935 break;
936 }
937 buf[0][0] = g_u;
938 buf[0][2] = b_v;
63881df9
HV
939 break;
940 case V4L2_PIX_FMT_YVYU:
941 buf[0][offset] = r_y;
1f088dc1
HV
942 if (odd) {
943 buf[0][1] = (buf[0][1] + b_v) / 2;
944 buf[0][3] = (buf[0][3] + g_u) / 2;
945 break;
946 }
947 buf[0][1] = b_v;
948 buf[0][3] = g_u;
63881df9
HV
949 break;
950 case V4L2_PIX_FMT_VYUY:
63881df9 951 buf[0][offset + 1] = r_y;
1f088dc1
HV
952 if (odd) {
953 buf[0][0] = (buf[0][0] + b_v) / 2;
954 buf[0][2] = (buf[0][2] + g_u) / 2;
955 break;
956 }
957 buf[0][0] = b_v;
958 buf[0][2] = g_u;
63881df9 959 break;
71491063
HV
960 case V4L2_PIX_FMT_RGB332:
961 buf[0][offset] = (r_y << 5) | (g_u << 2) | b_v;
962 break;
628821c8 963 case V4L2_PIX_FMT_YUV565:
63881df9
HV
964 case V4L2_PIX_FMT_RGB565:
965 buf[0][offset] = (g_u << 5) | b_v;
966 buf[0][offset + 1] = (r_y << 3) | (g_u >> 3);
967 break;
968 case V4L2_PIX_FMT_RGB565X:
969 buf[0][offset] = (r_y << 3) | (g_u >> 3);
970 buf[0][offset + 1] = (g_u << 5) | b_v;
971 break;
8aca230b
HV
972 case V4L2_PIX_FMT_RGB444:
973 case V4L2_PIX_FMT_XRGB444:
974 alpha = 0;
975 /* fall through */
628821c8 976 case V4L2_PIX_FMT_YUV444:
8aca230b
HV
977 case V4L2_PIX_FMT_ARGB444:
978 buf[0][offset] = (g_u << 4) | b_v;
979 buf[0][offset + 1] = (alpha & 0xf0) | r_y;
980 break;
63881df9
HV
981 case V4L2_PIX_FMT_RGB555:
982 case V4L2_PIX_FMT_XRGB555:
983 alpha = 0;
984 /* fall through */
628821c8 985 case V4L2_PIX_FMT_YUV555:
63881df9
HV
986 case V4L2_PIX_FMT_ARGB555:
987 buf[0][offset] = (g_u << 5) | b_v;
988 buf[0][offset + 1] = (alpha & 0x80) | (r_y << 2) | (g_u >> 3);
989 break;
990 case V4L2_PIX_FMT_RGB555X:
8f1ff543
HV
991 case V4L2_PIX_FMT_XRGB555X:
992 alpha = 0;
993 /* fall through */
994 case V4L2_PIX_FMT_ARGB555X:
63881df9
HV
995 buf[0][offset] = (alpha & 0x80) | (r_y << 2) | (g_u >> 3);
996 buf[0][offset + 1] = (g_u << 5) | b_v;
997 break;
998 case V4L2_PIX_FMT_RGB24:
999 buf[0][offset] = r_y;
1000 buf[0][offset + 1] = g_u;
1001 buf[0][offset + 2] = b_v;
1002 break;
1003 case V4L2_PIX_FMT_BGR24:
1004 buf[0][offset] = b_v;
1005 buf[0][offset + 1] = g_u;
1006 buf[0][offset + 2] = r_y;
1007 break;
68cd4e9f
HV
1008 case V4L2_PIX_FMT_BGR666:
1009 buf[0][offset] = (b_v << 2) | (g_u >> 4);
1010 buf[0][offset + 1] = (g_u << 4) | (r_y >> 2);
1011 buf[0][offset + 2] = r_y << 6;
1012 buf[0][offset + 3] = 0;
1013 break;
63881df9
HV
1014 case V4L2_PIX_FMT_RGB32:
1015 case V4L2_PIX_FMT_XRGB32:
1016 alpha = 0;
1017 /* fall through */
628821c8 1018 case V4L2_PIX_FMT_YUV32:
63881df9
HV
1019 case V4L2_PIX_FMT_ARGB32:
1020 buf[0][offset] = alpha;
1021 buf[0][offset + 1] = r_y;
1022 buf[0][offset + 2] = g_u;
1023 buf[0][offset + 3] = b_v;
1024 break;
1025 case V4L2_PIX_FMT_BGR32:
1026 case V4L2_PIX_FMT_XBGR32:
1027 alpha = 0;
1028 /* fall through */
1029 case V4L2_PIX_FMT_ABGR32:
1030 buf[0][offset] = b_v;
1031 buf[0][offset + 1] = g_u;
1032 buf[0][offset + 2] = r_y;
1033 buf[0][offset + 3] = alpha;
1034 break;
02aa769d
HV
1035 case V4L2_PIX_FMT_SBGGR8:
1036 buf[0][offset] = odd ? g_u : b_v;
1037 buf[1][offset] = odd ? r_y : g_u;
1038 break;
1039 case V4L2_PIX_FMT_SGBRG8:
1040 buf[0][offset] = odd ? b_v : g_u;
1041 buf[1][offset] = odd ? g_u : r_y;
1042 break;
1043 case V4L2_PIX_FMT_SGRBG8:
1044 buf[0][offset] = odd ? r_y : g_u;
1045 buf[1][offset] = odd ? g_u : b_v;
1046 break;
1047 case V4L2_PIX_FMT_SRGGB8:
1048 buf[0][offset] = odd ? g_u : r_y;
1049 buf[1][offset] = odd ? b_v : g_u;
1050 break;
1051 }
1052}
1053
1054unsigned tpg_g_interleaved_plane(const struct tpg_data *tpg, unsigned buf_line)
1055{
1056 switch (tpg->fourcc) {
1057 case V4L2_PIX_FMT_SBGGR8:
1058 case V4L2_PIX_FMT_SGBRG8:
1059 case V4L2_PIX_FMT_SGRBG8:
1060 case V4L2_PIX_FMT_SRGGB8:
1061 return buf_line & 1;
1062 default:
1063 return 0;
63881df9
HV
1064 }
1065}
1066
1067/* Return how many pattern lines are used by the current pattern. */
1a05d313 1068static unsigned tpg_get_pat_lines(const struct tpg_data *tpg)
63881df9
HV
1069{
1070 switch (tpg->pattern) {
1071 case TPG_PAT_CHECKERS_16X16:
1a05d313 1072 case TPG_PAT_CHECKERS_2X2:
63881df9 1073 case TPG_PAT_CHECKERS_1X1:
1a05d313
HV
1074 case TPG_PAT_COLOR_CHECKERS_2X2:
1075 case TPG_PAT_COLOR_CHECKERS_1X1:
63881df9
HV
1076 case TPG_PAT_ALTERNATING_HLINES:
1077 case TPG_PAT_CROSS_1_PIXEL:
1078 case TPG_PAT_CROSS_2_PIXELS:
1079 case TPG_PAT_CROSS_10_PIXELS:
1080 return 2;
1081 case TPG_PAT_100_COLORSQUARES:
1082 case TPG_PAT_100_HCOLORBAR:
1083 return 8;
1084 default:
1085 return 1;
1086 }
1087}
1088
1089/* Which pattern line should be used for the given frame line. */
1a05d313 1090static unsigned tpg_get_pat_line(const struct tpg_data *tpg, unsigned line)
63881df9
HV
1091{
1092 switch (tpg->pattern) {
1093 case TPG_PAT_CHECKERS_16X16:
1094 return (line >> 4) & 1;
1095 case TPG_PAT_CHECKERS_1X1:
1a05d313 1096 case TPG_PAT_COLOR_CHECKERS_1X1:
63881df9
HV
1097 case TPG_PAT_ALTERNATING_HLINES:
1098 return line & 1;
1a05d313
HV
1099 case TPG_PAT_CHECKERS_2X2:
1100 case TPG_PAT_COLOR_CHECKERS_2X2:
1101 return (line & 2) >> 1;
63881df9
HV
1102 case TPG_PAT_100_COLORSQUARES:
1103 case TPG_PAT_100_HCOLORBAR:
1104 return (line * 8) / tpg->src_height;
1105 case TPG_PAT_CROSS_1_PIXEL:
1106 return line == tpg->src_height / 2;
1107 case TPG_PAT_CROSS_2_PIXELS:
1108 return (line + 1) / 2 == tpg->src_height / 4;
1109 case TPG_PAT_CROSS_10_PIXELS:
1110 return (line + 10) / 20 == tpg->src_height / 40;
1111 default:
1112 return 0;
1113 }
1114}
1115
1116/*
1117 * Which color should be used for the given pattern line and X coordinate.
1118 * Note: x is in the range 0 to 2 * tpg->src_width.
1119 */
1a05d313
HV
1120static enum tpg_color tpg_get_color(const struct tpg_data *tpg,
1121 unsigned pat_line, unsigned x)
63881df9
HV
1122{
1123 /* Maximum number of bars are TPG_COLOR_MAX - otherwise, the input print code
1124 should be modified */
1125 static const enum tpg_color bars[3][8] = {
1126 /* Standard ITU-R 75% color bar sequence */
1127 { TPG_COLOR_CSC_WHITE, TPG_COLOR_75_YELLOW,
1128 TPG_COLOR_75_CYAN, TPG_COLOR_75_GREEN,
1129 TPG_COLOR_75_MAGENTA, TPG_COLOR_75_RED,
1130 TPG_COLOR_75_BLUE, TPG_COLOR_100_BLACK, },
1131 /* Standard ITU-R 100% color bar sequence */
1132 { TPG_COLOR_100_WHITE, TPG_COLOR_100_YELLOW,
1133 TPG_COLOR_100_CYAN, TPG_COLOR_100_GREEN,
1134 TPG_COLOR_100_MAGENTA, TPG_COLOR_100_RED,
1135 TPG_COLOR_100_BLUE, TPG_COLOR_100_BLACK, },
1136 /* Color bar sequence suitable to test CSC */
1137 { TPG_COLOR_CSC_WHITE, TPG_COLOR_CSC_YELLOW,
1138 TPG_COLOR_CSC_CYAN, TPG_COLOR_CSC_GREEN,
1139 TPG_COLOR_CSC_MAGENTA, TPG_COLOR_CSC_RED,
1140 TPG_COLOR_CSC_BLUE, TPG_COLOR_CSC_BLACK, },
1141 };
1142
1143 switch (tpg->pattern) {
1144 case TPG_PAT_75_COLORBAR:
1145 case TPG_PAT_100_COLORBAR:
1146 case TPG_PAT_CSC_COLORBAR:
1147 return bars[tpg->pattern][((x * 8) / tpg->src_width) % 8];
1148 case TPG_PAT_100_COLORSQUARES:
1149 return bars[1][(pat_line + (x * 8) / tpg->src_width) % 8];
1150 case TPG_PAT_100_HCOLORBAR:
1151 return bars[1][pat_line];
1152 case TPG_PAT_BLACK:
1153 return TPG_COLOR_100_BLACK;
1154 case TPG_PAT_WHITE:
1155 return TPG_COLOR_100_WHITE;
1156 case TPG_PAT_RED:
1157 return TPG_COLOR_100_RED;
1158 case TPG_PAT_GREEN:
1159 return TPG_COLOR_100_GREEN;
1160 case TPG_PAT_BLUE:
1161 return TPG_COLOR_100_BLUE;
1162 case TPG_PAT_CHECKERS_16X16:
1163 return (((x >> 4) & 1) ^ (pat_line & 1)) ?
1164 TPG_COLOR_100_BLACK : TPG_COLOR_100_WHITE;
1165 case TPG_PAT_CHECKERS_1X1:
1166 return ((x & 1) ^ (pat_line & 1)) ?
1167 TPG_COLOR_100_WHITE : TPG_COLOR_100_BLACK;
1a05d313
HV
1168 case TPG_PAT_COLOR_CHECKERS_1X1:
1169 return ((x & 1) ^ (pat_line & 1)) ?
1170 TPG_COLOR_100_RED : TPG_COLOR_100_BLUE;
1171 case TPG_PAT_CHECKERS_2X2:
1172 return (((x >> 1) & 1) ^ (pat_line & 1)) ?
1173 TPG_COLOR_100_WHITE : TPG_COLOR_100_BLACK;
1174 case TPG_PAT_COLOR_CHECKERS_2X2:
1175 return (((x >> 1) & 1) ^ (pat_line & 1)) ?
1176 TPG_COLOR_100_RED : TPG_COLOR_100_BLUE;
63881df9
HV
1177 case TPG_PAT_ALTERNATING_HLINES:
1178 return pat_line ? TPG_COLOR_100_WHITE : TPG_COLOR_100_BLACK;
1179 case TPG_PAT_ALTERNATING_VLINES:
1180 return (x & 1) ? TPG_COLOR_100_WHITE : TPG_COLOR_100_BLACK;
1181 case TPG_PAT_CROSS_1_PIXEL:
1182 if (pat_line || (x % tpg->src_width) == tpg->src_width / 2)
1183 return TPG_COLOR_100_BLACK;
1184 return TPG_COLOR_100_WHITE;
1185 case TPG_PAT_CROSS_2_PIXELS:
1186 if (pat_line || ((x % tpg->src_width) + 1) / 2 == tpg->src_width / 4)
1187 return TPG_COLOR_100_BLACK;
1188 return TPG_COLOR_100_WHITE;
1189 case TPG_PAT_CROSS_10_PIXELS:
1190 if (pat_line || ((x % tpg->src_width) + 10) / 20 == tpg->src_width / 40)
1191 return TPG_COLOR_100_BLACK;
1192 return TPG_COLOR_100_WHITE;
1193 case TPG_PAT_GRAY_RAMP:
1194 return TPG_COLOR_RAMP + ((x % tpg->src_width) * 256) / tpg->src_width;
1195 default:
1196 return TPG_COLOR_100_RED;
1197 }
1198}
1199
1200/*
1201 * Given the pixel aspect ratio and video aspect ratio calculate the
1202 * coordinates of a centered square and the coordinates of the border of
1203 * the active video area. The coordinates are relative to the source
1204 * frame rectangle.
1205 */
1206static void tpg_calculate_square_border(struct tpg_data *tpg)
1207{
1208 unsigned w = tpg->src_width;
1209 unsigned h = tpg->src_height;
1210 unsigned sq_w, sq_h;
1211
1212 sq_w = (w * 2 / 5) & ~1;
1213 if (((w - sq_w) / 2) & 1)
1214 sq_w += 2;
1215 sq_h = sq_w;
1216 tpg->square.width = sq_w;
1217 if (tpg->vid_aspect == TPG_VIDEO_ASPECT_16X9_ANAMORPHIC) {
1218 unsigned ana_sq_w = (sq_w / 4) * 3;
1219
1220 if (((w - ana_sq_w) / 2) & 1)
1221 ana_sq_w += 2;
1222 tpg->square.width = ana_sq_w;
1223 }
1224 tpg->square.left = (w - tpg->square.width) / 2;
1225 if (tpg->pix_aspect == TPG_PIXEL_ASPECT_NTSC)
1226 sq_h = sq_w * 10 / 11;
1227 else if (tpg->pix_aspect == TPG_PIXEL_ASPECT_PAL)
1228 sq_h = sq_w * 59 / 54;
1229 tpg->square.height = sq_h;
1230 tpg->square.top = (h - sq_h) / 2;
1231 tpg->border.left = 0;
1232 tpg->border.width = w;
1233 tpg->border.top = 0;
1234 tpg->border.height = h;
1235 switch (tpg->vid_aspect) {
1236 case TPG_VIDEO_ASPECT_4X3:
1237 if (tpg->pix_aspect)
1238 return;
1239 if (3 * w >= 4 * h) {
1240 tpg->border.width = ((4 * h) / 3) & ~1;
1241 if (((w - tpg->border.width) / 2) & ~1)
1242 tpg->border.width -= 2;
1243 tpg->border.left = (w - tpg->border.width) / 2;
1244 break;
1245 }
1246 tpg->border.height = ((3 * w) / 4) & ~1;
1247 tpg->border.top = (h - tpg->border.height) / 2;
1248 break;
1249 case TPG_VIDEO_ASPECT_14X9_CENTRE:
1250 if (tpg->pix_aspect) {
1251 tpg->border.height = tpg->pix_aspect == TPG_PIXEL_ASPECT_NTSC ? 420 : 506;
1252 tpg->border.top = (h - tpg->border.height) / 2;
1253 break;
1254 }
1255 if (9 * w >= 14 * h) {
1256 tpg->border.width = ((14 * h) / 9) & ~1;
1257 if (((w - tpg->border.width) / 2) & ~1)
1258 tpg->border.width -= 2;
1259 tpg->border.left = (w - tpg->border.width) / 2;
1260 break;
1261 }
1262 tpg->border.height = ((9 * w) / 14) & ~1;
1263 tpg->border.top = (h - tpg->border.height) / 2;
1264 break;
1265 case TPG_VIDEO_ASPECT_16X9_CENTRE:
1266 if (tpg->pix_aspect) {
1267 tpg->border.height = tpg->pix_aspect == TPG_PIXEL_ASPECT_NTSC ? 368 : 442;
1268 tpg->border.top = (h - tpg->border.height) / 2;
1269 break;
1270 }
1271 if (9 * w >= 16 * h) {
1272 tpg->border.width = ((16 * h) / 9) & ~1;
1273 if (((w - tpg->border.width) / 2) & ~1)
1274 tpg->border.width -= 2;
1275 tpg->border.left = (w - tpg->border.width) / 2;
1276 break;
1277 }
1278 tpg->border.height = ((9 * w) / 16) & ~1;
1279 tpg->border.top = (h - tpg->border.height) / 2;
1280 break;
1281 default:
1282 break;
1283 }
1284}
1285
1286static void tpg_precalculate_line(struct tpg_data *tpg)
1287{
1288 enum tpg_color contrast;
9991deff 1289 u8 pix[TPG_MAX_PLANES][8];
63881df9
HV
1290 unsigned pat;
1291 unsigned p;
1292 unsigned x;
1293
1294 switch (tpg->pattern) {
1295 case TPG_PAT_GREEN:
1296 contrast = TPG_COLOR_100_RED;
1297 break;
1298 case TPG_PAT_CSC_COLORBAR:
1299 contrast = TPG_COLOR_CSC_GREEN;
1300 break;
1301 default:
1302 contrast = TPG_COLOR_100_GREEN;
1303 break;
1304 }
1305
1306 for (pat = 0; pat < tpg_get_pat_lines(tpg); pat++) {
1307 /* Coarse scaling with Bresenham */
1308 unsigned int_part = tpg->src_width / tpg->scaled_width;
1309 unsigned fract_part = tpg->src_width % tpg->scaled_width;
1310 unsigned src_x = 0;
1311 unsigned error = 0;
1312
1313 for (x = 0; x < tpg->scaled_width * 2; x += 2) {
1314 unsigned real_x = src_x;
1315 enum tpg_color color1, color2;
63881df9
HV
1316
1317 real_x = tpg->hflip ? tpg->src_width * 2 - real_x - 2 : real_x;
1318 color1 = tpg_get_color(tpg, pat, real_x);
1319
1320 src_x += int_part;
1321 error += fract_part;
1322 if (error >= tpg->scaled_width) {
1323 error -= tpg->scaled_width;
1324 src_x++;
1325 }
1326
1327 real_x = src_x;
1328 real_x = tpg->hflip ? tpg->src_width * 2 - real_x - 2 : real_x;
1329 color2 = tpg_get_color(tpg, pat, real_x);
1330
1331 src_x += int_part;
1332 error += fract_part;
1333 if (error >= tpg->scaled_width) {
1334 error -= tpg->scaled_width;
1335 src_x++;
1336 }
1337
1338 gen_twopix(tpg, pix, tpg->hflip ? color2 : color1, 0);
1339 gen_twopix(tpg, pix, tpg->hflip ? color1 : color2, 1);
1340 for (p = 0; p < tpg->planes; p++) {
1341 unsigned twopixsize = tpg->twopixelsize[p];
5d7c539e 1342 unsigned hdiv = tpg->hdownsampling[p];
9991deff 1343 u8 *pos = tpg->lines[pat][p] + tpg_hdiv(tpg, p, x);
63881df9 1344
5d7c539e 1345 memcpy(pos, pix[p], twopixsize / hdiv);
63881df9
HV
1346 }
1347 }
1348 }
5d7c539e
HV
1349
1350 if (tpg->vdownsampling[tpg->planes - 1] > 1) {
1351 unsigned pat_lines = tpg_get_pat_lines(tpg);
1352
1353 for (pat = 0; pat < pat_lines; pat++) {
1354 unsigned next_pat = (pat + 1) % pat_lines;
1355
1356 for (p = 1; p < tpg->planes; p++) {
9991deff
HV
1357 unsigned w = tpg_hdiv(tpg, p, tpg->scaled_width * 2);
1358 u8 *pos1 = tpg->lines[pat][p];
1359 u8 *pos2 = tpg->lines[next_pat][p];
1360 u8 *dest = tpg->downsampled_lines[pat][p];
5d7c539e 1361
9991deff
HV
1362 for (x = 0; x < w; x++, pos1++, pos2++, dest++)
1363 *dest = ((u16)*pos1 + (u16)*pos2) / 2;
5d7c539e
HV
1364 }
1365 }
1366 }
1367
9991deff
HV
1368 gen_twopix(tpg, pix, contrast, 0);
1369 gen_twopix(tpg, pix, contrast, 1);
1370 for (p = 0; p < tpg->planes; p++) {
1371 unsigned twopixsize = tpg->twopixelsize[p];
1372 u8 *pos = tpg->contrast_line[p];
63881df9 1373
9991deff 1374 for (x = 0; x < tpg->scaled_width; x += 2, pos += twopixsize)
63881df9 1375 memcpy(pos, pix[p], twopixsize);
63881df9 1376 }
63881df9 1377
9991deff
HV
1378 gen_twopix(tpg, pix, TPG_COLOR_100_BLACK, 0);
1379 gen_twopix(tpg, pix, TPG_COLOR_100_BLACK, 1);
1380 for (p = 0; p < tpg->planes; p++) {
1381 unsigned twopixsize = tpg->twopixelsize[p];
1382 u8 *pos = tpg->black_line[p];
63881df9 1383
9991deff 1384 for (x = 0; x < tpg->scaled_width; x += 2, pos += twopixsize)
63881df9 1385 memcpy(pos, pix[p], twopixsize);
63881df9 1386 }
63881df9 1387
9991deff 1388 for (x = 0; x < tpg->scaled_width * 2; x += 2) {
63881df9
HV
1389 gen_twopix(tpg, pix, TPG_COLOR_RANDOM, 0);
1390 gen_twopix(tpg, pix, TPG_COLOR_RANDOM, 1);
1391 for (p = 0; p < tpg->planes; p++) {
1392 unsigned twopixsize = tpg->twopixelsize[p];
1393 u8 *pos = tpg->random_line[p] + x * twopixsize / 2;
1394
1395 memcpy(pos, pix[p], twopixsize);
1396 }
1397 }
9991deff 1398
63881df9
HV
1399 gen_twopix(tpg, tpg->textbg, TPG_COLOR_TEXTBG, 0);
1400 gen_twopix(tpg, tpg->textbg, TPG_COLOR_TEXTBG, 1);
1401 gen_twopix(tpg, tpg->textfg, TPG_COLOR_TEXTFG, 0);
1402 gen_twopix(tpg, tpg->textfg, TPG_COLOR_TEXTFG, 1);
1403}
1404
1405/* need this to do rgb24 rendering */
1406typedef struct { u16 __; u8 _; } __packed x24;
1407
dfff0489
HV
1408void tpg_gen_text(const struct tpg_data *tpg, u8 *basep[TPG_MAX_PLANES][2],
1409 int y, int x, char *text)
63881df9
HV
1410{
1411 int line;
1412 unsigned step = V4L2_FIELD_HAS_T_OR_B(tpg->field) ? 2 : 1;
1413 unsigned div = step;
1414 unsigned first = 0;
1415 unsigned len = strlen(text);
1416 unsigned p;
1417
1418 if (font8x16 == NULL || basep == NULL)
1419 return;
1420
1421 /* Checks if it is possible to show string */
1422 if (y + 16 >= tpg->compose.height || x + 8 >= tpg->compose.width)
1423 return;
1424
1425 if (len > (tpg->compose.width - x) / 8)
1426 len = (tpg->compose.width - x) / 8;
1427 if (tpg->vflip)
1428 y = tpg->compose.height - y - 16;
1429 if (tpg->hflip)
1430 x = tpg->compose.width - x - 8;
1431 y += tpg->compose.top;
1432 x += tpg->compose.left;
1433 if (tpg->field == V4L2_FIELD_BOTTOM)
1434 first = 1;
1435 else if (tpg->field == V4L2_FIELD_SEQ_TB || tpg->field == V4L2_FIELD_SEQ_BT)
1436 div = 2;
1437
1438 for (p = 0; p < tpg->planes; p++) {
3e14e7a8
HV
1439 unsigned vdiv = tpg->vdownsampling[p];
1440 unsigned hdiv = tpg->hdownsampling[p];
1441
1442 /* Print text */
63881df9
HV
1443#define PRINTSTR(PIXTYPE) do { \
1444 PIXTYPE fg; \
1445 PIXTYPE bg; \
1446 memcpy(&fg, tpg->textfg[p], sizeof(PIXTYPE)); \
1447 memcpy(&bg, tpg->textbg[p], sizeof(PIXTYPE)); \
1448 \
3e14e7a8 1449 for (line = first; line < 16; line += vdiv * step) { \
63881df9 1450 int l = tpg->vflip ? 15 - line : line; \
3e14e7a8
HV
1451 PIXTYPE *pos = (PIXTYPE *)(basep[p][(line / vdiv) & 1] + \
1452 ((y * step + l) / (vdiv * div)) * tpg->bytesperline[p] + \
1453 (x / hdiv) * sizeof(PIXTYPE)); \
63881df9
HV
1454 unsigned s; \
1455 \
1456 for (s = 0; s < len; s++) { \
1457 u8 chr = font8x16[text[s] * 16 + line]; \
1458 \
3e14e7a8
HV
1459 if (hdiv == 2 && tpg->hflip) { \
1460 pos[3] = (chr & (0x01 << 6) ? fg : bg); \
1461 pos[2] = (chr & (0x01 << 4) ? fg : bg); \
1462 pos[1] = (chr & (0x01 << 2) ? fg : bg); \
1463 pos[0] = (chr & (0x01 << 0) ? fg : bg); \
1464 } else if (hdiv == 2) { \
1465 pos[0] = (chr & (0x01 << 7) ? fg : bg); \
1466 pos[1] = (chr & (0x01 << 5) ? fg : bg); \
1467 pos[2] = (chr & (0x01 << 3) ? fg : bg); \
1468 pos[3] = (chr & (0x01 << 1) ? fg : bg); \
1469 } else if (tpg->hflip) { \
63881df9
HV
1470 pos[7] = (chr & (0x01 << 7) ? fg : bg); \
1471 pos[6] = (chr & (0x01 << 6) ? fg : bg); \
1472 pos[5] = (chr & (0x01 << 5) ? fg : bg); \
1473 pos[4] = (chr & (0x01 << 4) ? fg : bg); \
1474 pos[3] = (chr & (0x01 << 3) ? fg : bg); \
1475 pos[2] = (chr & (0x01 << 2) ? fg : bg); \
1476 pos[1] = (chr & (0x01 << 1) ? fg : bg); \
1477 pos[0] = (chr & (0x01 << 0) ? fg : bg); \
1478 } else { \
1479 pos[0] = (chr & (0x01 << 7) ? fg : bg); \
1480 pos[1] = (chr & (0x01 << 6) ? fg : bg); \
1481 pos[2] = (chr & (0x01 << 5) ? fg : bg); \
1482 pos[3] = (chr & (0x01 << 4) ? fg : bg); \
1483 pos[4] = (chr & (0x01 << 3) ? fg : bg); \
1484 pos[5] = (chr & (0x01 << 2) ? fg : bg); \
1485 pos[6] = (chr & (0x01 << 1) ? fg : bg); \
1486 pos[7] = (chr & (0x01 << 0) ? fg : bg); \
1487 } \
1488 \
3e14e7a8 1489 pos += (tpg->hflip ? -8 : 8) / hdiv; \
63881df9
HV
1490 } \
1491 } \
1492} while (0)
1493
1494 switch (tpg->twopixelsize[p]) {
1495 case 2:
1496 PRINTSTR(u8); break;
1497 case 4:
1498 PRINTSTR(u16); break;
1499 case 6:
1500 PRINTSTR(x24); break;
1501 case 8:
1502 PRINTSTR(u32); break;
1503 }
1504 }
1505}
1506
1507void tpg_update_mv_step(struct tpg_data *tpg)
1508{
1509 int factor = tpg->mv_hor_mode > TPG_MOVE_NONE ? -1 : 1;
1510
1511 if (tpg->hflip)
1512 factor = -factor;
1513 switch (tpg->mv_hor_mode) {
1514 case TPG_MOVE_NEG_FAST:
1515 case TPG_MOVE_POS_FAST:
1516 tpg->mv_hor_step = ((tpg->src_width + 319) / 320) * 4;
1517 break;
1518 case TPG_MOVE_NEG:
1519 case TPG_MOVE_POS:
1520 tpg->mv_hor_step = ((tpg->src_width + 639) / 640) * 4;
1521 break;
1522 case TPG_MOVE_NEG_SLOW:
1523 case TPG_MOVE_POS_SLOW:
1524 tpg->mv_hor_step = 2;
1525 break;
1526 case TPG_MOVE_NONE:
1527 tpg->mv_hor_step = 0;
1528 break;
1529 }
1530 if (factor < 0)
1531 tpg->mv_hor_step = tpg->src_width - tpg->mv_hor_step;
1532
1533 factor = tpg->mv_vert_mode > TPG_MOVE_NONE ? -1 : 1;
1534 switch (tpg->mv_vert_mode) {
1535 case TPG_MOVE_NEG_FAST:
1536 case TPG_MOVE_POS_FAST:
1537 tpg->mv_vert_step = ((tpg->src_width + 319) / 320) * 4;
1538 break;
1539 case TPG_MOVE_NEG:
1540 case TPG_MOVE_POS:
1541 tpg->mv_vert_step = ((tpg->src_width + 639) / 640) * 4;
1542 break;
1543 case TPG_MOVE_NEG_SLOW:
1544 case TPG_MOVE_POS_SLOW:
1545 tpg->mv_vert_step = 1;
1546 break;
1547 case TPG_MOVE_NONE:
1548 tpg->mv_vert_step = 0;
1549 break;
1550 }
1551 if (factor < 0)
1552 tpg->mv_vert_step = tpg->src_height - tpg->mv_vert_step;
1553}
1554
1555/* Map the line number relative to the crop rectangle to a frame line number */
dfff0489 1556static unsigned tpg_calc_frameline(const struct tpg_data *tpg, unsigned src_y,
63881df9
HV
1557 unsigned field)
1558{
1559 switch (field) {
1560 case V4L2_FIELD_TOP:
1561 return tpg->crop.top + src_y * 2;
1562 case V4L2_FIELD_BOTTOM:
1563 return tpg->crop.top + src_y * 2 + 1;
1564 default:
1565 return src_y + tpg->crop.top;
1566 }
1567}
1568
1569/*
1570 * Map the line number relative to the compose rectangle to a destination
1571 * buffer line number.
1572 */
dfff0489 1573static unsigned tpg_calc_buffer_line(const struct tpg_data *tpg, unsigned y,
63881df9
HV
1574 unsigned field)
1575{
1576 y += tpg->compose.top;
1577 switch (field) {
1578 case V4L2_FIELD_SEQ_TB:
1579 if (y & 1)
1580 return tpg->buf_height / 2 + y / 2;
1581 return y / 2;
1582 case V4L2_FIELD_SEQ_BT:
1583 if (y & 1)
1584 return y / 2;
1585 return tpg->buf_height / 2 + y / 2;
1586 default:
1587 return y;
1588 }
1589}
1590
1591static void tpg_recalc(struct tpg_data *tpg)
1592{
1593 if (tpg->recalc_colors) {
1594 tpg->recalc_colors = false;
1595 tpg->recalc_lines = true;
481b97a1
HV
1596 tpg->real_ycbcr_enc = tpg->ycbcr_enc;
1597 tpg->real_quantization = tpg->quantization;
1598 if (tpg->ycbcr_enc == V4L2_YCBCR_ENC_DEFAULT) {
1599 switch (tpg->colorspace) {
1600 case V4L2_COLORSPACE_REC709:
1601 tpg->real_ycbcr_enc = V4L2_YCBCR_ENC_709;
1602 break;
1603 case V4L2_COLORSPACE_SRGB:
1604 tpg->real_ycbcr_enc = V4L2_YCBCR_ENC_SYCC;
1605 break;
1606 case V4L2_COLORSPACE_BT2020:
1607 tpg->real_ycbcr_enc = V4L2_YCBCR_ENC_BT2020;
1608 break;
1609 case V4L2_COLORSPACE_SMPTE240M:
1610 tpg->real_ycbcr_enc = V4L2_YCBCR_ENC_SMPTE240M;
1611 break;
1612 case V4L2_COLORSPACE_SMPTE170M:
1613 case V4L2_COLORSPACE_470_SYSTEM_M:
1614 case V4L2_COLORSPACE_470_SYSTEM_BG:
1615 case V4L2_COLORSPACE_ADOBERGB:
1616 default:
1617 tpg->real_ycbcr_enc = V4L2_YCBCR_ENC_601;
1618 break;
1619 }
1620 }
1621 if (tpg->quantization == V4L2_QUANTIZATION_DEFAULT) {
1622 tpg->real_quantization = V4L2_QUANTIZATION_FULL_RANGE;
1623 if (tpg->is_yuv) {
1624 switch (tpg->real_ycbcr_enc) {
1625 case V4L2_YCBCR_ENC_SYCC:
1626 case V4L2_YCBCR_ENC_XV601:
1627 case V4L2_YCBCR_ENC_XV709:
1628 break;
1629 default:
1630 tpg->real_quantization =
1631 V4L2_QUANTIZATION_LIM_RANGE;
1632 break;
1633 }
c0b50d95
HV
1634 } else if (tpg->colorspace == V4L2_COLORSPACE_BT2020) {
1635 /* R'G'B' BT.2020 is limited range */
1636 tpg->real_quantization =
1637 V4L2_QUANTIZATION_LIM_RANGE;
481b97a1
HV
1638 }
1639 }
63881df9
HV
1640 tpg_precalculate_colors(tpg);
1641 }
1642 if (tpg->recalc_square_border) {
1643 tpg->recalc_square_border = false;
1644 tpg_calculate_square_border(tpg);
1645 }
1646 if (tpg->recalc_lines) {
1647 tpg->recalc_lines = false;
1648 tpg_precalculate_line(tpg);
1649 }
1650}
1651
1652void tpg_calc_text_basep(struct tpg_data *tpg,
1653 u8 *basep[TPG_MAX_PLANES][2], unsigned p, u8 *vbuf)
1654{
1655 unsigned stride = tpg->bytesperline[p];
280abe47 1656 unsigned h = tpg->buf_height;
63881df9
HV
1657
1658 tpg_recalc(tpg);
1659
1660 basep[p][0] = vbuf;
1661 basep[p][1] = vbuf;
280abe47 1662 h /= tpg->vdownsampling[p];
63881df9 1663 if (tpg->field == V4L2_FIELD_SEQ_TB)
280abe47 1664 basep[p][1] += h * stride / 2;
63881df9 1665 else if (tpg->field == V4L2_FIELD_SEQ_BT)
280abe47 1666 basep[p][0] += h * stride / 2;
02aa769d
HV
1667 if (p == 0 && tpg->interleaved)
1668 tpg_calc_text_basep(tpg, basep, 1, vbuf);
280abe47
HV
1669}
1670
1671static int tpg_pattern_avg(const struct tpg_data *tpg,
1672 unsigned pat1, unsigned pat2)
1673{
1674 unsigned pat_lines = tpg_get_pat_lines(tpg);
1675
1676 if (pat1 == (pat2 + 1) % pat_lines)
1677 return pat2;
1678 if (pat2 == (pat1 + 1) % pat_lines)
1679 return pat1;
1680 return -1;
63881df9
HV
1681}
1682
84b76d74
HV
1683void tpg_log_status(struct tpg_data *tpg)
1684{
1685 pr_info("tpg source WxH: %ux%u (%s)\n",
1686 tpg->src_width, tpg->src_height,
1687 tpg->is_yuv ? "YCbCr" : "RGB");
1688 pr_info("tpg field: %u\n", tpg->field);
1689 pr_info("tpg crop: %ux%u@%dx%d\n", tpg->crop.width, tpg->crop.height,
1690 tpg->crop.left, tpg->crop.top);
1691 pr_info("tpg compose: %ux%u@%dx%d\n", tpg->compose.width, tpg->compose.height,
1692 tpg->compose.left, tpg->compose.top);
1693 pr_info("tpg colorspace: %d\n", tpg->colorspace);
1694 pr_info("tpg Y'CbCr encoding: %d/%d\n", tpg->ycbcr_enc, tpg->real_ycbcr_enc);
1695 pr_info("tpg quantization: %d/%d\n", tpg->quantization, tpg->real_quantization);
1696 pr_info("tpg RGB range: %d/%d\n", tpg->rgb_range, tpg->real_rgb_range);
1697}
1698
e76036d8
HV
1699/*
1700 * This struct contains common parameters used by both the drawing of the
1701 * test pattern and the drawing of the extras (borders, square, etc.)
1702 */
1703struct tpg_draw_params {
1704 /* common data */
1705 bool is_tv;
1706 bool is_60hz;
1707 unsigned twopixsize;
1708 unsigned img_width;
1709 unsigned stride;
1710 unsigned hmax;
1711 unsigned frame_line;
1712 unsigned frame_line_next;
1713
1714 /* test pattern */
1715 unsigned mv_hor_old;
1716 unsigned mv_hor_new;
1717 unsigned mv_vert_old;
1718 unsigned mv_vert_new;
1719
1720 /* extras */
1721 unsigned wss_width;
1722 unsigned wss_random_offset;
1723 unsigned sav_eav_f;
1724 unsigned left_pillar_width;
1725 unsigned right_pillar_start;
1726};
1727
f0ce4fd6
HV
1728static void tpg_fill_params_pattern(const struct tpg_data *tpg, unsigned p,
1729 struct tpg_draw_params *params)
1730{
1731 params->mv_hor_old =
1732 tpg_hscale_div(tpg, p, tpg->mv_hor_count % tpg->src_width);
1733 params->mv_hor_new =
1734 tpg_hscale_div(tpg, p, (tpg->mv_hor_count + tpg->mv_hor_step) %
1735 tpg->src_width);
1736 params->mv_vert_old = tpg->mv_vert_count % tpg->src_height;
1737 params->mv_vert_new =
1738 (tpg->mv_vert_count + tpg->mv_vert_step) % tpg->src_height;
1739}
1740
07386b9a
HV
1741static void tpg_fill_params_extras(const struct tpg_data *tpg,
1742 unsigned p,
1743 struct tpg_draw_params *params)
1744{
1745 unsigned left_pillar_width = 0;
1746 unsigned right_pillar_start = params->img_width;
1747
1748 params->wss_width = tpg->crop.left < tpg->src_width / 2 ?
1749 tpg->src_width / 2 - tpg->crop.left : 0;
1750 if (params->wss_width > tpg->crop.width)
1751 params->wss_width = tpg->crop.width;
1752 params->wss_width = tpg_hscale_div(tpg, p, params->wss_width);
1753 params->wss_random_offset =
1754 params->twopixsize * prandom_u32_max(tpg->src_width / 2);
1755
1756 if (tpg->crop.left < tpg->border.left) {
1757 left_pillar_width = tpg->border.left - tpg->crop.left;
1758 if (left_pillar_width > tpg->crop.width)
1759 left_pillar_width = tpg->crop.width;
1760 left_pillar_width = tpg_hscale_div(tpg, p, left_pillar_width);
1761 }
1762 params->left_pillar_width = left_pillar_width;
1763
1764 if (tpg->crop.left + tpg->crop.width >
1765 tpg->border.left + tpg->border.width) {
1766 right_pillar_start =
1767 tpg->border.left + tpg->border.width - tpg->crop.left;
1768 right_pillar_start =
1769 tpg_hscale_div(tpg, p, right_pillar_start);
1770 if (right_pillar_start > params->img_width)
1771 right_pillar_start = params->img_width;
1772 }
1773 params->right_pillar_start = right_pillar_start;
1774
1775 params->sav_eav_f = tpg->field ==
1776 (params->is_60hz ? V4L2_FIELD_TOP : V4L2_FIELD_BOTTOM);
1777}
1778
c6ff1c1b
HV
1779static void tpg_fill_plane_extras(const struct tpg_data *tpg,
1780 const struct tpg_draw_params *params,
1781 unsigned p, unsigned h, u8 *vbuf)
1782{
1783 unsigned twopixsize = params->twopixsize;
1784 unsigned img_width = params->img_width;
1785 unsigned frame_line = params->frame_line;
1786 const struct v4l2_rect *sq = &tpg->square;
1787 const struct v4l2_rect *b = &tpg->border;
1788 const struct v4l2_rect *c = &tpg->crop;
1789
1790 if (params->is_tv && !params->is_60hz &&
1791 frame_line == 0 && params->wss_width) {
1792 /*
1793 * Replace the first half of the top line of a 50 Hz frame
1794 * with random data to simulate a WSS signal.
1795 */
1796 u8 *wss = tpg->random_line[p] + params->wss_random_offset;
1797
1798 memcpy(vbuf, wss, params->wss_width);
1799 }
1800
1801 if (tpg->show_border && frame_line >= b->top &&
1802 frame_line < b->top + b->height) {
1803 unsigned bottom = b->top + b->height - 1;
1804 unsigned left = params->left_pillar_width;
1805 unsigned right = params->right_pillar_start;
1806
1807 if (frame_line == b->top || frame_line == b->top + 1 ||
1808 frame_line == bottom || frame_line == bottom - 1) {
1809 memcpy(vbuf + left, tpg->contrast_line[p],
1810 right - left);
1811 } else {
1812 if (b->left >= c->left &&
1813 b->left < c->left + c->width)
1814 memcpy(vbuf + left,
1815 tpg->contrast_line[p], twopixsize);
1816 if (b->left + b->width > c->left &&
1817 b->left + b->width <= c->left + c->width)
1818 memcpy(vbuf + right - twopixsize,
1819 tpg->contrast_line[p], twopixsize);
1820 }
1821 }
1822 if (tpg->qual != TPG_QUAL_NOISE && frame_line >= b->top &&
1823 frame_line < b->top + b->height) {
1824 memcpy(vbuf, tpg->black_line[p], params->left_pillar_width);
1825 memcpy(vbuf + params->right_pillar_start, tpg->black_line[p],
1826 img_width - params->right_pillar_start);
1827 }
1828 if (tpg->show_square && frame_line >= sq->top &&
1829 frame_line < sq->top + sq->height &&
1830 sq->left < c->left + c->width &&
1831 sq->left + sq->width >= c->left) {
1832 unsigned left = sq->left;
1833 unsigned width = sq->width;
1834
1835 if (c->left > left) {
1836 width -= c->left - left;
1837 left = c->left;
1838 }
1839 if (c->left + c->width < left + width)
1840 width -= left + width - c->left - c->width;
1841 left -= c->left;
1842 left = tpg_hscale_div(tpg, p, left);
1843 width = tpg_hscale_div(tpg, p, width);
1844 memcpy(vbuf + left, tpg->contrast_line[p], width);
1845 }
1846 if (tpg->insert_sav) {
1847 unsigned offset = tpg_hdiv(tpg, p, tpg->compose.width / 3);
1848 u8 *p = vbuf + offset;
1849 unsigned vact = 0, hact = 0;
1850
1851 p[0] = 0xff;
1852 p[1] = 0;
1853 p[2] = 0;
1854 p[3] = 0x80 | (params->sav_eav_f << 6) |
1855 (vact << 5) | (hact << 4) |
1856 ((hact ^ vact) << 3) |
1857 ((hact ^ params->sav_eav_f) << 2) |
1858 ((params->sav_eav_f ^ vact) << 1) |
1859 (hact ^ vact ^ params->sav_eav_f);
1860 }
1861 if (tpg->insert_eav) {
1862 unsigned offset = tpg_hdiv(tpg, p, tpg->compose.width * 2 / 3);
1863 u8 *p = vbuf + offset;
1864 unsigned vact = 0, hact = 1;
1865
1866 p[0] = 0xff;
1867 p[1] = 0;
1868 p[2] = 0;
1869 p[3] = 0x80 | (params->sav_eav_f << 6) |
1870 (vact << 5) | (hact << 4) |
1871 ((hact ^ vact) << 3) |
1872 ((hact ^ params->sav_eav_f) << 2) |
1873 ((params->sav_eav_f ^ vact) << 1) |
1874 (hact ^ vact ^ params->sav_eav_f);
1875 }
1876}
1877
ecb9e91b
HV
1878static void tpg_fill_plane_pattern(const struct tpg_data *tpg,
1879 const struct tpg_draw_params *params,
1880 unsigned p, unsigned h, u8 *vbuf)
1881{
1882 unsigned twopixsize = params->twopixsize;
1883 unsigned img_width = params->img_width;
1884 unsigned mv_hor_old = params->mv_hor_old;
1885 unsigned mv_hor_new = params->mv_hor_new;
1886 unsigned mv_vert_old = params->mv_vert_old;
1887 unsigned mv_vert_new = params->mv_vert_new;
1888 unsigned frame_line = params->frame_line;
1889 unsigned frame_line_next = params->frame_line_next;
1890 unsigned line_offset = tpg_hscale_div(tpg, p, tpg->crop.left);
1891 bool even;
1892 bool fill_blank = false;
1893 unsigned pat_line_old;
1894 unsigned pat_line_new;
1895 u8 *linestart_older;
1896 u8 *linestart_newer;
1897 u8 *linestart_top;
1898 u8 *linestart_bottom;
1899
1900 even = !(frame_line & 1);
1901
1902 if (h >= params->hmax) {
1903 if (params->hmax == tpg->compose.height)
1904 return;
1905 if (!tpg->perc_fill_blank)
1906 return;
1907 fill_blank = true;
1908 }
1909
1910 if (tpg->vflip) {
1911 frame_line = tpg->src_height - frame_line - 1;
1912 frame_line_next = tpg->src_height - frame_line_next - 1;
1913 }
1914
1915 if (fill_blank) {
1916 linestart_older = tpg->contrast_line[p];
1917 linestart_newer = tpg->contrast_line[p];
1918 } else if (tpg->qual != TPG_QUAL_NOISE &&
1919 (frame_line < tpg->border.top ||
1920 frame_line >= tpg->border.top + tpg->border.height)) {
1921 linestart_older = tpg->black_line[p];
1922 linestart_newer = tpg->black_line[p];
1923 } else if (tpg->pattern == TPG_PAT_NOISE || tpg->qual == TPG_QUAL_NOISE) {
1924 linestart_older = tpg->random_line[p] +
1925 twopixsize * prandom_u32_max(tpg->src_width / 2);
1926 linestart_newer = tpg->random_line[p] +
1927 twopixsize * prandom_u32_max(tpg->src_width / 2);
1928 } else {
1929 unsigned frame_line_old =
1930 (frame_line + mv_vert_old) % tpg->src_height;
1931 unsigned frame_line_new =
1932 (frame_line + mv_vert_new) % tpg->src_height;
1933 unsigned pat_line_next_old;
1934 unsigned pat_line_next_new;
1935
1936 pat_line_old = tpg_get_pat_line(tpg, frame_line_old);
1937 pat_line_new = tpg_get_pat_line(tpg, frame_line_new);
1938 linestart_older = tpg->lines[pat_line_old][p] + mv_hor_old;
1939 linestart_newer = tpg->lines[pat_line_new][p] + mv_hor_new;
1940
1941 if (tpg->vdownsampling[p] > 1 && frame_line != frame_line_next) {
1942 int avg_pat;
1943
1944 /*
1945 * Now decide whether we need to use downsampled_lines[].
1946 * That's necessary if the two lines use different patterns.
1947 */
1948 pat_line_next_old = tpg_get_pat_line(tpg,
1949 (frame_line_next + mv_vert_old) % tpg->src_height);
1950 pat_line_next_new = tpg_get_pat_line(tpg,
1951 (frame_line_next + mv_vert_new) % tpg->src_height);
1952
1953 switch (tpg->field) {
1954 case V4L2_FIELD_INTERLACED:
1955 case V4L2_FIELD_INTERLACED_BT:
1956 case V4L2_FIELD_INTERLACED_TB:
1957 avg_pat = tpg_pattern_avg(tpg, pat_line_old, pat_line_new);
1958 if (avg_pat < 0)
1959 break;
1960 linestart_older = tpg->downsampled_lines[avg_pat][p] + mv_hor_old;
1961 linestart_newer = linestart_older;
1962 break;
1963 case V4L2_FIELD_NONE:
1964 case V4L2_FIELD_TOP:
1965 case V4L2_FIELD_BOTTOM:
1966 case V4L2_FIELD_SEQ_BT:
1967 case V4L2_FIELD_SEQ_TB:
1968 avg_pat = tpg_pattern_avg(tpg, pat_line_old, pat_line_next_old);
1969 if (avg_pat >= 0)
1970 linestart_older = tpg->downsampled_lines[avg_pat][p] +
1971 mv_hor_old;
1972 avg_pat = tpg_pattern_avg(tpg, pat_line_new, pat_line_next_new);
1973 if (avg_pat >= 0)
1974 linestart_newer = tpg->downsampled_lines[avg_pat][p] +
1975 mv_hor_new;
1976 break;
1977 }
1978 }
1979 linestart_older += line_offset;
1980 linestart_newer += line_offset;
1981 }
1982 if (tpg->field_alternate) {
1983 linestart_top = linestart_bottom = linestart_older;
1984 } else if (params->is_60hz) {
1985 linestart_top = linestart_newer;
1986 linestart_bottom = linestart_older;
1987 } else {
1988 linestart_top = linestart_older;
1989 linestart_bottom = linestart_newer;
1990 }
1991
1992 switch (tpg->field) {
1993 case V4L2_FIELD_INTERLACED:
1994 case V4L2_FIELD_INTERLACED_TB:
1995 case V4L2_FIELD_SEQ_TB:
1996 case V4L2_FIELD_SEQ_BT:
1997 if (even)
1998 memcpy(vbuf, linestart_top, img_width);
1999 else
2000 memcpy(vbuf, linestart_bottom, img_width);
2001 break;
2002 case V4L2_FIELD_INTERLACED_BT:
2003 if (even)
2004 memcpy(vbuf, linestart_bottom, img_width);
2005 else
2006 memcpy(vbuf, linestart_top, img_width);
2007 break;
2008 case V4L2_FIELD_TOP:
2009 memcpy(vbuf, linestart_top, img_width);
2010 break;
2011 case V4L2_FIELD_BOTTOM:
2012 memcpy(vbuf, linestart_bottom, img_width);
2013 break;
2014 case V4L2_FIELD_NONE:
2015 default:
2016 memcpy(vbuf, linestart_older, img_width);
2017 break;
2018 }
2019}
2020
2021void tpg_fill_plane_buffer(struct tpg_data *tpg, v4l2_std_id std,
2022 unsigned p, u8 *vbuf)
63881df9 2023{
5e729393 2024 struct tpg_draw_params params;
63881df9 2025 unsigned factor = V4L2_FIELD_HAS_T_OR_B(tpg->field) ? 2 : 1;
63881df9
HV
2026
2027 /* Coarse scaling with Bresenham */
2028 unsigned int_part = (tpg->crop.height / factor) / tpg->compose.height;
2029 unsigned fract_part = (tpg->crop.height / factor) % tpg->compose.height;
2030 unsigned src_y = 0;
2031 unsigned error = 0;
ecb9e91b 2032 unsigned h;
63881df9
HV
2033
2034 tpg_recalc(tpg);
2035
5e729393
HV
2036 params.is_tv = std;
2037 params.is_60hz = std & V4L2_STD_525_60;
2038 params.twopixsize = tpg->twopixelsize[p];
2039 params.img_width = tpg_hdiv(tpg, p, tpg->compose.width);
2040 params.stride = tpg->bytesperline[p];
2041 params.hmax = (tpg->compose.height * tpg->perc_fill) / 100;
2042
f0ce4fd6 2043 tpg_fill_params_pattern(tpg, p, &params);
07386b9a
HV
2044 tpg_fill_params_extras(tpg, p, &params);
2045
9991deff 2046 vbuf += tpg_hdiv(tpg, p, tpg->compose.left);
63881df9
HV
2047
2048 for (h = 0; h < tpg->compose.height; h++) {
63881df9 2049 unsigned buf_line;
63881df9 2050
c6ff1c1b
HV
2051 params.frame_line = tpg_calc_frameline(tpg, src_y, tpg->field);
2052 params.frame_line_next = params.frame_line;
63881df9
HV
2053 buf_line = tpg_calc_buffer_line(tpg, h, tpg->field);
2054 src_y += int_part;
2055 error += fract_part;
2056 if (error >= tpg->compose.height) {
2057 error -= tpg->compose.height;
2058 src_y++;
2059 }
2060
02aa769d
HV
2061 /*
2062 * For line-interleaved formats determine the 'plane'
2063 * based on the buffer line.
2064 */
2065 if (tpg_g_interleaved(tpg))
2066 p = tpg_g_interleaved_plane(tpg, buf_line);
2067
ecb9e91b 2068 if (tpg->vdownsampling[p] > 1) {
280abe47
HV
2069 /*
2070 * When doing vertical downsampling the field setting
2071 * matters: for SEQ_BT/TB we downsample each field
2072 * separately (i.e. lines 0+2 are combined, as are
2073 * lines 1+3), for the other field settings we combine
2074 * odd and even lines. Doing that for SEQ_BT/TB would
2075 * be really weird.
2076 */
2077 if (tpg->field == V4L2_FIELD_SEQ_BT ||
2078 tpg->field == V4L2_FIELD_SEQ_TB) {
ecb9e91b
HV
2079 unsigned next_src_y = src_y;
2080
280abe47
HV
2081 if ((h & 3) >= 2)
2082 continue;
ecb9e91b
HV
2083 next_src_y += int_part;
2084 if (error + fract_part >= tpg->compose.height)
2085 next_src_y++;
2086 params.frame_line_next =
2087 tpg_calc_frameline(tpg, next_src_y, tpg->field);
2088 } else {
2089 if (h & 1)
2090 continue;
2091 params.frame_line_next =
2092 tpg_calc_frameline(tpg, src_y, tpg->field);
280abe47 2093 }
63881df9 2094
ecb9e91b 2095 buf_line /= tpg->vdownsampling[p];
63881df9 2096 }
ecb9e91b
HV
2097 tpg_fill_plane_pattern(tpg, &params, p, h,
2098 vbuf + buf_line * params.stride);
c6ff1c1b
HV
2099 tpg_fill_plane_extras(tpg, &params, p, h,
2100 vbuf + buf_line * params.stride);
63881df9
HV
2101 }
2102}
4db22041
HV
2103
2104void tpg_fillbuffer(struct tpg_data *tpg, v4l2_std_id std, unsigned p, u8 *vbuf)
2105{
2106 unsigned offset = 0;
2107 unsigned i;
2108
2109 if (tpg->buffers > 1) {
2110 tpg_fill_plane_buffer(tpg, std, p, vbuf);
2111 return;
2112 }
2113
02aa769d 2114 for (i = 0; i < tpg_g_planes(tpg); i++) {
4db22041
HV
2115 tpg_fill_plane_buffer(tpg, std, i, vbuf + offset);
2116 offset += tpg_calc_plane_size(tpg, i);
2117 }
2118}