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