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