[media] vivid-tpg: add hor/vert downsampling fields
[deliverable/linux.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++) {
126 unsigned pixelsz = plane ? 1 : 4;
127
128 tpg->lines[pat][plane] = vzalloc(max_w * 2 * pixelsz);
129 if (!tpg->lines[pat][plane])
130 return -ENOMEM;
131 }
132 }
133 for (plane = 0; plane < TPG_MAX_PLANES; plane++) {
134 unsigned pixelsz = plane ? 1 : 4;
135
136 tpg->contrast_line[plane] = vzalloc(max_w * pixelsz);
137 if (!tpg->contrast_line[plane])
138 return -ENOMEM;
139 tpg->black_line[plane] = vzalloc(max_w * pixelsz);
140 if (!tpg->black_line[plane])
141 return -ENOMEM;
c204e1fa 142 tpg->random_line[plane] = vzalloc(max_w * 2 * pixelsz);
63881df9
HV
143 if (!tpg->random_line[plane])
144 return -ENOMEM;
145 }
146 return 0;
147}
148
149void tpg_free(struct tpg_data *tpg)
150{
151 unsigned pat;
152 unsigned plane;
153
154 for (pat = 0; pat < TPG_MAX_PAT_LINES; pat++)
155 for (plane = 0; plane < TPG_MAX_PLANES; plane++) {
156 vfree(tpg->lines[pat][plane]);
157 tpg->lines[pat][plane] = NULL;
158 }
159 for (plane = 0; plane < TPG_MAX_PLANES; plane++) {
160 vfree(tpg->contrast_line[plane]);
161 vfree(tpg->black_line[plane]);
162 vfree(tpg->random_line[plane]);
163 tpg->contrast_line[plane] = NULL;
164 tpg->black_line[plane] = NULL;
165 tpg->random_line[plane] = NULL;
166 }
167}
168
169bool tpg_s_fourcc(struct tpg_data *tpg, u32 fourcc)
170{
171 tpg->fourcc = fourcc;
172 tpg->planes = 1;
06d1f0c2 173 tpg->buffers = 1;
63881df9 174 tpg->recalc_colors = true;
ba01f673
HV
175 tpg->vdownsampling[0] = 1;
176 tpg->hdownsampling[0] = 1;
06d1f0c2 177
63881df9
HV
178 switch (fourcc) {
179 case V4L2_PIX_FMT_RGB565:
180 case V4L2_PIX_FMT_RGB565X:
181 case V4L2_PIX_FMT_RGB555:
182 case V4L2_PIX_FMT_XRGB555:
183 case V4L2_PIX_FMT_ARGB555:
184 case V4L2_PIX_FMT_RGB555X:
185 case V4L2_PIX_FMT_RGB24:
186 case V4L2_PIX_FMT_BGR24:
187 case V4L2_PIX_FMT_RGB32:
188 case V4L2_PIX_FMT_BGR32:
189 case V4L2_PIX_FMT_XRGB32:
190 case V4L2_PIX_FMT_XBGR32:
191 case V4L2_PIX_FMT_ARGB32:
192 case V4L2_PIX_FMT_ABGR32:
6c515a44 193 tpg->is_yuv = false;
63881df9
HV
194 break;
195 case V4L2_PIX_FMT_NV16M:
196 case V4L2_PIX_FMT_NV61M:
ba01f673
HV
197 tpg->vdownsampling[1] = 1;
198 tpg->hdownsampling[1] = 1;
06d1f0c2 199 tpg->buffers = 2;
63881df9
HV
200 tpg->planes = 2;
201 /* fall-through */
202 case V4L2_PIX_FMT_YUYV:
203 case V4L2_PIX_FMT_UYVY:
204 case V4L2_PIX_FMT_YVYU:
205 case V4L2_PIX_FMT_VYUY:
6c515a44 206 tpg->is_yuv = true;
63881df9
HV
207 break;
208 default:
209 return false;
210 }
211
212 switch (fourcc) {
213 case V4L2_PIX_FMT_RGB565:
214 case V4L2_PIX_FMT_RGB565X:
215 case V4L2_PIX_FMT_RGB555:
216 case V4L2_PIX_FMT_XRGB555:
217 case V4L2_PIX_FMT_ARGB555:
218 case V4L2_PIX_FMT_RGB555X:
219 case V4L2_PIX_FMT_YUYV:
220 case V4L2_PIX_FMT_UYVY:
221 case V4L2_PIX_FMT_YVYU:
222 case V4L2_PIX_FMT_VYUY:
223 tpg->twopixelsize[0] = 2 * 2;
224 break;
225 case V4L2_PIX_FMT_RGB24:
226 case V4L2_PIX_FMT_BGR24:
227 tpg->twopixelsize[0] = 2 * 3;
228 break;
229 case V4L2_PIX_FMT_RGB32:
230 case V4L2_PIX_FMT_BGR32:
231 case V4L2_PIX_FMT_XRGB32:
232 case V4L2_PIX_FMT_XBGR32:
233 case V4L2_PIX_FMT_ARGB32:
234 case V4L2_PIX_FMT_ABGR32:
235 tpg->twopixelsize[0] = 2 * 4;
236 break;
237 case V4L2_PIX_FMT_NV16M:
238 case V4L2_PIX_FMT_NV61M:
239 tpg->twopixelsize[0] = 2;
240 tpg->twopixelsize[1] = 2;
241 break;
242 }
243 return true;
244}
245
246void tpg_s_crop_compose(struct tpg_data *tpg, const struct v4l2_rect *crop,
247 const struct v4l2_rect *compose)
248{
249 tpg->crop = *crop;
250 tpg->compose = *compose;
251 tpg->scaled_width = (tpg->src_width * tpg->compose.width +
252 tpg->crop.width - 1) / tpg->crop.width;
253 tpg->scaled_width &= ~1;
254 if (tpg->scaled_width > tpg->max_line_width)
255 tpg->scaled_width = tpg->max_line_width;
256 if (tpg->scaled_width < 2)
257 tpg->scaled_width = 2;
258 tpg->recalc_lines = true;
259}
260
261void tpg_reset_source(struct tpg_data *tpg, unsigned width, unsigned height,
73d81022 262 u32 field)
63881df9
HV
263{
264 unsigned p;
265
266 tpg->src_width = width;
267 tpg->src_height = height;
268 tpg->field = field;
269 tpg->buf_height = height;
270 if (V4L2_FIELD_HAS_T_OR_B(field))
271 tpg->buf_height /= 2;
272 tpg->scaled_width = width;
273 tpg->crop.top = tpg->crop.left = 0;
274 tpg->crop.width = width;
275 tpg->crop.height = height;
276 tpg->compose.top = tpg->compose.left = 0;
277 tpg->compose.width = width;
278 tpg->compose.height = tpg->buf_height;
279 for (p = 0; p < tpg->planes; p++)
ba01f673
HV
280 tpg->bytesperline[p] = (width * tpg->twopixelsize[p]) /
281 (2 * tpg->hdownsampling[p]);
63881df9
HV
282 tpg->recalc_square_border = true;
283}
284
285static enum tpg_color tpg_get_textbg_color(struct tpg_data *tpg)
286{
287 switch (tpg->pattern) {
288 case TPG_PAT_BLACK:
289 return TPG_COLOR_100_WHITE;
290 case TPG_PAT_CSC_COLORBAR:
291 return TPG_COLOR_CSC_BLACK;
292 default:
293 return TPG_COLOR_100_BLACK;
294 }
295}
296
297static enum tpg_color tpg_get_textfg_color(struct tpg_data *tpg)
298{
299 switch (tpg->pattern) {
300 case TPG_PAT_75_COLORBAR:
301 case TPG_PAT_CSC_COLORBAR:
302 return TPG_COLOR_CSC_WHITE;
303 case TPG_PAT_BLACK:
304 return TPG_COLOR_100_BLACK;
305 default:
306 return TPG_COLOR_100_WHITE;
307 }
308}
309
481b97a1 310static inline int rec709_to_linear(int v)
63881df9 311{
481b97a1
HV
312 v = clamp(v, 0, 0xff0);
313 return tpg_rec709_to_linear[v];
63881df9
HV
314}
315
481b97a1 316static inline int linear_to_rec709(int v)
63881df9 317{
481b97a1
HV
318 v = clamp(v, 0, 0xff0);
319 return tpg_linear_to_rec709[v];
63881df9
HV
320}
321
481b97a1
HV
322static void rgb2ycbcr(const int m[3][3], int r, int g, int b,
323 int y_offset, int *y, int *cb, int *cr)
63881df9 324{
481b97a1
HV
325 *y = ((m[0][0] * r + m[0][1] * g + m[0][2] * b) >> 16) + (y_offset << 4);
326 *cb = ((m[1][0] * r + m[1][1] * g + m[1][2] * b) >> 16) + (128 << 4);
327 *cr = ((m[2][0] * r + m[2][1] * g + m[2][2] * b) >> 16) + (128 << 4);
63881df9
HV
328}
329
481b97a1
HV
330static void color_to_ycbcr(struct tpg_data *tpg, int r, int g, int b,
331 int *y, int *cb, int *cr)
63881df9 332{
481b97a1 333#define COEFF(v, r) ((int)(0.5 + (v) * (r) * 256.0))
63881df9 334
481b97a1
HV
335 static const int bt601[3][3] = {
336 { COEFF(0.299, 219), COEFF(0.587, 219), COEFF(0.114, 219) },
337 { COEFF(-0.169, 224), COEFF(-0.331, 224), COEFF(0.5, 224) },
338 { COEFF(0.5, 224), COEFF(-0.419, 224), COEFF(-0.081, 224) },
339 };
340 static const int bt601_full[3][3] = {
341 { COEFF(0.299, 255), COEFF(0.587, 255), COEFF(0.114, 255) },
342 { COEFF(-0.169, 255), COEFF(-0.331, 255), COEFF(0.5, 255) },
343 { COEFF(0.5, 255), COEFF(-0.419, 255), COEFF(-0.081, 255) },
344 };
345 static const int rec709[3][3] = {
346 { COEFF(0.2126, 219), COEFF(0.7152, 219), COEFF(0.0722, 219) },
347 { COEFF(-0.1146, 224), COEFF(-0.3854, 224), COEFF(0.5, 224) },
348 { COEFF(0.5, 224), COEFF(-0.4542, 224), COEFF(-0.0458, 224) },
349 };
350 static const int rec709_full[3][3] = {
351 { COEFF(0.2126, 255), COEFF(0.7152, 255), COEFF(0.0722, 255) },
352 { COEFF(-0.1146, 255), COEFF(-0.3854, 255), COEFF(0.5, 255) },
353 { COEFF(0.5, 255), COEFF(-0.4542, 255), COEFF(-0.0458, 255) },
354 };
355 static const int smpte240m[3][3] = {
356 { COEFF(0.212, 219), COEFF(0.701, 219), COEFF(0.087, 219) },
357 { COEFF(-0.116, 224), COEFF(-0.384, 224), COEFF(0.5, 224) },
358 { COEFF(0.5, 224), COEFF(-0.445, 224), COEFF(-0.055, 224) },
359 };
360 static const int bt2020[3][3] = {
361 { COEFF(0.2726, 219), COEFF(0.6780, 219), COEFF(0.0593, 219) },
362 { COEFF(-0.1396, 224), COEFF(-0.3604, 224), COEFF(0.5, 224) },
363 { COEFF(0.5, 224), COEFF(-0.4629, 224), COEFF(-0.0405, 224) },
364 };
365 bool full = tpg->real_quantization == V4L2_QUANTIZATION_FULL_RANGE;
afad4dd5 366 unsigned y_offset = full ? 0 : 16;
481b97a1
HV
367 int lin_y, yc;
368
369 switch (tpg->real_ycbcr_enc) {
370 case V4L2_YCBCR_ENC_601:
371 case V4L2_YCBCR_ENC_XV601:
372 case V4L2_YCBCR_ENC_SYCC:
afad4dd5 373 rgb2ycbcr(full ? bt601_full : bt601, r, g, b, y_offset, y, cb, cr);
481b97a1
HV
374 break;
375 case V4L2_YCBCR_ENC_BT2020:
376 rgb2ycbcr(bt2020, r, g, b, 16, y, cb, cr);
63881df9 377 break;
481b97a1
HV
378 case V4L2_YCBCR_ENC_BT2020_CONST_LUM:
379 lin_y = (COEFF(0.2627, 255) * rec709_to_linear(r) +
380 COEFF(0.6780, 255) * rec709_to_linear(g) +
381 COEFF(0.0593, 255) * rec709_to_linear(b)) >> 16;
382 yc = linear_to_rec709(lin_y);
383 *y = (yc * 219) / 255 + (16 << 4);
384 if (b <= yc)
385 *cb = (((b - yc) * COEFF(1.0 / 1.9404, 224)) >> 16) + (128 << 4);
386 else
387 *cb = (((b - yc) * COEFF(1.0 / 1.5816, 224)) >> 16) + (128 << 4);
388 if (r <= yc)
389 *cr = (((r - yc) * COEFF(1.0 / 1.7184, 224)) >> 16) + (128 << 4);
390 else
391 *cr = (((r - yc) * COEFF(1.0 / 0.9936, 224)) >> 16) + (128 << 4);
63881df9 392 break;
481b97a1
HV
393 case V4L2_YCBCR_ENC_SMPTE240M:
394 rgb2ycbcr(smpte240m, r, g, b, 16, y, cb, cr);
395 break;
396 case V4L2_YCBCR_ENC_709:
397 case V4L2_YCBCR_ENC_XV709:
63881df9 398 default:
afad4dd5 399 rgb2ycbcr(full ? rec709_full : rec709, r, g, b, y_offset, y, cb, cr);
63881df9
HV
400 break;
401 }
63881df9
HV
402}
403
481b97a1
HV
404static void ycbcr2rgb(const int m[3][3], int y, int cb, int cr,
405 int y_offset, int *r, int *g, int *b)
63881df9 406{
481b97a1 407 y -= y_offset << 4;
63881df9
HV
408 cb -= 128 << 4;
409 cr -= 128 << 4;
481b97a1
HV
410 *r = m[0][0] * y + m[0][1] * cb + m[0][2] * cr;
411 *g = m[1][0] * y + m[1][1] * cb + m[1][2] * cr;
412 *b = m[2][0] * y + m[2][1] * cb + m[2][2] * cr;
413 *r = clamp(*r >> 12, 0, 0xff0);
414 *g = clamp(*g >> 12, 0, 0xff0);
415 *b = clamp(*b >> 12, 0, 0xff0);
63881df9
HV
416}
417
481b97a1
HV
418static void ycbcr_to_color(struct tpg_data *tpg, int y, int cb, int cr,
419 int *r, int *g, int *b)
63881df9 420{
481b97a1
HV
421#undef COEFF
422#define COEFF(v, r) ((int)(0.5 + (v) * ((255.0 * 255.0 * 16.0) / (r))))
423 static const int bt601[3][3] = {
424 { COEFF(1, 219), COEFF(0, 224), COEFF(1.4020, 224) },
425 { COEFF(1, 219), COEFF(-0.3441, 224), COEFF(-0.7141, 224) },
426 { COEFF(1, 219), COEFF(1.7720, 224), COEFF(0, 224) },
427 };
428 static const int bt601_full[3][3] = {
429 { COEFF(1, 255), COEFF(0, 255), COEFF(1.4020, 255) },
430 { COEFF(1, 255), COEFF(-0.3441, 255), COEFF(-0.7141, 255) },
431 { COEFF(1, 255), COEFF(1.7720, 255), COEFF(0, 255) },
432 };
433 static const int rec709[3][3] = {
434 { COEFF(1, 219), COEFF(0, 224), COEFF(1.5748, 224) },
435 { COEFF(1, 219), COEFF(-0.1873, 224), COEFF(-0.4681, 224) },
436 { COEFF(1, 219), COEFF(1.8556, 224), COEFF(0, 224) },
437 };
438 static const int rec709_full[3][3] = {
439 { COEFF(1, 255), COEFF(0, 255), COEFF(1.5748, 255) },
440 { COEFF(1, 255), COEFF(-0.1873, 255), COEFF(-0.4681, 255) },
441 { COEFF(1, 255), COEFF(1.8556, 255), COEFF(0, 255) },
442 };
443 static const int smpte240m[3][3] = {
444 { COEFF(1, 219), COEFF(0, 224), COEFF(1.5756, 224) },
445 { COEFF(1, 219), COEFF(-0.2253, 224), COEFF(-0.4767, 224) },
446 { COEFF(1, 219), COEFF(1.8270, 224), COEFF(0, 224) },
447 };
448 static const int bt2020[3][3] = {
449 { COEFF(1, 219), COEFF(0, 224), COEFF(1.4746, 224) },
450 { COEFF(1, 219), COEFF(-0.1646, 224), COEFF(-0.5714, 224) },
451 { COEFF(1, 219), COEFF(1.8814, 224), COEFF(0, 224) },
452 };
453 bool full = tpg->real_quantization == V4L2_QUANTIZATION_FULL_RANGE;
afad4dd5 454 unsigned y_offset = full ? 0 : 16;
481b97a1
HV
455 int lin_r, lin_g, lin_b, lin_y;
456
457 switch (tpg->real_ycbcr_enc) {
458 case V4L2_YCBCR_ENC_601:
459 case V4L2_YCBCR_ENC_XV601:
460 case V4L2_YCBCR_ENC_SYCC:
afad4dd5 461 ycbcr2rgb(full ? bt601_full : bt601, y, cb, cr, y_offset, r, g, b);
481b97a1
HV
462 break;
463 case V4L2_YCBCR_ENC_BT2020:
464 ycbcr2rgb(bt2020, y, cb, cr, 16, r, g, b);
465 break;
466 case V4L2_YCBCR_ENC_BT2020_CONST_LUM:
467 y -= 16 << 4;
468 cb -= 128 << 4;
469 cr -= 128 << 4;
63881df9 470
481b97a1
HV
471 if (cb <= 0)
472 *b = COEFF(1.0, 219) * y + COEFF(1.9404, 224) * cb;
473 else
474 *b = COEFF(1.0, 219) * y + COEFF(1.5816, 224) * cb;
475 *b = *b >> 12;
476 if (cr <= 0)
477 *r = COEFF(1.0, 219) * y + COEFF(1.7184, 224) * cr;
478 else
479 *r = COEFF(1.0, 219) * y + COEFF(0.9936, 224) * cr;
480 *r = *r >> 12;
481 lin_r = rec709_to_linear(*r);
482 lin_b = rec709_to_linear(*b);
483 lin_y = rec709_to_linear((y * 255) / 219);
484
485 lin_g = COEFF(1.0 / 0.6780, 255) * lin_y -
486 COEFF(0.2627 / 0.6780, 255) * lin_r -
487 COEFF(0.0593 / 0.6780, 255) * lin_b;
488 *g = linear_to_rec709(lin_g >> 12);
63881df9 489 break;
481b97a1
HV
490 case V4L2_YCBCR_ENC_SMPTE240M:
491 ycbcr2rgb(smpte240m, y, cb, cr, 16, r, g, b);
63881df9 492 break;
481b97a1
HV
493 case V4L2_YCBCR_ENC_709:
494 case V4L2_YCBCR_ENC_XV709:
63881df9 495 default:
afad4dd5 496 ycbcr2rgb(full ? rec709_full : rec709, y, cb, cr, y_offset, r, g, b);
63881df9
HV
497 break;
498 }
63881df9
HV
499}
500
501/* precalculate color bar values to speed up rendering */
502static void precalculate_color(struct tpg_data *tpg, int k)
503{
504 int col = k;
505 int r = tpg_colors[col].r;
506 int g = tpg_colors[col].g;
507 int b = tpg_colors[col].b;
508
509 if (k == TPG_COLOR_TEXTBG) {
510 col = tpg_get_textbg_color(tpg);
511
512 r = tpg_colors[col].r;
513 g = tpg_colors[col].g;
514 b = tpg_colors[col].b;
515 } else if (k == TPG_COLOR_TEXTFG) {
516 col = tpg_get_textfg_color(tpg);
517
518 r = tpg_colors[col].r;
519 g = tpg_colors[col].g;
520 b = tpg_colors[col].b;
521 } else if (tpg->pattern == TPG_PAT_NOISE) {
522 r = g = b = prandom_u32_max(256);
523 } else if (k == TPG_COLOR_RANDOM) {
524 r = g = b = tpg->qual_offset + prandom_u32_max(196);
525 } else if (k >= TPG_COLOR_RAMP) {
526 r = g = b = k - TPG_COLOR_RAMP;
527 }
528
529 if (tpg->pattern == TPG_PAT_CSC_COLORBAR && col <= TPG_COLOR_CSC_BLACK) {
530 r = tpg_csc_colors[tpg->colorspace][col].r;
531 g = tpg_csc_colors[tpg->colorspace][col].g;
532 b = tpg_csc_colors[tpg->colorspace][col].b;
533 } else {
534 r <<= 4;
535 g <<= 4;
536 b <<= 4;
537 }
481b97a1
HV
538 if (tpg->qual == TPG_QUAL_GRAY) {
539 /* Rec. 709 Luma function */
540 /* (0.2126, 0.7152, 0.0722) * (255 * 256) */
9c35bd48 541 r = g = b = (13879 * r + 46688 * g + 4713 * b) >> 16;
481b97a1 542 }
63881df9
HV
543
544 /*
545 * The assumption is that the RGB output is always full range,
546 * so only if the rgb_range overrides the 'real' rgb range do
547 * we need to convert the RGB values.
548 *
63881df9
HV
549 * Remember that r, g and b are still in the 0 - 0xff0 range.
550 */
551 if (tpg->real_rgb_range == V4L2_DV_RGB_RANGE_LIMITED &&
552 tpg->rgb_range == V4L2_DV_RGB_RANGE_FULL) {
553 /*
554 * Convert from full range (which is what r, g and b are)
555 * to limited range (which is the 'real' RGB range), which
556 * is then interpreted as full range.
557 */
558 r = (r * 219) / 255 + (16 << 4);
559 g = (g * 219) / 255 + (16 << 4);
560 b = (b * 219) / 255 + (16 << 4);
561 } else if (tpg->real_rgb_range != V4L2_DV_RGB_RANGE_LIMITED &&
562 tpg->rgb_range == V4L2_DV_RGB_RANGE_LIMITED) {
563 /*
564 * Clamp r, g and b to the limited range and convert to full
565 * range since that's what we deliver.
566 */
567 r = clamp(r, 16 << 4, 235 << 4);
568 g = clamp(g, 16 << 4, 235 << 4);
569 b = clamp(b, 16 << 4, 235 << 4);
570 r = (r - (16 << 4)) * 255 / 219;
571 g = (g - (16 << 4)) * 255 / 219;
572 b = (b - (16 << 4)) * 255 / 219;
573 }
574
575 if (tpg->brightness != 128 || tpg->contrast != 128 ||
576 tpg->saturation != 128 || tpg->hue) {
577 /* Implement these operations */
481b97a1
HV
578 int y, cb, cr;
579 int tmp_cb, tmp_cr;
63881df9
HV
580
581 /* First convert to YCbCr */
481b97a1
HV
582
583 color_to_ycbcr(tpg, r, g, b, &y, &cb, &cr);
63881df9
HV
584
585 y = (16 << 4) + ((y - (16 << 4)) * tpg->contrast) / 128;
586 y += (tpg->brightness << 4) - (128 << 4);
587
588 cb -= 128 << 4;
589 cr -= 128 << 4;
590 tmp_cb = (cb * cos(128 + tpg->hue)) / 127 + (cr * sin[128 + tpg->hue]) / 127;
591 tmp_cr = (cr * cos(128 + tpg->hue)) / 127 - (cb * sin[128 + tpg->hue]) / 127;
592
593 cb = (128 << 4) + (tmp_cb * tpg->contrast * tpg->saturation) / (128 * 128);
594 cr = (128 << 4) + (tmp_cr * tpg->contrast * tpg->saturation) / (128 * 128);
595 if (tpg->is_yuv) {
596 tpg->colors[k][0] = clamp(y >> 4, 1, 254);
597 tpg->colors[k][1] = clamp(cb >> 4, 1, 254);
598 tpg->colors[k][2] = clamp(cr >> 4, 1, 254);
599 return;
600 }
481b97a1 601 ycbcr_to_color(tpg, y, cb, cr, &r, &g, &b);
63881df9
HV
602 }
603
604 if (tpg->is_yuv) {
605 /* Convert to YCbCr */
481b97a1
HV
606 int y, cb, cr;
607
608 color_to_ycbcr(tpg, r, g, b, &y, &cb, &cr);
63881df9 609
481b97a1
HV
610 if (tpg->real_quantization == V4L2_QUANTIZATION_LIM_RANGE) {
611 y = clamp(y, 16 << 4, 235 << 4);
612 cb = clamp(cb, 16 << 4, 240 << 4);
613 cr = clamp(cr, 16 << 4, 240 << 4);
614 }
63881df9
HV
615 tpg->colors[k][0] = clamp(y >> 4, 1, 254);
616 tpg->colors[k][1] = clamp(cb >> 4, 1, 254);
617 tpg->colors[k][2] = clamp(cr >> 4, 1, 254);
618 } else {
481b97a1
HV
619 if (tpg->real_quantization == V4L2_QUANTIZATION_LIM_RANGE) {
620 r = (r * 219) / 255 + (16 << 4);
621 g = (g * 219) / 255 + (16 << 4);
622 b = (b * 219) / 255 + (16 << 4);
623 }
63881df9
HV
624 switch (tpg->fourcc) {
625 case V4L2_PIX_FMT_RGB565:
626 case V4L2_PIX_FMT_RGB565X:
627 r >>= 7;
628 g >>= 6;
629 b >>= 7;
630 break;
631 case V4L2_PIX_FMT_RGB555:
632 case V4L2_PIX_FMT_XRGB555:
633 case V4L2_PIX_FMT_ARGB555:
634 case V4L2_PIX_FMT_RGB555X:
635 r >>= 7;
636 g >>= 7;
637 b >>= 7;
638 break;
639 default:
640 r >>= 4;
641 g >>= 4;
642 b >>= 4;
643 break;
644 }
645
646 tpg->colors[k][0] = r;
647 tpg->colors[k][1] = g;
648 tpg->colors[k][2] = b;
649 }
650}
651
652static void tpg_precalculate_colors(struct tpg_data *tpg)
653{
654 int k;
655
656 for (k = 0; k < TPG_COLOR_MAX; k++)
657 precalculate_color(tpg, k);
658}
659
660/* 'odd' is true for pixels 1, 3, 5, etc. and false for pixels 0, 2, 4, etc. */
661static void gen_twopix(struct tpg_data *tpg,
662 u8 buf[TPG_MAX_PLANES][8], int color, bool odd)
663{
664 unsigned offset = odd * tpg->twopixelsize[0] / 2;
665 u8 alpha = tpg->alpha_component;
666 u8 r_y, g_u, b_v;
667
668 if (tpg->alpha_red_only && color != TPG_COLOR_CSC_RED &&
669 color != TPG_COLOR_100_RED &&
670 color != TPG_COLOR_75_RED)
671 alpha = 0;
672 if (color == TPG_COLOR_RANDOM)
673 precalculate_color(tpg, color);
674 r_y = tpg->colors[color][0]; /* R or precalculated Y */
675 g_u = tpg->colors[color][1]; /* G or precalculated U */
676 b_v = tpg->colors[color][2]; /* B or precalculated V */
677
678 switch (tpg->fourcc) {
679 case V4L2_PIX_FMT_NV16M:
680 buf[0][offset] = r_y;
681 buf[1][offset] = odd ? b_v : g_u;
682 break;
683 case V4L2_PIX_FMT_NV61M:
684 buf[0][offset] = r_y;
685 buf[1][offset] = odd ? g_u : b_v;
686 break;
687
688 case V4L2_PIX_FMT_YUYV:
689 buf[0][offset] = r_y;
690 buf[0][offset + 1] = odd ? b_v : g_u;
691 break;
692 case V4L2_PIX_FMT_UYVY:
693 buf[0][offset] = odd ? b_v : g_u;
694 buf[0][offset + 1] = r_y;
695 break;
696 case V4L2_PIX_FMT_YVYU:
697 buf[0][offset] = r_y;
698 buf[0][offset + 1] = odd ? g_u : b_v;
699 break;
700 case V4L2_PIX_FMT_VYUY:
701 buf[0][offset] = odd ? g_u : b_v;
702 buf[0][offset + 1] = r_y;
703 break;
704 case V4L2_PIX_FMT_RGB565:
705 buf[0][offset] = (g_u << 5) | b_v;
706 buf[0][offset + 1] = (r_y << 3) | (g_u >> 3);
707 break;
708 case V4L2_PIX_FMT_RGB565X:
709 buf[0][offset] = (r_y << 3) | (g_u >> 3);
710 buf[0][offset + 1] = (g_u << 5) | b_v;
711 break;
712 case V4L2_PIX_FMT_RGB555:
713 case V4L2_PIX_FMT_XRGB555:
714 alpha = 0;
715 /* fall through */
716 case V4L2_PIX_FMT_ARGB555:
717 buf[0][offset] = (g_u << 5) | b_v;
718 buf[0][offset + 1] = (alpha & 0x80) | (r_y << 2) | (g_u >> 3);
719 break;
720 case V4L2_PIX_FMT_RGB555X:
721 buf[0][offset] = (alpha & 0x80) | (r_y << 2) | (g_u >> 3);
722 buf[0][offset + 1] = (g_u << 5) | b_v;
723 break;
724 case V4L2_PIX_FMT_RGB24:
725 buf[0][offset] = r_y;
726 buf[0][offset + 1] = g_u;
727 buf[0][offset + 2] = b_v;
728 break;
729 case V4L2_PIX_FMT_BGR24:
730 buf[0][offset] = b_v;
731 buf[0][offset + 1] = g_u;
732 buf[0][offset + 2] = r_y;
733 break;
734 case V4L2_PIX_FMT_RGB32:
735 case V4L2_PIX_FMT_XRGB32:
736 alpha = 0;
737 /* fall through */
738 case V4L2_PIX_FMT_ARGB32:
739 buf[0][offset] = alpha;
740 buf[0][offset + 1] = r_y;
741 buf[0][offset + 2] = g_u;
742 buf[0][offset + 3] = b_v;
743 break;
744 case V4L2_PIX_FMT_BGR32:
745 case V4L2_PIX_FMT_XBGR32:
746 alpha = 0;
747 /* fall through */
748 case V4L2_PIX_FMT_ABGR32:
749 buf[0][offset] = b_v;
750 buf[0][offset + 1] = g_u;
751 buf[0][offset + 2] = r_y;
752 buf[0][offset + 3] = alpha;
753 break;
754 }
755}
756
757/* Return how many pattern lines are used by the current pattern. */
1a05d313 758static unsigned tpg_get_pat_lines(const struct tpg_data *tpg)
63881df9
HV
759{
760 switch (tpg->pattern) {
761 case TPG_PAT_CHECKERS_16X16:
1a05d313 762 case TPG_PAT_CHECKERS_2X2:
63881df9 763 case TPG_PAT_CHECKERS_1X1:
1a05d313
HV
764 case TPG_PAT_COLOR_CHECKERS_2X2:
765 case TPG_PAT_COLOR_CHECKERS_1X1:
63881df9
HV
766 case TPG_PAT_ALTERNATING_HLINES:
767 case TPG_PAT_CROSS_1_PIXEL:
768 case TPG_PAT_CROSS_2_PIXELS:
769 case TPG_PAT_CROSS_10_PIXELS:
770 return 2;
771 case TPG_PAT_100_COLORSQUARES:
772 case TPG_PAT_100_HCOLORBAR:
773 return 8;
774 default:
775 return 1;
776 }
777}
778
779/* Which pattern line should be used for the given frame line. */
1a05d313 780static unsigned tpg_get_pat_line(const struct tpg_data *tpg, unsigned line)
63881df9
HV
781{
782 switch (tpg->pattern) {
783 case TPG_PAT_CHECKERS_16X16:
784 return (line >> 4) & 1;
785 case TPG_PAT_CHECKERS_1X1:
1a05d313 786 case TPG_PAT_COLOR_CHECKERS_1X1:
63881df9
HV
787 case TPG_PAT_ALTERNATING_HLINES:
788 return line & 1;
1a05d313
HV
789 case TPG_PAT_CHECKERS_2X2:
790 case TPG_PAT_COLOR_CHECKERS_2X2:
791 return (line & 2) >> 1;
63881df9
HV
792 case TPG_PAT_100_COLORSQUARES:
793 case TPG_PAT_100_HCOLORBAR:
794 return (line * 8) / tpg->src_height;
795 case TPG_PAT_CROSS_1_PIXEL:
796 return line == tpg->src_height / 2;
797 case TPG_PAT_CROSS_2_PIXELS:
798 return (line + 1) / 2 == tpg->src_height / 4;
799 case TPG_PAT_CROSS_10_PIXELS:
800 return (line + 10) / 20 == tpg->src_height / 40;
801 default:
802 return 0;
803 }
804}
805
806/*
807 * Which color should be used for the given pattern line and X coordinate.
808 * Note: x is in the range 0 to 2 * tpg->src_width.
809 */
1a05d313
HV
810static enum tpg_color tpg_get_color(const struct tpg_data *tpg,
811 unsigned pat_line, unsigned x)
63881df9
HV
812{
813 /* Maximum number of bars are TPG_COLOR_MAX - otherwise, the input print code
814 should be modified */
815 static const enum tpg_color bars[3][8] = {
816 /* Standard ITU-R 75% color bar sequence */
817 { TPG_COLOR_CSC_WHITE, TPG_COLOR_75_YELLOW,
818 TPG_COLOR_75_CYAN, TPG_COLOR_75_GREEN,
819 TPG_COLOR_75_MAGENTA, TPG_COLOR_75_RED,
820 TPG_COLOR_75_BLUE, TPG_COLOR_100_BLACK, },
821 /* Standard ITU-R 100% color bar sequence */
822 { TPG_COLOR_100_WHITE, TPG_COLOR_100_YELLOW,
823 TPG_COLOR_100_CYAN, TPG_COLOR_100_GREEN,
824 TPG_COLOR_100_MAGENTA, TPG_COLOR_100_RED,
825 TPG_COLOR_100_BLUE, TPG_COLOR_100_BLACK, },
826 /* Color bar sequence suitable to test CSC */
827 { TPG_COLOR_CSC_WHITE, TPG_COLOR_CSC_YELLOW,
828 TPG_COLOR_CSC_CYAN, TPG_COLOR_CSC_GREEN,
829 TPG_COLOR_CSC_MAGENTA, TPG_COLOR_CSC_RED,
830 TPG_COLOR_CSC_BLUE, TPG_COLOR_CSC_BLACK, },
831 };
832
833 switch (tpg->pattern) {
834 case TPG_PAT_75_COLORBAR:
835 case TPG_PAT_100_COLORBAR:
836 case TPG_PAT_CSC_COLORBAR:
837 return bars[tpg->pattern][((x * 8) / tpg->src_width) % 8];
838 case TPG_PAT_100_COLORSQUARES:
839 return bars[1][(pat_line + (x * 8) / tpg->src_width) % 8];
840 case TPG_PAT_100_HCOLORBAR:
841 return bars[1][pat_line];
842 case TPG_PAT_BLACK:
843 return TPG_COLOR_100_BLACK;
844 case TPG_PAT_WHITE:
845 return TPG_COLOR_100_WHITE;
846 case TPG_PAT_RED:
847 return TPG_COLOR_100_RED;
848 case TPG_PAT_GREEN:
849 return TPG_COLOR_100_GREEN;
850 case TPG_PAT_BLUE:
851 return TPG_COLOR_100_BLUE;
852 case TPG_PAT_CHECKERS_16X16:
853 return (((x >> 4) & 1) ^ (pat_line & 1)) ?
854 TPG_COLOR_100_BLACK : TPG_COLOR_100_WHITE;
855 case TPG_PAT_CHECKERS_1X1:
856 return ((x & 1) ^ (pat_line & 1)) ?
857 TPG_COLOR_100_WHITE : TPG_COLOR_100_BLACK;
1a05d313
HV
858 case TPG_PAT_COLOR_CHECKERS_1X1:
859 return ((x & 1) ^ (pat_line & 1)) ?
860 TPG_COLOR_100_RED : TPG_COLOR_100_BLUE;
861 case TPG_PAT_CHECKERS_2X2:
862 return (((x >> 1) & 1) ^ (pat_line & 1)) ?
863 TPG_COLOR_100_WHITE : TPG_COLOR_100_BLACK;
864 case TPG_PAT_COLOR_CHECKERS_2X2:
865 return (((x >> 1) & 1) ^ (pat_line & 1)) ?
866 TPG_COLOR_100_RED : TPG_COLOR_100_BLUE;
63881df9
HV
867 case TPG_PAT_ALTERNATING_HLINES:
868 return pat_line ? TPG_COLOR_100_WHITE : TPG_COLOR_100_BLACK;
869 case TPG_PAT_ALTERNATING_VLINES:
870 return (x & 1) ? TPG_COLOR_100_WHITE : TPG_COLOR_100_BLACK;
871 case TPG_PAT_CROSS_1_PIXEL:
872 if (pat_line || (x % tpg->src_width) == tpg->src_width / 2)
873 return TPG_COLOR_100_BLACK;
874 return TPG_COLOR_100_WHITE;
875 case TPG_PAT_CROSS_2_PIXELS:
876 if (pat_line || ((x % tpg->src_width) + 1) / 2 == tpg->src_width / 4)
877 return TPG_COLOR_100_BLACK;
878 return TPG_COLOR_100_WHITE;
879 case TPG_PAT_CROSS_10_PIXELS:
880 if (pat_line || ((x % tpg->src_width) + 10) / 20 == tpg->src_width / 40)
881 return TPG_COLOR_100_BLACK;
882 return TPG_COLOR_100_WHITE;
883 case TPG_PAT_GRAY_RAMP:
884 return TPG_COLOR_RAMP + ((x % tpg->src_width) * 256) / tpg->src_width;
885 default:
886 return TPG_COLOR_100_RED;
887 }
888}
889
890/*
891 * Given the pixel aspect ratio and video aspect ratio calculate the
892 * coordinates of a centered square and the coordinates of the border of
893 * the active video area. The coordinates are relative to the source
894 * frame rectangle.
895 */
896static void tpg_calculate_square_border(struct tpg_data *tpg)
897{
898 unsigned w = tpg->src_width;
899 unsigned h = tpg->src_height;
900 unsigned sq_w, sq_h;
901
902 sq_w = (w * 2 / 5) & ~1;
903 if (((w - sq_w) / 2) & 1)
904 sq_w += 2;
905 sq_h = sq_w;
906 tpg->square.width = sq_w;
907 if (tpg->vid_aspect == TPG_VIDEO_ASPECT_16X9_ANAMORPHIC) {
908 unsigned ana_sq_w = (sq_w / 4) * 3;
909
910 if (((w - ana_sq_w) / 2) & 1)
911 ana_sq_w += 2;
912 tpg->square.width = ana_sq_w;
913 }
914 tpg->square.left = (w - tpg->square.width) / 2;
915 if (tpg->pix_aspect == TPG_PIXEL_ASPECT_NTSC)
916 sq_h = sq_w * 10 / 11;
917 else if (tpg->pix_aspect == TPG_PIXEL_ASPECT_PAL)
918 sq_h = sq_w * 59 / 54;
919 tpg->square.height = sq_h;
920 tpg->square.top = (h - sq_h) / 2;
921 tpg->border.left = 0;
922 tpg->border.width = w;
923 tpg->border.top = 0;
924 tpg->border.height = h;
925 switch (tpg->vid_aspect) {
926 case TPG_VIDEO_ASPECT_4X3:
927 if (tpg->pix_aspect)
928 return;
929 if (3 * w >= 4 * h) {
930 tpg->border.width = ((4 * h) / 3) & ~1;
931 if (((w - tpg->border.width) / 2) & ~1)
932 tpg->border.width -= 2;
933 tpg->border.left = (w - tpg->border.width) / 2;
934 break;
935 }
936 tpg->border.height = ((3 * w) / 4) & ~1;
937 tpg->border.top = (h - tpg->border.height) / 2;
938 break;
939 case TPG_VIDEO_ASPECT_14X9_CENTRE:
940 if (tpg->pix_aspect) {
941 tpg->border.height = tpg->pix_aspect == TPG_PIXEL_ASPECT_NTSC ? 420 : 506;
942 tpg->border.top = (h - tpg->border.height) / 2;
943 break;
944 }
945 if (9 * w >= 14 * h) {
946 tpg->border.width = ((14 * h) / 9) & ~1;
947 if (((w - tpg->border.width) / 2) & ~1)
948 tpg->border.width -= 2;
949 tpg->border.left = (w - tpg->border.width) / 2;
950 break;
951 }
952 tpg->border.height = ((9 * w) / 14) & ~1;
953 tpg->border.top = (h - tpg->border.height) / 2;
954 break;
955 case TPG_VIDEO_ASPECT_16X9_CENTRE:
956 if (tpg->pix_aspect) {
957 tpg->border.height = tpg->pix_aspect == TPG_PIXEL_ASPECT_NTSC ? 368 : 442;
958 tpg->border.top = (h - tpg->border.height) / 2;
959 break;
960 }
961 if (9 * w >= 16 * h) {
962 tpg->border.width = ((16 * h) / 9) & ~1;
963 if (((w - tpg->border.width) / 2) & ~1)
964 tpg->border.width -= 2;
965 tpg->border.left = (w - tpg->border.width) / 2;
966 break;
967 }
968 tpg->border.height = ((9 * w) / 16) & ~1;
969 tpg->border.top = (h - tpg->border.height) / 2;
970 break;
971 default:
972 break;
973 }
974}
975
976static void tpg_precalculate_line(struct tpg_data *tpg)
977{
978 enum tpg_color contrast;
979 unsigned pat;
980 unsigned p;
981 unsigned x;
982
983 switch (tpg->pattern) {
984 case TPG_PAT_GREEN:
985 contrast = TPG_COLOR_100_RED;
986 break;
987 case TPG_PAT_CSC_COLORBAR:
988 contrast = TPG_COLOR_CSC_GREEN;
989 break;
990 default:
991 contrast = TPG_COLOR_100_GREEN;
992 break;
993 }
994
995 for (pat = 0; pat < tpg_get_pat_lines(tpg); pat++) {
996 /* Coarse scaling with Bresenham */
997 unsigned int_part = tpg->src_width / tpg->scaled_width;
998 unsigned fract_part = tpg->src_width % tpg->scaled_width;
999 unsigned src_x = 0;
1000 unsigned error = 0;
1001
1002 for (x = 0; x < tpg->scaled_width * 2; x += 2) {
1003 unsigned real_x = src_x;
1004 enum tpg_color color1, color2;
1005 u8 pix[TPG_MAX_PLANES][8];
1006
1007 real_x = tpg->hflip ? tpg->src_width * 2 - real_x - 2 : real_x;
1008 color1 = tpg_get_color(tpg, pat, real_x);
1009
1010 src_x += int_part;
1011 error += fract_part;
1012 if (error >= tpg->scaled_width) {
1013 error -= tpg->scaled_width;
1014 src_x++;
1015 }
1016
1017 real_x = src_x;
1018 real_x = tpg->hflip ? tpg->src_width * 2 - real_x - 2 : real_x;
1019 color2 = tpg_get_color(tpg, pat, real_x);
1020
1021 src_x += int_part;
1022 error += fract_part;
1023 if (error >= tpg->scaled_width) {
1024 error -= tpg->scaled_width;
1025 src_x++;
1026 }
1027
1028 gen_twopix(tpg, pix, tpg->hflip ? color2 : color1, 0);
1029 gen_twopix(tpg, pix, tpg->hflip ? color1 : color2, 1);
1030 for (p = 0; p < tpg->planes; p++) {
1031 unsigned twopixsize = tpg->twopixelsize[p];
1032 u8 *pos = tpg->lines[pat][p] + x * twopixsize / 2;
1033
1034 memcpy(pos, pix[p], twopixsize);
1035 }
1036 }
1037 }
1038 for (x = 0; x < tpg->scaled_width; x += 2) {
1039 u8 pix[TPG_MAX_PLANES][8];
1040
1041 gen_twopix(tpg, pix, contrast, 0);
1042 gen_twopix(tpg, pix, contrast, 1);
1043 for (p = 0; p < tpg->planes; p++) {
1044 unsigned twopixsize = tpg->twopixelsize[p];
1045 u8 *pos = tpg->contrast_line[p] + x * twopixsize / 2;
1046
1047 memcpy(pos, pix[p], twopixsize);
1048 }
1049 }
1050 for (x = 0; x < tpg->scaled_width; x += 2) {
1051 u8 pix[TPG_MAX_PLANES][8];
1052
1053 gen_twopix(tpg, pix, TPG_COLOR_100_BLACK, 0);
1054 gen_twopix(tpg, pix, TPG_COLOR_100_BLACK, 1);
1055 for (p = 0; p < tpg->planes; p++) {
1056 unsigned twopixsize = tpg->twopixelsize[p];
1057 u8 *pos = tpg->black_line[p] + x * twopixsize / 2;
1058
1059 memcpy(pos, pix[p], twopixsize);
1060 }
1061 }
1062 for (x = 0; x < tpg->scaled_width * 2; x += 2) {
1063 u8 pix[TPG_MAX_PLANES][8];
1064
1065 gen_twopix(tpg, pix, TPG_COLOR_RANDOM, 0);
1066 gen_twopix(tpg, pix, TPG_COLOR_RANDOM, 1);
1067 for (p = 0; p < tpg->planes; p++) {
1068 unsigned twopixsize = tpg->twopixelsize[p];
1069 u8 *pos = tpg->random_line[p] + x * twopixsize / 2;
1070
1071 memcpy(pos, pix[p], twopixsize);
1072 }
1073 }
1074 gen_twopix(tpg, tpg->textbg, TPG_COLOR_TEXTBG, 0);
1075 gen_twopix(tpg, tpg->textbg, TPG_COLOR_TEXTBG, 1);
1076 gen_twopix(tpg, tpg->textfg, TPG_COLOR_TEXTFG, 0);
1077 gen_twopix(tpg, tpg->textfg, TPG_COLOR_TEXTFG, 1);
1078}
1079
1080/* need this to do rgb24 rendering */
1081typedef struct { u16 __; u8 _; } __packed x24;
1082
1083void tpg_gen_text(struct tpg_data *tpg, u8 *basep[TPG_MAX_PLANES][2],
1084 int y, int x, char *text)
1085{
1086 int line;
1087 unsigned step = V4L2_FIELD_HAS_T_OR_B(tpg->field) ? 2 : 1;
1088 unsigned div = step;
1089 unsigned first = 0;
1090 unsigned len = strlen(text);
1091 unsigned p;
1092
1093 if (font8x16 == NULL || basep == NULL)
1094 return;
1095
1096 /* Checks if it is possible to show string */
1097 if (y + 16 >= tpg->compose.height || x + 8 >= tpg->compose.width)
1098 return;
1099
1100 if (len > (tpg->compose.width - x) / 8)
1101 len = (tpg->compose.width - x) / 8;
1102 if (tpg->vflip)
1103 y = tpg->compose.height - y - 16;
1104 if (tpg->hflip)
1105 x = tpg->compose.width - x - 8;
1106 y += tpg->compose.top;
1107 x += tpg->compose.left;
1108 if (tpg->field == V4L2_FIELD_BOTTOM)
1109 first = 1;
1110 else if (tpg->field == V4L2_FIELD_SEQ_TB || tpg->field == V4L2_FIELD_SEQ_BT)
1111 div = 2;
1112
1113 for (p = 0; p < tpg->planes; p++) {
1114 /* Print stream time */
1115#define PRINTSTR(PIXTYPE) do { \
1116 PIXTYPE fg; \
1117 PIXTYPE bg; \
1118 memcpy(&fg, tpg->textfg[p], sizeof(PIXTYPE)); \
1119 memcpy(&bg, tpg->textbg[p], sizeof(PIXTYPE)); \
1120 \
1121 for (line = first; line < 16; line += step) { \
1122 int l = tpg->vflip ? 15 - line : line; \
1123 PIXTYPE *pos = (PIXTYPE *)(basep[p][line & 1] + \
1124 ((y * step + l) / div) * tpg->bytesperline[p] + \
1125 x * sizeof(PIXTYPE)); \
1126 unsigned s; \
1127 \
1128 for (s = 0; s < len; s++) { \
1129 u8 chr = font8x16[text[s] * 16 + line]; \
1130 \
1131 if (tpg->hflip) { \
1132 pos[7] = (chr & (0x01 << 7) ? fg : bg); \
1133 pos[6] = (chr & (0x01 << 6) ? fg : bg); \
1134 pos[5] = (chr & (0x01 << 5) ? fg : bg); \
1135 pos[4] = (chr & (0x01 << 4) ? fg : bg); \
1136 pos[3] = (chr & (0x01 << 3) ? fg : bg); \
1137 pos[2] = (chr & (0x01 << 2) ? fg : bg); \
1138 pos[1] = (chr & (0x01 << 1) ? fg : bg); \
1139 pos[0] = (chr & (0x01 << 0) ? fg : bg); \
1140 } else { \
1141 pos[0] = (chr & (0x01 << 7) ? fg : bg); \
1142 pos[1] = (chr & (0x01 << 6) ? fg : bg); \
1143 pos[2] = (chr & (0x01 << 5) ? fg : bg); \
1144 pos[3] = (chr & (0x01 << 4) ? fg : bg); \
1145 pos[4] = (chr & (0x01 << 3) ? fg : bg); \
1146 pos[5] = (chr & (0x01 << 2) ? fg : bg); \
1147 pos[6] = (chr & (0x01 << 1) ? fg : bg); \
1148 pos[7] = (chr & (0x01 << 0) ? fg : bg); \
1149 } \
1150 \
1151 pos += tpg->hflip ? -8 : 8; \
1152 } \
1153 } \
1154} while (0)
1155
1156 switch (tpg->twopixelsize[p]) {
1157 case 2:
1158 PRINTSTR(u8); break;
1159 case 4:
1160 PRINTSTR(u16); break;
1161 case 6:
1162 PRINTSTR(x24); break;
1163 case 8:
1164 PRINTSTR(u32); break;
1165 }
1166 }
1167}
1168
1169void tpg_update_mv_step(struct tpg_data *tpg)
1170{
1171 int factor = tpg->mv_hor_mode > TPG_MOVE_NONE ? -1 : 1;
1172
1173 if (tpg->hflip)
1174 factor = -factor;
1175 switch (tpg->mv_hor_mode) {
1176 case TPG_MOVE_NEG_FAST:
1177 case TPG_MOVE_POS_FAST:
1178 tpg->mv_hor_step = ((tpg->src_width + 319) / 320) * 4;
1179 break;
1180 case TPG_MOVE_NEG:
1181 case TPG_MOVE_POS:
1182 tpg->mv_hor_step = ((tpg->src_width + 639) / 640) * 4;
1183 break;
1184 case TPG_MOVE_NEG_SLOW:
1185 case TPG_MOVE_POS_SLOW:
1186 tpg->mv_hor_step = 2;
1187 break;
1188 case TPG_MOVE_NONE:
1189 tpg->mv_hor_step = 0;
1190 break;
1191 }
1192 if (factor < 0)
1193 tpg->mv_hor_step = tpg->src_width - tpg->mv_hor_step;
1194
1195 factor = tpg->mv_vert_mode > TPG_MOVE_NONE ? -1 : 1;
1196 switch (tpg->mv_vert_mode) {
1197 case TPG_MOVE_NEG_FAST:
1198 case TPG_MOVE_POS_FAST:
1199 tpg->mv_vert_step = ((tpg->src_width + 319) / 320) * 4;
1200 break;
1201 case TPG_MOVE_NEG:
1202 case TPG_MOVE_POS:
1203 tpg->mv_vert_step = ((tpg->src_width + 639) / 640) * 4;
1204 break;
1205 case TPG_MOVE_NEG_SLOW:
1206 case TPG_MOVE_POS_SLOW:
1207 tpg->mv_vert_step = 1;
1208 break;
1209 case TPG_MOVE_NONE:
1210 tpg->mv_vert_step = 0;
1211 break;
1212 }
1213 if (factor < 0)
1214 tpg->mv_vert_step = tpg->src_height - tpg->mv_vert_step;
1215}
1216
1217/* Map the line number relative to the crop rectangle to a frame line number */
1218static unsigned tpg_calc_frameline(struct tpg_data *tpg, unsigned src_y,
1219 unsigned field)
1220{
1221 switch (field) {
1222 case V4L2_FIELD_TOP:
1223 return tpg->crop.top + src_y * 2;
1224 case V4L2_FIELD_BOTTOM:
1225 return tpg->crop.top + src_y * 2 + 1;
1226 default:
1227 return src_y + tpg->crop.top;
1228 }
1229}
1230
1231/*
1232 * Map the line number relative to the compose rectangle to a destination
1233 * buffer line number.
1234 */
1235static unsigned tpg_calc_buffer_line(struct tpg_data *tpg, unsigned y,
1236 unsigned field)
1237{
1238 y += tpg->compose.top;
1239 switch (field) {
1240 case V4L2_FIELD_SEQ_TB:
1241 if (y & 1)
1242 return tpg->buf_height / 2 + y / 2;
1243 return y / 2;
1244 case V4L2_FIELD_SEQ_BT:
1245 if (y & 1)
1246 return y / 2;
1247 return tpg->buf_height / 2 + y / 2;
1248 default:
1249 return y;
1250 }
1251}
1252
1253static void tpg_recalc(struct tpg_data *tpg)
1254{
1255 if (tpg->recalc_colors) {
1256 tpg->recalc_colors = false;
1257 tpg->recalc_lines = true;
481b97a1
HV
1258 tpg->real_ycbcr_enc = tpg->ycbcr_enc;
1259 tpg->real_quantization = tpg->quantization;
1260 if (tpg->ycbcr_enc == V4L2_YCBCR_ENC_DEFAULT) {
1261 switch (tpg->colorspace) {
1262 case V4L2_COLORSPACE_REC709:
1263 tpg->real_ycbcr_enc = V4L2_YCBCR_ENC_709;
1264 break;
1265 case V4L2_COLORSPACE_SRGB:
1266 tpg->real_ycbcr_enc = V4L2_YCBCR_ENC_SYCC;
1267 break;
1268 case V4L2_COLORSPACE_BT2020:
1269 tpg->real_ycbcr_enc = V4L2_YCBCR_ENC_BT2020;
1270 break;
1271 case V4L2_COLORSPACE_SMPTE240M:
1272 tpg->real_ycbcr_enc = V4L2_YCBCR_ENC_SMPTE240M;
1273 break;
1274 case V4L2_COLORSPACE_SMPTE170M:
1275 case V4L2_COLORSPACE_470_SYSTEM_M:
1276 case V4L2_COLORSPACE_470_SYSTEM_BG:
1277 case V4L2_COLORSPACE_ADOBERGB:
1278 default:
1279 tpg->real_ycbcr_enc = V4L2_YCBCR_ENC_601;
1280 break;
1281 }
1282 }
1283 if (tpg->quantization == V4L2_QUANTIZATION_DEFAULT) {
1284 tpg->real_quantization = V4L2_QUANTIZATION_FULL_RANGE;
1285 if (tpg->is_yuv) {
1286 switch (tpg->real_ycbcr_enc) {
1287 case V4L2_YCBCR_ENC_SYCC:
1288 case V4L2_YCBCR_ENC_XV601:
1289 case V4L2_YCBCR_ENC_XV709:
1290 break;
1291 default:
1292 tpg->real_quantization =
1293 V4L2_QUANTIZATION_LIM_RANGE;
1294 break;
1295 }
c0b50d95
HV
1296 } else if (tpg->colorspace == V4L2_COLORSPACE_BT2020) {
1297 /* R'G'B' BT.2020 is limited range */
1298 tpg->real_quantization =
1299 V4L2_QUANTIZATION_LIM_RANGE;
481b97a1
HV
1300 }
1301 }
63881df9
HV
1302 tpg_precalculate_colors(tpg);
1303 }
1304 if (tpg->recalc_square_border) {
1305 tpg->recalc_square_border = false;
1306 tpg_calculate_square_border(tpg);
1307 }
1308 if (tpg->recalc_lines) {
1309 tpg->recalc_lines = false;
1310 tpg_precalculate_line(tpg);
1311 }
1312}
1313
1314void tpg_calc_text_basep(struct tpg_data *tpg,
1315 u8 *basep[TPG_MAX_PLANES][2], unsigned p, u8 *vbuf)
1316{
1317 unsigned stride = tpg->bytesperline[p];
1318
1319 tpg_recalc(tpg);
1320
1321 basep[p][0] = vbuf;
1322 basep[p][1] = vbuf;
1323 if (tpg->field == V4L2_FIELD_SEQ_TB)
1324 basep[p][1] += tpg->buf_height * stride / 2;
1325 else if (tpg->field == V4L2_FIELD_SEQ_BT)
1326 basep[p][0] += tpg->buf_height * stride / 2;
1327}
1328
4db22041 1329void tpg_fill_plane_buffer(struct tpg_data *tpg, v4l2_std_id std, unsigned p, u8 *vbuf)
63881df9
HV
1330{
1331 bool is_tv = std;
1332 bool is_60hz = is_tv && (std & V4L2_STD_525_60);
1333 unsigned mv_hor_old = tpg->mv_hor_count % tpg->src_width;
1334 unsigned mv_hor_new = (tpg->mv_hor_count + tpg->mv_hor_step) % tpg->src_width;
1335 unsigned mv_vert_old = tpg->mv_vert_count % tpg->src_height;
1336 unsigned mv_vert_new = (tpg->mv_vert_count + tpg->mv_vert_step) % tpg->src_height;
1337 unsigned wss_width;
1338 unsigned f;
1339 int hmax = (tpg->compose.height * tpg->perc_fill) / 100;
1340 int h;
1341 unsigned twopixsize = tpg->twopixelsize[p];
1342 unsigned img_width = tpg->compose.width * twopixsize / 2;
1343 unsigned line_offset;
1344 unsigned left_pillar_width = 0;
1345 unsigned right_pillar_start = img_width;
1346 unsigned stride = tpg->bytesperline[p];
1347 unsigned factor = V4L2_FIELD_HAS_T_OR_B(tpg->field) ? 2 : 1;
1348 u8 *orig_vbuf = vbuf;
1349
1350 /* Coarse scaling with Bresenham */
1351 unsigned int_part = (tpg->crop.height / factor) / tpg->compose.height;
1352 unsigned fract_part = (tpg->crop.height / factor) % tpg->compose.height;
1353 unsigned src_y = 0;
1354 unsigned error = 0;
1355
1356 tpg_recalc(tpg);
1357
1358 mv_hor_old = (mv_hor_old * tpg->scaled_width / tpg->src_width) & ~1;
1359 mv_hor_new = (mv_hor_new * tpg->scaled_width / tpg->src_width) & ~1;
1360 wss_width = tpg->crop.left < tpg->src_width / 2 ?
1361 tpg->src_width / 2 - tpg->crop.left : 0;
1362 if (wss_width > tpg->crop.width)
1363 wss_width = tpg->crop.width;
1364 wss_width = wss_width * tpg->scaled_width / tpg->src_width;
1365
1366 vbuf += tpg->compose.left * twopixsize / 2;
1367 line_offset = tpg->crop.left * tpg->scaled_width / tpg->src_width;
1368 line_offset = (line_offset & ~1) * twopixsize / 2;
1369 if (tpg->crop.left < tpg->border.left) {
1370 left_pillar_width = tpg->border.left - tpg->crop.left;
1371 if (left_pillar_width > tpg->crop.width)
1372 left_pillar_width = tpg->crop.width;
1373 left_pillar_width = (left_pillar_width * tpg->scaled_width) / tpg->src_width;
1374 left_pillar_width = (left_pillar_width & ~1) * twopixsize / 2;
1375 }
1376 if (tpg->crop.left + tpg->crop.width > tpg->border.left + tpg->border.width) {
1377 right_pillar_start = tpg->border.left + tpg->border.width - tpg->crop.left;
1378 right_pillar_start = (right_pillar_start * tpg->scaled_width) / tpg->src_width;
1379 right_pillar_start = (right_pillar_start & ~1) * twopixsize / 2;
1380 if (right_pillar_start > img_width)
1381 right_pillar_start = img_width;
1382 }
1383
1384 f = tpg->field == (is_60hz ? V4L2_FIELD_TOP : V4L2_FIELD_BOTTOM);
1385
1386 for (h = 0; h < tpg->compose.height; h++) {
1387 bool even;
1388 bool fill_blank = false;
1389 unsigned frame_line;
1390 unsigned buf_line;
1391 unsigned pat_line_old;
1392 unsigned pat_line_new;
1393 u8 *linestart_older;
1394 u8 *linestart_newer;
1395 u8 *linestart_top;
1396 u8 *linestart_bottom;
1397
1398 frame_line = tpg_calc_frameline(tpg, src_y, tpg->field);
1399 even = !(frame_line & 1);
1400 buf_line = tpg_calc_buffer_line(tpg, h, tpg->field);
1401 src_y += int_part;
1402 error += fract_part;
1403 if (error >= tpg->compose.height) {
1404 error -= tpg->compose.height;
1405 src_y++;
1406 }
1407
1408 if (h >= hmax) {
1409 if (hmax == tpg->compose.height)
1410 continue;
1411 if (!tpg->perc_fill_blank)
1412 continue;
1413 fill_blank = true;
1414 }
1415
1416 if (tpg->vflip)
1417 frame_line = tpg->src_height - frame_line - 1;
1418
1419 if (fill_blank) {
1420 linestart_older = tpg->contrast_line[p];
1421 linestart_newer = tpg->contrast_line[p];
1422 } else if (tpg->qual != TPG_QUAL_NOISE &&
1423 (frame_line < tpg->border.top ||
1424 frame_line >= tpg->border.top + tpg->border.height)) {
1425 linestart_older = tpg->black_line[p];
1426 linestart_newer = tpg->black_line[p];
1427 } else if (tpg->pattern == TPG_PAT_NOISE || tpg->qual == TPG_QUAL_NOISE) {
1428 linestart_older = tpg->random_line[p] +
1429 twopixsize * prandom_u32_max(tpg->src_width / 2);
1430 linestart_newer = tpg->random_line[p] +
1431 twopixsize * prandom_u32_max(tpg->src_width / 2);
1432 } else {
1433 pat_line_old = tpg_get_pat_line(tpg,
1434 (frame_line + mv_vert_old) % tpg->src_height);
1435 pat_line_new = tpg_get_pat_line(tpg,
1436 (frame_line + mv_vert_new) % tpg->src_height);
1437 linestart_older = tpg->lines[pat_line_old][p] +
1438 mv_hor_old * twopixsize / 2;
1439 linestart_newer = tpg->lines[pat_line_new][p] +
1440 mv_hor_new * twopixsize / 2;
1441 linestart_older += line_offset;
1442 linestart_newer += line_offset;
1443 }
43047f6b
HV
1444 if (tpg->field_alternate) {
1445 linestart_top = linestart_bottom = linestart_older;
1446 } else if (is_60hz) {
63881df9
HV
1447 linestart_top = linestart_newer;
1448 linestart_bottom = linestart_older;
1449 } else {
1450 linestart_top = linestart_older;
1451 linestart_bottom = linestart_newer;
1452 }
1453
1454 switch (tpg->field) {
1455 case V4L2_FIELD_INTERLACED:
1456 case V4L2_FIELD_INTERLACED_TB:
1457 case V4L2_FIELD_SEQ_TB:
1458 case V4L2_FIELD_SEQ_BT:
1459 if (even)
1460 memcpy(vbuf + buf_line * stride, linestart_top, img_width);
1461 else
1462 memcpy(vbuf + buf_line * stride, linestart_bottom, img_width);
1463 break;
1464 case V4L2_FIELD_INTERLACED_BT:
1465 if (even)
1466 memcpy(vbuf + buf_line * stride, linestart_bottom, img_width);
1467 else
1468 memcpy(vbuf + buf_line * stride, linestart_top, img_width);
1469 break;
1470 case V4L2_FIELD_TOP:
1471 memcpy(vbuf + buf_line * stride, linestart_top, img_width);
1472 break;
1473 case V4L2_FIELD_BOTTOM:
1474 memcpy(vbuf + buf_line * stride, linestart_bottom, img_width);
1475 break;
1476 case V4L2_FIELD_NONE:
1477 default:
1478 memcpy(vbuf + buf_line * stride, linestart_older, img_width);
1479 break;
1480 }
1481
1482 if (is_tv && !is_60hz && frame_line == 0 && wss_width) {
1483 /*
1484 * Replace the first half of the top line of a 50 Hz frame
1485 * with random data to simulate a WSS signal.
1486 */
1487 u8 *wss = tpg->random_line[p] +
1488 twopixsize * prandom_u32_max(tpg->src_width / 2);
1489
1490 memcpy(vbuf + buf_line * stride, wss, wss_width * twopixsize / 2);
1491 }
1492 }
1493
1494 vbuf = orig_vbuf;
1495 vbuf += tpg->compose.left * twopixsize / 2;
1496 src_y = 0;
1497 error = 0;
1498 for (h = 0; h < tpg->compose.height; h++) {
1499 unsigned frame_line = tpg_calc_frameline(tpg, src_y, tpg->field);
1500 unsigned buf_line = tpg_calc_buffer_line(tpg, h, tpg->field);
1501 const struct v4l2_rect *sq = &tpg->square;
1502 const struct v4l2_rect *b = &tpg->border;
1503 const struct v4l2_rect *c = &tpg->crop;
1504
1505 src_y += int_part;
1506 error += fract_part;
1507 if (error >= tpg->compose.height) {
1508 error -= tpg->compose.height;
1509 src_y++;
1510 }
1511
1512 if (tpg->show_border && frame_line >= b->top &&
1513 frame_line < b->top + b->height) {
1514 unsigned bottom = b->top + b->height - 1;
1515 unsigned left = left_pillar_width;
1516 unsigned right = right_pillar_start;
1517
1518 if (frame_line == b->top || frame_line == b->top + 1 ||
1519 frame_line == bottom || frame_line == bottom - 1) {
1520 memcpy(vbuf + buf_line * stride + left, tpg->contrast_line[p],
1521 right - left);
1522 } else {
1523 if (b->left >= c->left &&
1524 b->left < c->left + c->width)
1525 memcpy(vbuf + buf_line * stride + left,
1526 tpg->contrast_line[p], twopixsize);
1527 if (b->left + b->width > c->left &&
1528 b->left + b->width <= c->left + c->width)
1529 memcpy(vbuf + buf_line * stride + right - twopixsize,
1530 tpg->contrast_line[p], twopixsize);
1531 }
1532 }
1533 if (tpg->qual != TPG_QUAL_NOISE && frame_line >= b->top &&
1534 frame_line < b->top + b->height) {
1535 memcpy(vbuf + buf_line * stride, tpg->black_line[p], left_pillar_width);
1536 memcpy(vbuf + buf_line * stride + right_pillar_start, tpg->black_line[p],
1537 img_width - right_pillar_start);
1538 }
1539 if (tpg->show_square && frame_line >= sq->top &&
1540 frame_line < sq->top + sq->height &&
1541 sq->left < c->left + c->width &&
1542 sq->left + sq->width >= c->left) {
1543 unsigned left = sq->left;
1544 unsigned width = sq->width;
1545
1546 if (c->left > left) {
1547 width -= c->left - left;
1548 left = c->left;
1549 }
1550 if (c->left + c->width < left + width)
1551 width -= left + width - c->left - c->width;
1552 left -= c->left;
1553 left = (left * tpg->scaled_width) / tpg->src_width;
1554 left = (left & ~1) * twopixsize / 2;
1555 width = (width * tpg->scaled_width) / tpg->src_width;
1556 width = (width & ~1) * twopixsize / 2;
1557 memcpy(vbuf + buf_line * stride + left, tpg->contrast_line[p], width);
1558 }
1559 if (tpg->insert_sav) {
1560 unsigned offset = (tpg->compose.width / 6) * twopixsize;
1561 u8 *p = vbuf + buf_line * stride + offset;
1562 unsigned vact = 0, hact = 0;
1563
1564 p[0] = 0xff;
1565 p[1] = 0;
1566 p[2] = 0;
1567 p[3] = 0x80 | (f << 6) | (vact << 5) | (hact << 4) |
1568 ((hact ^ vact) << 3) |
1569 ((hact ^ f) << 2) |
1570 ((f ^ vact) << 1) |
1571 (hact ^ vact ^ f);
1572 }
1573 if (tpg->insert_eav) {
1574 unsigned offset = (tpg->compose.width / 6) * 2 * twopixsize;
1575 u8 *p = vbuf + buf_line * stride + offset;
1576 unsigned vact = 0, hact = 1;
1577
1578 p[0] = 0xff;
1579 p[1] = 0;
1580 p[2] = 0;
1581 p[3] = 0x80 | (f << 6) | (vact << 5) | (hact << 4) |
1582 ((hact ^ vact) << 3) |
1583 ((hact ^ f) << 2) |
1584 ((f ^ vact) << 1) |
1585 (hact ^ vact ^ f);
1586 }
1587 }
1588}
4db22041
HV
1589
1590void tpg_fillbuffer(struct tpg_data *tpg, v4l2_std_id std, unsigned p, u8 *vbuf)
1591{
1592 unsigned offset = 0;
1593 unsigned i;
1594
1595 if (tpg->buffers > 1) {
1596 tpg_fill_plane_buffer(tpg, std, p, vbuf);
1597 return;
1598 }
1599
1600 for (i = 0; i < tpg->planes; i++) {
1601 tpg_fill_plane_buffer(tpg, std, i, vbuf + offset);
1602 offset += tpg_calc_plane_size(tpg, i);
1603 }
1604}
This page took 0.119226 seconds and 5 git commands to generate.