sh_eth: fix EESIPR values for SH77{34|63}
[linux/fpc-iii.git] / drivers / media / common / v4l2-tpg / v4l2-tpg-core.c
blobe47b46e2d26ca7dd4a86f387422a19d8484701cf
1 /*
2 * v4l2-tpg-core.c - Test Pattern Generator
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.
7 * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
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.
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.
23 #include <linux/module.h>
24 #include <media/v4l2-tpg.h>
26 /* Must remain in sync with enum tpg_pattern */
27 const char * const tpg_pattern_strings[] = {
28 "75% Colorbar",
29 "100% Colorbar",
30 "CSC Colorbar",
31 "Horizontal 100% Colorbar",
32 "100% Color Squares",
33 "100% Black",
34 "100% White",
35 "100% Red",
36 "100% Green",
37 "100% Blue",
38 "16x16 Checkers",
39 "2x2 Checkers",
40 "1x1 Checkers",
41 "2x2 Red/Green Checkers",
42 "1x1 Red/Green Checkers",
43 "Alternating Hor Lines",
44 "Alternating Vert Lines",
45 "One Pixel Wide Cross",
46 "Two Pixels Wide Cross",
47 "Ten Pixels Wide Cross",
48 "Gray Ramp",
49 "Noise",
50 NULL
52 EXPORT_SYMBOL_GPL(tpg_pattern_strings);
54 /* Must remain in sync with enum tpg_aspect */
55 const char * const tpg_aspect_strings[] = {
56 "Source Width x Height",
57 "4x3",
58 "14x9",
59 "16x9",
60 "16x9 Anamorphic",
61 NULL
63 EXPORT_SYMBOL_GPL(tpg_aspect_strings);
66 * Sine table: sin[0] = 127 * sin(-180 degrees)
67 * sin[128] = 127 * sin(0 degrees)
68 * sin[256] = 127 * sin(180 degrees)
70 static const s8 sin[257] = {
71 0, -4, -7, -11, -13, -18, -20, -22, -26, -29, -33, -35, -37, -41, -43, -48,
72 -50, -52, -56, -58, -62, -63, -65, -69, -71, -75, -76, -78, -82, -83, -87, -88,
73 -90, -93, -94, -97, -99, -101, -103, -104, -107, -108, -110, -111, -112, -114, -115, -117,
74 -118, -119, -120, -121, -122, -123, -123, -124, -125, -125, -126, -126, -127, -127, -127, -127,
75 -127, -127, -127, -127, -126, -126, -125, -125, -124, -124, -123, -122, -121, -120, -119, -118,
76 -117, -116, -114, -113, -111, -110, -109, -107, -105, -103, -101, -100, -97, -96, -93, -91,
77 -90, -87, -85, -82, -80, -76, -75, -73, -69, -67, -63, -62, -60, -56, -54, -50,
78 -48, -46, -41, -39, -35, -33, -31, -26, -24, -20, -18, -15, -11, -9, -4, -2,
79 0, 2, 4, 9, 11, 15, 18, 20, 24, 26, 31, 33, 35, 39, 41, 46,
80 48, 50, 54, 56, 60, 62, 64, 67, 69, 73, 75, 76, 80, 82, 85, 87,
81 90, 91, 93, 96, 97, 100, 101, 103, 105, 107, 109, 110, 111, 113, 114, 116,
82 117, 118, 119, 120, 121, 122, 123, 124, 124, 125, 125, 126, 126, 127, 127, 127,
83 127, 127, 127, 127, 127, 126, 126, 125, 125, 124, 123, 123, 122, 121, 120, 119,
84 118, 117, 115, 114, 112, 111, 110, 108, 107, 104, 103, 101, 99, 97, 94, 93,
85 90, 88, 87, 83, 82, 78, 76, 75, 71, 69, 65, 64, 62, 58, 56, 52,
86 50, 48, 43, 41, 37, 35, 33, 29, 26, 22, 20, 18, 13, 11, 7, 4,
90 #define cos(idx) sin[((idx) + 64) % sizeof(sin)]
92 /* Global font descriptor */
93 static const u8 *font8x16;
95 void tpg_set_font(const u8 *f)
97 font8x16 = f;
99 EXPORT_SYMBOL_GPL(tpg_set_font);
101 void tpg_init(struct tpg_data *tpg, unsigned w, unsigned h)
103 memset(tpg, 0, sizeof(*tpg));
104 tpg->scaled_width = tpg->src_width = w;
105 tpg->src_height = tpg->buf_height = h;
106 tpg->crop.width = tpg->compose.width = w;
107 tpg->crop.height = tpg->compose.height = h;
108 tpg->recalc_colors = true;
109 tpg->recalc_square_border = true;
110 tpg->brightness = 128;
111 tpg->contrast = 128;
112 tpg->saturation = 128;
113 tpg->hue = 0;
114 tpg->mv_hor_mode = TPG_MOVE_NONE;
115 tpg->mv_vert_mode = TPG_MOVE_NONE;
116 tpg->field = V4L2_FIELD_NONE;
117 tpg_s_fourcc(tpg, V4L2_PIX_FMT_RGB24);
118 tpg->colorspace = V4L2_COLORSPACE_SRGB;
119 tpg->perc_fill = 100;
120 tpg->hsv_enc = V4L2_HSV_ENC_180;
122 EXPORT_SYMBOL_GPL(tpg_init);
124 int tpg_alloc(struct tpg_data *tpg, unsigned max_w)
126 unsigned pat;
127 unsigned plane;
129 tpg->max_line_width = max_w;
130 for (pat = 0; pat < TPG_MAX_PAT_LINES; pat++) {
131 for (plane = 0; plane < TPG_MAX_PLANES; plane++) {
132 unsigned pixelsz = plane ? 2 : 4;
134 tpg->lines[pat][plane] = vzalloc(max_w * 2 * pixelsz);
135 if (!tpg->lines[pat][plane])
136 return -ENOMEM;
137 if (plane == 0)
138 continue;
139 tpg->downsampled_lines[pat][plane] = vzalloc(max_w * 2 * pixelsz);
140 if (!tpg->downsampled_lines[pat][plane])
141 return -ENOMEM;
144 for (plane = 0; plane < TPG_MAX_PLANES; plane++) {
145 unsigned pixelsz = plane ? 2 : 4;
147 tpg->contrast_line[plane] = vzalloc(max_w * pixelsz);
148 if (!tpg->contrast_line[plane])
149 return -ENOMEM;
150 tpg->black_line[plane] = vzalloc(max_w * pixelsz);
151 if (!tpg->black_line[plane])
152 return -ENOMEM;
153 tpg->random_line[plane] = vzalloc(max_w * 2 * pixelsz);
154 if (!tpg->random_line[plane])
155 return -ENOMEM;
157 return 0;
159 EXPORT_SYMBOL_GPL(tpg_alloc);
161 void tpg_free(struct tpg_data *tpg)
163 unsigned pat;
164 unsigned plane;
166 for (pat = 0; pat < TPG_MAX_PAT_LINES; pat++)
167 for (plane = 0; plane < TPG_MAX_PLANES; plane++) {
168 vfree(tpg->lines[pat][plane]);
169 tpg->lines[pat][plane] = NULL;
170 if (plane == 0)
171 continue;
172 vfree(tpg->downsampled_lines[pat][plane]);
173 tpg->downsampled_lines[pat][plane] = NULL;
175 for (plane = 0; plane < TPG_MAX_PLANES; plane++) {
176 vfree(tpg->contrast_line[plane]);
177 vfree(tpg->black_line[plane]);
178 vfree(tpg->random_line[plane]);
179 tpg->contrast_line[plane] = NULL;
180 tpg->black_line[plane] = NULL;
181 tpg->random_line[plane] = NULL;
184 EXPORT_SYMBOL_GPL(tpg_free);
186 bool tpg_s_fourcc(struct tpg_data *tpg, u32 fourcc)
188 tpg->fourcc = fourcc;
189 tpg->planes = 1;
190 tpg->buffers = 1;
191 tpg->recalc_colors = true;
192 tpg->interleaved = false;
193 tpg->vdownsampling[0] = 1;
194 tpg->hdownsampling[0] = 1;
195 tpg->hmask[0] = ~0;
196 tpg->hmask[1] = ~0;
197 tpg->hmask[2] = ~0;
199 switch (fourcc) {
200 case V4L2_PIX_FMT_SBGGR8:
201 case V4L2_PIX_FMT_SGBRG8:
202 case V4L2_PIX_FMT_SGRBG8:
203 case V4L2_PIX_FMT_SRGGB8:
204 case V4L2_PIX_FMT_SBGGR10:
205 case V4L2_PIX_FMT_SGBRG10:
206 case V4L2_PIX_FMT_SGRBG10:
207 case V4L2_PIX_FMT_SRGGB10:
208 case V4L2_PIX_FMT_SBGGR12:
209 case V4L2_PIX_FMT_SGBRG12:
210 case V4L2_PIX_FMT_SGRBG12:
211 case V4L2_PIX_FMT_SRGGB12:
212 tpg->interleaved = true;
213 tpg->vdownsampling[1] = 1;
214 tpg->hdownsampling[1] = 1;
215 tpg->planes = 2;
216 /* fall through */
217 case V4L2_PIX_FMT_RGB332:
218 case V4L2_PIX_FMT_RGB565:
219 case V4L2_PIX_FMT_RGB565X:
220 case V4L2_PIX_FMT_RGB444:
221 case V4L2_PIX_FMT_XRGB444:
222 case V4L2_PIX_FMT_ARGB444:
223 case V4L2_PIX_FMT_RGB555:
224 case V4L2_PIX_FMT_XRGB555:
225 case V4L2_PIX_FMT_ARGB555:
226 case V4L2_PIX_FMT_RGB555X:
227 case V4L2_PIX_FMT_XRGB555X:
228 case V4L2_PIX_FMT_ARGB555X:
229 case V4L2_PIX_FMT_BGR666:
230 case V4L2_PIX_FMT_RGB24:
231 case V4L2_PIX_FMT_BGR24:
232 case V4L2_PIX_FMT_RGB32:
233 case V4L2_PIX_FMT_BGR32:
234 case V4L2_PIX_FMT_XRGB32:
235 case V4L2_PIX_FMT_XBGR32:
236 case V4L2_PIX_FMT_ARGB32:
237 case V4L2_PIX_FMT_ABGR32:
238 tpg->color_enc = TGP_COLOR_ENC_RGB;
239 break;
240 case V4L2_PIX_FMT_GREY:
241 case V4L2_PIX_FMT_Y16:
242 case V4L2_PIX_FMT_Y16_BE:
243 tpg->color_enc = TGP_COLOR_ENC_LUMA;
244 break;
245 case V4L2_PIX_FMT_YUV444:
246 case V4L2_PIX_FMT_YUV555:
247 case V4L2_PIX_FMT_YUV565:
248 case V4L2_PIX_FMT_YUV32:
249 tpg->color_enc = TGP_COLOR_ENC_YCBCR;
250 break;
251 case V4L2_PIX_FMT_YUV420M:
252 case V4L2_PIX_FMT_YVU420M:
253 tpg->buffers = 3;
254 /* fall through */
255 case V4L2_PIX_FMT_YUV420:
256 case V4L2_PIX_FMT_YVU420:
257 tpg->vdownsampling[1] = 2;
258 tpg->vdownsampling[2] = 2;
259 tpg->hdownsampling[1] = 2;
260 tpg->hdownsampling[2] = 2;
261 tpg->planes = 3;
262 tpg->color_enc = TGP_COLOR_ENC_YCBCR;
263 break;
264 case V4L2_PIX_FMT_YUV422M:
265 case V4L2_PIX_FMT_YVU422M:
266 tpg->buffers = 3;
267 /* fall through */
268 case V4L2_PIX_FMT_YUV422P:
269 tpg->vdownsampling[1] = 1;
270 tpg->vdownsampling[2] = 1;
271 tpg->hdownsampling[1] = 2;
272 tpg->hdownsampling[2] = 2;
273 tpg->planes = 3;
274 tpg->color_enc = TGP_COLOR_ENC_YCBCR;
275 break;
276 case V4L2_PIX_FMT_NV16M:
277 case V4L2_PIX_FMT_NV61M:
278 tpg->buffers = 2;
279 /* fall through */
280 case V4L2_PIX_FMT_NV16:
281 case V4L2_PIX_FMT_NV61:
282 tpg->vdownsampling[1] = 1;
283 tpg->hdownsampling[1] = 1;
284 tpg->hmask[1] = ~1;
285 tpg->planes = 2;
286 tpg->color_enc = TGP_COLOR_ENC_YCBCR;
287 break;
288 case V4L2_PIX_FMT_NV12M:
289 case V4L2_PIX_FMT_NV21M:
290 tpg->buffers = 2;
291 /* fall through */
292 case V4L2_PIX_FMT_NV12:
293 case V4L2_PIX_FMT_NV21:
294 tpg->vdownsampling[1] = 2;
295 tpg->hdownsampling[1] = 1;
296 tpg->hmask[1] = ~1;
297 tpg->planes = 2;
298 tpg->color_enc = TGP_COLOR_ENC_YCBCR;
299 break;
300 case V4L2_PIX_FMT_YUV444M:
301 case V4L2_PIX_FMT_YVU444M:
302 tpg->buffers = 3;
303 tpg->planes = 3;
304 tpg->vdownsampling[1] = 1;
305 tpg->vdownsampling[2] = 1;
306 tpg->hdownsampling[1] = 1;
307 tpg->hdownsampling[2] = 1;
308 tpg->color_enc = TGP_COLOR_ENC_YCBCR;
309 break;
310 case V4L2_PIX_FMT_NV24:
311 case V4L2_PIX_FMT_NV42:
312 tpg->vdownsampling[1] = 1;
313 tpg->hdownsampling[1] = 1;
314 tpg->planes = 2;
315 tpg->color_enc = TGP_COLOR_ENC_YCBCR;
316 break;
317 case V4L2_PIX_FMT_YUYV:
318 case V4L2_PIX_FMT_UYVY:
319 case V4L2_PIX_FMT_YVYU:
320 case V4L2_PIX_FMT_VYUY:
321 tpg->hmask[0] = ~1;
322 tpg->color_enc = TGP_COLOR_ENC_YCBCR;
323 break;
324 case V4L2_PIX_FMT_HSV24:
325 case V4L2_PIX_FMT_HSV32:
326 tpg->color_enc = TGP_COLOR_ENC_HSV;
327 break;
328 default:
329 return false;
332 switch (fourcc) {
333 case V4L2_PIX_FMT_GREY:
334 case V4L2_PIX_FMT_RGB332:
335 tpg->twopixelsize[0] = 2;
336 break;
337 case V4L2_PIX_FMT_RGB565:
338 case V4L2_PIX_FMT_RGB565X:
339 case V4L2_PIX_FMT_RGB444:
340 case V4L2_PIX_FMT_XRGB444:
341 case V4L2_PIX_FMT_ARGB444:
342 case V4L2_PIX_FMT_RGB555:
343 case V4L2_PIX_FMT_XRGB555:
344 case V4L2_PIX_FMT_ARGB555:
345 case V4L2_PIX_FMT_RGB555X:
346 case V4L2_PIX_FMT_XRGB555X:
347 case V4L2_PIX_FMT_ARGB555X:
348 case V4L2_PIX_FMT_YUYV:
349 case V4L2_PIX_FMT_UYVY:
350 case V4L2_PIX_FMT_YVYU:
351 case V4L2_PIX_FMT_VYUY:
352 case V4L2_PIX_FMT_YUV444:
353 case V4L2_PIX_FMT_YUV555:
354 case V4L2_PIX_FMT_YUV565:
355 case V4L2_PIX_FMT_Y16:
356 case V4L2_PIX_FMT_Y16_BE:
357 tpg->twopixelsize[0] = 2 * 2;
358 break;
359 case V4L2_PIX_FMT_RGB24:
360 case V4L2_PIX_FMT_BGR24:
361 case V4L2_PIX_FMT_HSV24:
362 tpg->twopixelsize[0] = 2 * 3;
363 break;
364 case V4L2_PIX_FMT_BGR666:
365 case V4L2_PIX_FMT_RGB32:
366 case V4L2_PIX_FMT_BGR32:
367 case V4L2_PIX_FMT_XRGB32:
368 case V4L2_PIX_FMT_XBGR32:
369 case V4L2_PIX_FMT_ARGB32:
370 case V4L2_PIX_FMT_ABGR32:
371 case V4L2_PIX_FMT_YUV32:
372 case V4L2_PIX_FMT_HSV32:
373 tpg->twopixelsize[0] = 2 * 4;
374 break;
375 case V4L2_PIX_FMT_NV12:
376 case V4L2_PIX_FMT_NV21:
377 case V4L2_PIX_FMT_NV12M:
378 case V4L2_PIX_FMT_NV21M:
379 case V4L2_PIX_FMT_NV16:
380 case V4L2_PIX_FMT_NV61:
381 case V4L2_PIX_FMT_NV16M:
382 case V4L2_PIX_FMT_NV61M:
383 case V4L2_PIX_FMT_SBGGR8:
384 case V4L2_PIX_FMT_SGBRG8:
385 case V4L2_PIX_FMT_SGRBG8:
386 case V4L2_PIX_FMT_SRGGB8:
387 tpg->twopixelsize[0] = 2;
388 tpg->twopixelsize[1] = 2;
389 break;
390 case V4L2_PIX_FMT_SRGGB10:
391 case V4L2_PIX_FMT_SGRBG10:
392 case V4L2_PIX_FMT_SGBRG10:
393 case V4L2_PIX_FMT_SBGGR10:
394 case V4L2_PIX_FMT_SRGGB12:
395 case V4L2_PIX_FMT_SGRBG12:
396 case V4L2_PIX_FMT_SGBRG12:
397 case V4L2_PIX_FMT_SBGGR12:
398 tpg->twopixelsize[0] = 4;
399 tpg->twopixelsize[1] = 4;
400 break;
401 case V4L2_PIX_FMT_YUV444M:
402 case V4L2_PIX_FMT_YVU444M:
403 case V4L2_PIX_FMT_YUV422M:
404 case V4L2_PIX_FMT_YVU422M:
405 case V4L2_PIX_FMT_YUV422P:
406 case V4L2_PIX_FMT_YUV420:
407 case V4L2_PIX_FMT_YVU420:
408 case V4L2_PIX_FMT_YUV420M:
409 case V4L2_PIX_FMT_YVU420M:
410 tpg->twopixelsize[0] = 2;
411 tpg->twopixelsize[1] = 2;
412 tpg->twopixelsize[2] = 2;
413 break;
414 case V4L2_PIX_FMT_NV24:
415 case V4L2_PIX_FMT_NV42:
416 tpg->twopixelsize[0] = 2;
417 tpg->twopixelsize[1] = 4;
418 break;
420 return true;
422 EXPORT_SYMBOL_GPL(tpg_s_fourcc);
424 void tpg_s_crop_compose(struct tpg_data *tpg, const struct v4l2_rect *crop,
425 const struct v4l2_rect *compose)
427 tpg->crop = *crop;
428 tpg->compose = *compose;
429 tpg->scaled_width = (tpg->src_width * tpg->compose.width +
430 tpg->crop.width - 1) / tpg->crop.width;
431 tpg->scaled_width &= ~1;
432 if (tpg->scaled_width > tpg->max_line_width)
433 tpg->scaled_width = tpg->max_line_width;
434 if (tpg->scaled_width < 2)
435 tpg->scaled_width = 2;
436 tpg->recalc_lines = true;
438 EXPORT_SYMBOL_GPL(tpg_s_crop_compose);
440 void tpg_reset_source(struct tpg_data *tpg, unsigned width, unsigned height,
441 u32 field)
443 unsigned p;
445 tpg->src_width = width;
446 tpg->src_height = height;
447 tpg->field = field;
448 tpg->buf_height = height;
449 if (V4L2_FIELD_HAS_T_OR_B(field))
450 tpg->buf_height /= 2;
451 tpg->scaled_width = width;
452 tpg->crop.top = tpg->crop.left = 0;
453 tpg->crop.width = width;
454 tpg->crop.height = height;
455 tpg->compose.top = tpg->compose.left = 0;
456 tpg->compose.width = width;
457 tpg->compose.height = tpg->buf_height;
458 for (p = 0; p < tpg->planes; p++)
459 tpg->bytesperline[p] = (width * tpg->twopixelsize[p]) /
460 (2 * tpg->hdownsampling[p]);
461 tpg->recalc_square_border = true;
463 EXPORT_SYMBOL_GPL(tpg_reset_source);
465 static enum tpg_color tpg_get_textbg_color(struct tpg_data *tpg)
467 switch (tpg->pattern) {
468 case TPG_PAT_BLACK:
469 return TPG_COLOR_100_WHITE;
470 case TPG_PAT_CSC_COLORBAR:
471 return TPG_COLOR_CSC_BLACK;
472 default:
473 return TPG_COLOR_100_BLACK;
477 static enum tpg_color tpg_get_textfg_color(struct tpg_data *tpg)
479 switch (tpg->pattern) {
480 case TPG_PAT_75_COLORBAR:
481 case TPG_PAT_CSC_COLORBAR:
482 return TPG_COLOR_CSC_WHITE;
483 case TPG_PAT_BLACK:
484 return TPG_COLOR_100_BLACK;
485 default:
486 return TPG_COLOR_100_WHITE;
490 static inline int rec709_to_linear(int v)
492 v = clamp(v, 0, 0xff0);
493 return tpg_rec709_to_linear[v];
496 static inline int linear_to_rec709(int v)
498 v = clamp(v, 0, 0xff0);
499 return tpg_linear_to_rec709[v];
502 static void color_to_hsv(struct tpg_data *tpg, int r, int g, int b,
503 int *h, int *s, int *v)
505 int max_rgb, min_rgb, diff_rgb;
506 int aux;
507 int third;
508 int third_size;
510 r >>= 4;
511 g >>= 4;
512 b >>= 4;
514 /* Value */
515 max_rgb = max3(r, g, b);
516 *v = max_rgb;
517 if (!max_rgb) {
518 *h = 0;
519 *s = 0;
520 return;
523 /* Saturation */
524 min_rgb = min3(r, g, b);
525 diff_rgb = max_rgb - min_rgb;
526 aux = 255 * diff_rgb;
527 aux += max_rgb / 2;
528 aux /= max_rgb;
529 *s = aux;
530 if (!aux) {
531 *h = 0;
532 return;
535 third_size = (tpg->real_hsv_enc == V4L2_HSV_ENC_180) ? 60 : 85;
537 /* Hue */
538 if (max_rgb == r) {
539 aux = g - b;
540 third = 0;
541 } else if (max_rgb == g) {
542 aux = b - r;
543 third = third_size;
544 } else {
545 aux = r - g;
546 third = third_size * 2;
549 aux *= third_size / 2;
550 aux += diff_rgb / 2;
551 aux /= diff_rgb;
552 aux += third;
554 /* Clamp Hue */
555 if (tpg->real_hsv_enc == V4L2_HSV_ENC_180) {
556 if (aux < 0)
557 aux += 180;
558 else if (aux > 180)
559 aux -= 180;
560 } else {
561 aux = aux & 0xff;
564 *h = aux;
567 static void rgb2ycbcr(const int m[3][3], int r, int g, int b,
568 int y_offset, int *y, int *cb, int *cr)
570 *y = ((m[0][0] * r + m[0][1] * g + m[0][2] * b) >> 16) + (y_offset << 4);
571 *cb = ((m[1][0] * r + m[1][1] * g + m[1][2] * b) >> 16) + (128 << 4);
572 *cr = ((m[2][0] * r + m[2][1] * g + m[2][2] * b) >> 16) + (128 << 4);
575 static void color_to_ycbcr(struct tpg_data *tpg, int r, int g, int b,
576 int *y, int *cb, int *cr)
578 #define COEFF(v, r) ((int)(0.5 + (v) * (r) * 256.0))
580 static const int bt601[3][3] = {
581 { COEFF(0.299, 219), COEFF(0.587, 219), COEFF(0.114, 219) },
582 { COEFF(-0.1687, 224), COEFF(-0.3313, 224), COEFF(0.5, 224) },
583 { COEFF(0.5, 224), COEFF(-0.4187, 224), COEFF(-0.0813, 224) },
585 static const int bt601_full[3][3] = {
586 { COEFF(0.299, 255), COEFF(0.587, 255), COEFF(0.114, 255) },
587 { COEFF(-0.1687, 255), COEFF(-0.3313, 255), COEFF(0.5, 255) },
588 { COEFF(0.5, 255), COEFF(-0.4187, 255), COEFF(-0.0813, 255) },
590 static const int rec709[3][3] = {
591 { COEFF(0.2126, 219), COEFF(0.7152, 219), COEFF(0.0722, 219) },
592 { COEFF(-0.1146, 224), COEFF(-0.3854, 224), COEFF(0.5, 224) },
593 { COEFF(0.5, 224), COEFF(-0.4542, 224), COEFF(-0.0458, 224) },
595 static const int rec709_full[3][3] = {
596 { COEFF(0.2126, 255), COEFF(0.7152, 255), COEFF(0.0722, 255) },
597 { COEFF(-0.1146, 255), COEFF(-0.3854, 255), COEFF(0.5, 255) },
598 { COEFF(0.5, 255), COEFF(-0.4542, 255), COEFF(-0.0458, 255) },
600 static const int smpte240m[3][3] = {
601 { COEFF(0.212, 219), COEFF(0.701, 219), COEFF(0.087, 219) },
602 { COEFF(-0.116, 224), COEFF(-0.384, 224), COEFF(0.5, 224) },
603 { COEFF(0.5, 224), COEFF(-0.445, 224), COEFF(-0.055, 224) },
605 static const int smpte240m_full[3][3] = {
606 { COEFF(0.212, 255), COEFF(0.701, 255), COEFF(0.087, 255) },
607 { COEFF(-0.116, 255), COEFF(-0.384, 255), COEFF(0.5, 255) },
608 { COEFF(0.5, 255), COEFF(-0.445, 255), COEFF(-0.055, 255) },
610 static const int bt2020[3][3] = {
611 { COEFF(0.2627, 219), COEFF(0.6780, 219), COEFF(0.0593, 219) },
612 { COEFF(-0.1396, 224), COEFF(-0.3604, 224), COEFF(0.5, 224) },
613 { COEFF(0.5, 224), COEFF(-0.4598, 224), COEFF(-0.0402, 224) },
615 static const int bt2020_full[3][3] = {
616 { COEFF(0.2627, 255), COEFF(0.6780, 255), COEFF(0.0593, 255) },
617 { COEFF(-0.1396, 255), COEFF(-0.3604, 255), COEFF(0.5, 255) },
618 { COEFF(0.5, 255), COEFF(-0.4698, 255), COEFF(-0.0402, 255) },
620 static const int bt2020c[4] = {
621 COEFF(1.0 / 1.9404, 224), COEFF(1.0 / 1.5816, 224),
622 COEFF(1.0 / 1.7184, 224), COEFF(1.0 / 0.9936, 224),
624 static const int bt2020c_full[4] = {
625 COEFF(1.0 / 1.9404, 255), COEFF(1.0 / 1.5816, 255),
626 COEFF(1.0 / 1.7184, 255), COEFF(1.0 / 0.9936, 255),
629 bool full = tpg->real_quantization == V4L2_QUANTIZATION_FULL_RANGE;
630 unsigned y_offset = full ? 0 : 16;
631 int lin_y, yc;
633 switch (tpg->real_ycbcr_enc) {
634 case V4L2_YCBCR_ENC_601:
635 rgb2ycbcr(full ? bt601_full : bt601, r, g, b, y_offset, y, cb, cr);
636 break;
637 case V4L2_YCBCR_ENC_XV601:
638 /* Ignore quantization range, there is only one possible
639 * Y'CbCr encoding. */
640 rgb2ycbcr(bt601, r, g, b, 16, y, cb, cr);
641 break;
642 case V4L2_YCBCR_ENC_XV709:
643 /* Ignore quantization range, there is only one possible
644 * Y'CbCr encoding. */
645 rgb2ycbcr(rec709, r, g, b, 16, y, cb, cr);
646 break;
647 case V4L2_YCBCR_ENC_BT2020:
648 rgb2ycbcr(full ? bt2020_full : bt2020, r, g, b, y_offset, y, cb, cr);
649 break;
650 case V4L2_YCBCR_ENC_BT2020_CONST_LUM:
651 lin_y = (COEFF(0.2627, 255) * rec709_to_linear(r) +
652 COEFF(0.6780, 255) * rec709_to_linear(g) +
653 COEFF(0.0593, 255) * rec709_to_linear(b)) >> 16;
654 yc = linear_to_rec709(lin_y);
655 *y = full ? yc : (yc * 219) / 255 + (16 << 4);
656 if (b <= yc)
657 *cb = (((b - yc) * (full ? bt2020c_full[0] : bt2020c[0])) >> 16) + (128 << 4);
658 else
659 *cb = (((b - yc) * (full ? bt2020c_full[1] : bt2020c[1])) >> 16) + (128 << 4);
660 if (r <= yc)
661 *cr = (((r - yc) * (full ? bt2020c_full[2] : bt2020c[2])) >> 16) + (128 << 4);
662 else
663 *cr = (((r - yc) * (full ? bt2020c_full[3] : bt2020c[3])) >> 16) + (128 << 4);
664 break;
665 case V4L2_YCBCR_ENC_SMPTE240M:
666 rgb2ycbcr(full ? smpte240m_full : smpte240m, r, g, b, y_offset, y, cb, cr);
667 break;
668 case V4L2_YCBCR_ENC_709:
669 default:
670 rgb2ycbcr(full ? rec709_full : rec709, r, g, b, y_offset, y, cb, cr);
671 break;
675 static void ycbcr2rgb(const int m[3][3], int y, int cb, int cr,
676 int y_offset, int *r, int *g, int *b)
678 y -= y_offset << 4;
679 cb -= 128 << 4;
680 cr -= 128 << 4;
681 *r = m[0][0] * y + m[0][1] * cb + m[0][2] * cr;
682 *g = m[1][0] * y + m[1][1] * cb + m[1][2] * cr;
683 *b = m[2][0] * y + m[2][1] * cb + m[2][2] * cr;
684 *r = clamp(*r >> 12, 0, 0xff0);
685 *g = clamp(*g >> 12, 0, 0xff0);
686 *b = clamp(*b >> 12, 0, 0xff0);
689 static void ycbcr_to_color(struct tpg_data *tpg, int y, int cb, int cr,
690 int *r, int *g, int *b)
692 #undef COEFF
693 #define COEFF(v, r) ((int)(0.5 + (v) * ((255.0 * 255.0 * 16.0) / (r))))
694 static const int bt601[3][3] = {
695 { COEFF(1, 219), COEFF(0, 224), COEFF(1.4020, 224) },
696 { COEFF(1, 219), COEFF(-0.3441, 224), COEFF(-0.7141, 224) },
697 { COEFF(1, 219), COEFF(1.7720, 224), COEFF(0, 224) },
699 static const int bt601_full[3][3] = {
700 { COEFF(1, 255), COEFF(0, 255), COEFF(1.4020, 255) },
701 { COEFF(1, 255), COEFF(-0.3441, 255), COEFF(-0.7141, 255) },
702 { COEFF(1, 255), COEFF(1.7720, 255), COEFF(0, 255) },
704 static const int rec709[3][3] = {
705 { COEFF(1, 219), COEFF(0, 224), COEFF(1.5748, 224) },
706 { COEFF(1, 219), COEFF(-0.1873, 224), COEFF(-0.4681, 224) },
707 { COEFF(1, 219), COEFF(1.8556, 224), COEFF(0, 224) },
709 static const int rec709_full[3][3] = {
710 { COEFF(1, 255), COEFF(0, 255), COEFF(1.5748, 255) },
711 { COEFF(1, 255), COEFF(-0.1873, 255), COEFF(-0.4681, 255) },
712 { COEFF(1, 255), COEFF(1.8556, 255), COEFF(0, 255) },
714 static const int smpte240m[3][3] = {
715 { COEFF(1, 219), COEFF(0, 224), COEFF(1.5756, 224) },
716 { COEFF(1, 219), COEFF(-0.2253, 224), COEFF(-0.4767, 224) },
717 { COEFF(1, 219), COEFF(1.8270, 224), COEFF(0, 224) },
719 static const int smpte240m_full[3][3] = {
720 { COEFF(1, 255), COEFF(0, 255), COEFF(1.5756, 255) },
721 { COEFF(1, 255), COEFF(-0.2253, 255), COEFF(-0.4767, 255) },
722 { COEFF(1, 255), COEFF(1.8270, 255), COEFF(0, 255) },
724 static const int bt2020[3][3] = {
725 { COEFF(1, 219), COEFF(0, 224), COEFF(1.4746, 224) },
726 { COEFF(1, 219), COEFF(-0.1646, 224), COEFF(-0.5714, 224) },
727 { COEFF(1, 219), COEFF(1.8814, 224), COEFF(0, 224) },
729 static const int bt2020_full[3][3] = {
730 { COEFF(1, 255), COEFF(0, 255), COEFF(1.4746, 255) },
731 { COEFF(1, 255), COEFF(-0.1646, 255), COEFF(-0.5714, 255) },
732 { COEFF(1, 255), COEFF(1.8814, 255), COEFF(0, 255) },
734 static const int bt2020c[4] = {
735 COEFF(1.9404, 224), COEFF(1.5816, 224),
736 COEFF(1.7184, 224), COEFF(0.9936, 224),
738 static const int bt2020c_full[4] = {
739 COEFF(1.9404, 255), COEFF(1.5816, 255),
740 COEFF(1.7184, 255), COEFF(0.9936, 255),
743 bool full = tpg->real_quantization == V4L2_QUANTIZATION_FULL_RANGE;
744 unsigned y_offset = full ? 0 : 16;
745 int y_fac = full ? COEFF(1.0, 255) : COEFF(1.0, 219);
746 int lin_r, lin_g, lin_b, lin_y;
748 switch (tpg->real_ycbcr_enc) {
749 case V4L2_YCBCR_ENC_601:
750 ycbcr2rgb(full ? bt601_full : bt601, y, cb, cr, y_offset, r, g, b);
751 break;
752 case V4L2_YCBCR_ENC_XV601:
753 /* Ignore quantization range, there is only one possible
754 * Y'CbCr encoding. */
755 ycbcr2rgb(bt601, y, cb, cr, 16, r, g, b);
756 break;
757 case V4L2_YCBCR_ENC_XV709:
758 /* Ignore quantization range, there is only one possible
759 * Y'CbCr encoding. */
760 ycbcr2rgb(rec709, y, cb, cr, 16, r, g, b);
761 break;
762 case V4L2_YCBCR_ENC_BT2020:
763 ycbcr2rgb(full ? bt2020_full : bt2020, y, cb, cr, y_offset, r, g, b);
764 break;
765 case V4L2_YCBCR_ENC_BT2020_CONST_LUM:
766 y -= full ? 0 : 16 << 4;
767 cb -= 128 << 4;
768 cr -= 128 << 4;
770 if (cb <= 0)
771 *b = y_fac * y + (full ? bt2020c_full[0] : bt2020c[0]) * cb;
772 else
773 *b = y_fac * y + (full ? bt2020c_full[1] : bt2020c[1]) * cb;
774 *b = *b >> 12;
775 if (cr <= 0)
776 *r = y_fac * y + (full ? bt2020c_full[2] : bt2020c[2]) * cr;
777 else
778 *r = y_fac * y + (full ? bt2020c_full[3] : bt2020c[3]) * cr;
779 *r = *r >> 12;
780 lin_r = rec709_to_linear(*r);
781 lin_b = rec709_to_linear(*b);
782 lin_y = rec709_to_linear((y * 255) / (full ? 255 : 219));
784 lin_g = COEFF(1.0 / 0.6780, 255) * lin_y -
785 COEFF(0.2627 / 0.6780, 255) * lin_r -
786 COEFF(0.0593 / 0.6780, 255) * lin_b;
787 *g = linear_to_rec709(lin_g >> 12);
788 break;
789 case V4L2_YCBCR_ENC_SMPTE240M:
790 ycbcr2rgb(full ? smpte240m_full : smpte240m, y, cb, cr, y_offset, r, g, b);
791 break;
792 case V4L2_YCBCR_ENC_709:
793 default:
794 ycbcr2rgb(full ? rec709_full : rec709, y, cb, cr, y_offset, r, g, b);
795 break;
799 /* precalculate color bar values to speed up rendering */
800 static void precalculate_color(struct tpg_data *tpg, int k)
802 int col = k;
803 int r = tpg_colors[col].r;
804 int g = tpg_colors[col].g;
805 int b = tpg_colors[col].b;
806 int y, cb, cr;
807 bool ycbcr_valid = false;
809 if (k == TPG_COLOR_TEXTBG) {
810 col = tpg_get_textbg_color(tpg);
812 r = tpg_colors[col].r;
813 g = tpg_colors[col].g;
814 b = tpg_colors[col].b;
815 } else if (k == TPG_COLOR_TEXTFG) {
816 col = tpg_get_textfg_color(tpg);
818 r = tpg_colors[col].r;
819 g = tpg_colors[col].g;
820 b = tpg_colors[col].b;
821 } else if (tpg->pattern == TPG_PAT_NOISE) {
822 r = g = b = prandom_u32_max(256);
823 } else if (k == TPG_COLOR_RANDOM) {
824 r = g = b = tpg->qual_offset + prandom_u32_max(196);
825 } else if (k >= TPG_COLOR_RAMP) {
826 r = g = b = k - TPG_COLOR_RAMP;
829 if (tpg->pattern == TPG_PAT_CSC_COLORBAR && col <= TPG_COLOR_CSC_BLACK) {
830 r = tpg_csc_colors[tpg->colorspace][tpg->real_xfer_func][col].r;
831 g = tpg_csc_colors[tpg->colorspace][tpg->real_xfer_func][col].g;
832 b = tpg_csc_colors[tpg->colorspace][tpg->real_xfer_func][col].b;
833 } else {
834 r <<= 4;
835 g <<= 4;
836 b <<= 4;
839 if (tpg->qual == TPG_QUAL_GRAY ||
840 tpg->color_enc == TGP_COLOR_ENC_LUMA) {
841 /* Rec. 709 Luma function */
842 /* (0.2126, 0.7152, 0.0722) * (255 * 256) */
843 r = g = b = (13879 * r + 46688 * g + 4713 * b) >> 16;
847 * The assumption is that the RGB output is always full range,
848 * so only if the rgb_range overrides the 'real' rgb range do
849 * we need to convert the RGB values.
851 * Remember that r, g and b are still in the 0 - 0xff0 range.
853 if (tpg->real_rgb_range == V4L2_DV_RGB_RANGE_LIMITED &&
854 tpg->rgb_range == V4L2_DV_RGB_RANGE_FULL &&
855 tpg->color_enc == TGP_COLOR_ENC_RGB) {
857 * Convert from full range (which is what r, g and b are)
858 * to limited range (which is the 'real' RGB range), which
859 * is then interpreted as full range.
861 r = (r * 219) / 255 + (16 << 4);
862 g = (g * 219) / 255 + (16 << 4);
863 b = (b * 219) / 255 + (16 << 4);
864 } else if (tpg->real_rgb_range != V4L2_DV_RGB_RANGE_LIMITED &&
865 tpg->rgb_range == V4L2_DV_RGB_RANGE_LIMITED &&
866 tpg->color_enc == TGP_COLOR_ENC_RGB) {
869 * Clamp r, g and b to the limited range and convert to full
870 * range since that's what we deliver.
872 r = clamp(r, 16 << 4, 235 << 4);
873 g = clamp(g, 16 << 4, 235 << 4);
874 b = clamp(b, 16 << 4, 235 << 4);
875 r = (r - (16 << 4)) * 255 / 219;
876 g = (g - (16 << 4)) * 255 / 219;
877 b = (b - (16 << 4)) * 255 / 219;
880 if ((tpg->brightness != 128 || tpg->contrast != 128 ||
881 tpg->saturation != 128 || tpg->hue) &&
882 tpg->color_enc != TGP_COLOR_ENC_LUMA) {
883 /* Implement these operations */
884 int tmp_cb, tmp_cr;
886 /* First convert to YCbCr */
888 color_to_ycbcr(tpg, r, g, b, &y, &cb, &cr);
890 y = (16 << 4) + ((y - (16 << 4)) * tpg->contrast) / 128;
891 y += (tpg->brightness << 4) - (128 << 4);
893 cb -= 128 << 4;
894 cr -= 128 << 4;
895 tmp_cb = (cb * cos(128 + tpg->hue)) / 127 + (cr * sin[128 + tpg->hue]) / 127;
896 tmp_cr = (cr * cos(128 + tpg->hue)) / 127 - (cb * sin[128 + tpg->hue]) / 127;
898 cb = (128 << 4) + (tmp_cb * tpg->contrast * tpg->saturation) / (128 * 128);
899 cr = (128 << 4) + (tmp_cr * tpg->contrast * tpg->saturation) / (128 * 128);
900 if (tpg->color_enc == TGP_COLOR_ENC_YCBCR)
901 ycbcr_valid = true;
902 else
903 ycbcr_to_color(tpg, y, cb, cr, &r, &g, &b);
904 } else if ((tpg->brightness != 128 || tpg->contrast != 128) &&
905 tpg->color_enc == TGP_COLOR_ENC_LUMA) {
906 r = (16 << 4) + ((r - (16 << 4)) * tpg->contrast) / 128;
907 r += (tpg->brightness << 4) - (128 << 4);
910 switch (tpg->color_enc) {
911 case TGP_COLOR_ENC_HSV:
913 int h, s, v;
915 color_to_hsv(tpg, r, g, b, &h, &s, &v);
916 tpg->colors[k][0] = h;
917 tpg->colors[k][1] = s;
918 tpg->colors[k][2] = v;
919 break;
921 case TGP_COLOR_ENC_YCBCR:
923 /* Convert to YCbCr */
924 if (!ycbcr_valid)
925 color_to_ycbcr(tpg, r, g, b, &y, &cb, &cr);
927 y >>= 4;
928 cb >>= 4;
929 cr >>= 4;
930 if (tpg->real_quantization == V4L2_QUANTIZATION_LIM_RANGE) {
931 y = clamp(y, 16, 235);
932 cb = clamp(cb, 16, 240);
933 cr = clamp(cr, 16, 240);
934 } else {
935 y = clamp(y, 1, 254);
936 cb = clamp(cb, 1, 254);
937 cr = clamp(cr, 1, 254);
939 switch (tpg->fourcc) {
940 case V4L2_PIX_FMT_YUV444:
941 y >>= 4;
942 cb >>= 4;
943 cr >>= 4;
944 break;
945 case V4L2_PIX_FMT_YUV555:
946 y >>= 3;
947 cb >>= 3;
948 cr >>= 3;
949 break;
950 case V4L2_PIX_FMT_YUV565:
951 y >>= 3;
952 cb >>= 2;
953 cr >>= 3;
954 break;
956 tpg->colors[k][0] = y;
957 tpg->colors[k][1] = cb;
958 tpg->colors[k][2] = cr;
959 break;
961 case TGP_COLOR_ENC_LUMA:
963 tpg->colors[k][0] = r >> 4;
964 break;
966 case TGP_COLOR_ENC_RGB:
968 if (tpg->real_quantization == V4L2_QUANTIZATION_LIM_RANGE) {
969 r = (r * 219) / 255 + (16 << 4);
970 g = (g * 219) / 255 + (16 << 4);
971 b = (b * 219) / 255 + (16 << 4);
973 switch (tpg->fourcc) {
974 case V4L2_PIX_FMT_RGB332:
975 r >>= 9;
976 g >>= 9;
977 b >>= 10;
978 break;
979 case V4L2_PIX_FMT_RGB565:
980 case V4L2_PIX_FMT_RGB565X:
981 r >>= 7;
982 g >>= 6;
983 b >>= 7;
984 break;
985 case V4L2_PIX_FMT_RGB444:
986 case V4L2_PIX_FMT_XRGB444:
987 case V4L2_PIX_FMT_ARGB444:
988 r >>= 8;
989 g >>= 8;
990 b >>= 8;
991 break;
992 case V4L2_PIX_FMT_RGB555:
993 case V4L2_PIX_FMT_XRGB555:
994 case V4L2_PIX_FMT_ARGB555:
995 case V4L2_PIX_FMT_RGB555X:
996 case V4L2_PIX_FMT_XRGB555X:
997 case V4L2_PIX_FMT_ARGB555X:
998 r >>= 7;
999 g >>= 7;
1000 b >>= 7;
1001 break;
1002 case V4L2_PIX_FMT_BGR666:
1003 r >>= 6;
1004 g >>= 6;
1005 b >>= 6;
1006 break;
1007 default:
1008 r >>= 4;
1009 g >>= 4;
1010 b >>= 4;
1011 break;
1014 tpg->colors[k][0] = r;
1015 tpg->colors[k][1] = g;
1016 tpg->colors[k][2] = b;
1017 break;
1022 static void tpg_precalculate_colors(struct tpg_data *tpg)
1024 int k;
1026 for (k = 0; k < TPG_COLOR_MAX; k++)
1027 precalculate_color(tpg, k);
1030 /* 'odd' is true for pixels 1, 3, 5, etc. and false for pixels 0, 2, 4, etc. */
1031 static void gen_twopix(struct tpg_data *tpg,
1032 u8 buf[TPG_MAX_PLANES][8], int color, bool odd)
1034 unsigned offset = odd * tpg->twopixelsize[0] / 2;
1035 u8 alpha = tpg->alpha_component;
1036 u8 r_y_h, g_u_s, b_v;
1038 if (tpg->alpha_red_only && color != TPG_COLOR_CSC_RED &&
1039 color != TPG_COLOR_100_RED &&
1040 color != TPG_COLOR_75_RED)
1041 alpha = 0;
1042 if (color == TPG_COLOR_RANDOM)
1043 precalculate_color(tpg, color);
1044 r_y_h = tpg->colors[color][0]; /* R or precalculated Y, H */
1045 g_u_s = tpg->colors[color][1]; /* G or precalculated U, V */
1046 b_v = tpg->colors[color][2]; /* B or precalculated V */
1048 switch (tpg->fourcc) {
1049 case V4L2_PIX_FMT_GREY:
1050 buf[0][offset] = r_y_h;
1051 break;
1052 case V4L2_PIX_FMT_Y16:
1054 * Ideally both bytes should be set to r_y_h, but then you won't
1055 * be able to detect endian problems. So keep it 0 except for
1056 * the corner case where r_y_h is 0xff so white really will be
1057 * white (0xffff).
1059 buf[0][offset] = r_y_h == 0xff ? r_y_h : 0;
1060 buf[0][offset+1] = r_y_h;
1061 break;
1062 case V4L2_PIX_FMT_Y16_BE:
1063 /* See comment for V4L2_PIX_FMT_Y16 above */
1064 buf[0][offset] = r_y_h;
1065 buf[0][offset+1] = r_y_h == 0xff ? r_y_h : 0;
1066 break;
1067 case V4L2_PIX_FMT_YUV422M:
1068 case V4L2_PIX_FMT_YUV422P:
1069 case V4L2_PIX_FMT_YUV420:
1070 case V4L2_PIX_FMT_YUV420M:
1071 buf[0][offset] = r_y_h;
1072 if (odd) {
1073 buf[1][0] = (buf[1][0] + g_u_s) / 2;
1074 buf[2][0] = (buf[2][0] + b_v) / 2;
1075 buf[1][1] = buf[1][0];
1076 buf[2][1] = buf[2][0];
1077 break;
1079 buf[1][0] = g_u_s;
1080 buf[2][0] = b_v;
1081 break;
1082 case V4L2_PIX_FMT_YVU422M:
1083 case V4L2_PIX_FMT_YVU420:
1084 case V4L2_PIX_FMT_YVU420M:
1085 buf[0][offset] = r_y_h;
1086 if (odd) {
1087 buf[1][0] = (buf[1][0] + b_v) / 2;
1088 buf[2][0] = (buf[2][0] + g_u_s) / 2;
1089 buf[1][1] = buf[1][0];
1090 buf[2][1] = buf[2][0];
1091 break;
1093 buf[1][0] = b_v;
1094 buf[2][0] = g_u_s;
1095 break;
1097 case V4L2_PIX_FMT_NV12:
1098 case V4L2_PIX_FMT_NV12M:
1099 case V4L2_PIX_FMT_NV16:
1100 case V4L2_PIX_FMT_NV16M:
1101 buf[0][offset] = r_y_h;
1102 if (odd) {
1103 buf[1][0] = (buf[1][0] + g_u_s) / 2;
1104 buf[1][1] = (buf[1][1] + b_v) / 2;
1105 break;
1107 buf[1][0] = g_u_s;
1108 buf[1][1] = b_v;
1109 break;
1110 case V4L2_PIX_FMT_NV21:
1111 case V4L2_PIX_FMT_NV21M:
1112 case V4L2_PIX_FMT_NV61:
1113 case V4L2_PIX_FMT_NV61M:
1114 buf[0][offset] = r_y_h;
1115 if (odd) {
1116 buf[1][0] = (buf[1][0] + b_v) / 2;
1117 buf[1][1] = (buf[1][1] + g_u_s) / 2;
1118 break;
1120 buf[1][0] = b_v;
1121 buf[1][1] = g_u_s;
1122 break;
1124 case V4L2_PIX_FMT_YUV444M:
1125 buf[0][offset] = r_y_h;
1126 buf[1][offset] = g_u_s;
1127 buf[2][offset] = b_v;
1128 break;
1130 case V4L2_PIX_FMT_YVU444M:
1131 buf[0][offset] = r_y_h;
1132 buf[1][offset] = b_v;
1133 buf[2][offset] = g_u_s;
1134 break;
1136 case V4L2_PIX_FMT_NV24:
1137 buf[0][offset] = r_y_h;
1138 buf[1][2 * offset] = g_u_s;
1139 buf[1][2 * offset + 1] = b_v;
1140 break;
1142 case V4L2_PIX_FMT_NV42:
1143 buf[0][offset] = r_y_h;
1144 buf[1][2 * offset] = b_v;
1145 buf[1][2 * offset + 1] = g_u_s;
1146 break;
1148 case V4L2_PIX_FMT_YUYV:
1149 buf[0][offset] = r_y_h;
1150 if (odd) {
1151 buf[0][1] = (buf[0][1] + g_u_s) / 2;
1152 buf[0][3] = (buf[0][3] + b_v) / 2;
1153 break;
1155 buf[0][1] = g_u_s;
1156 buf[0][3] = b_v;
1157 break;
1158 case V4L2_PIX_FMT_UYVY:
1159 buf[0][offset + 1] = r_y_h;
1160 if (odd) {
1161 buf[0][0] = (buf[0][0] + g_u_s) / 2;
1162 buf[0][2] = (buf[0][2] + b_v) / 2;
1163 break;
1165 buf[0][0] = g_u_s;
1166 buf[0][2] = b_v;
1167 break;
1168 case V4L2_PIX_FMT_YVYU:
1169 buf[0][offset] = r_y_h;
1170 if (odd) {
1171 buf[0][1] = (buf[0][1] + b_v) / 2;
1172 buf[0][3] = (buf[0][3] + g_u_s) / 2;
1173 break;
1175 buf[0][1] = b_v;
1176 buf[0][3] = g_u_s;
1177 break;
1178 case V4L2_PIX_FMT_VYUY:
1179 buf[0][offset + 1] = r_y_h;
1180 if (odd) {
1181 buf[0][0] = (buf[0][0] + b_v) / 2;
1182 buf[0][2] = (buf[0][2] + g_u_s) / 2;
1183 break;
1185 buf[0][0] = b_v;
1186 buf[0][2] = g_u_s;
1187 break;
1188 case V4L2_PIX_FMT_RGB332:
1189 buf[0][offset] = (r_y_h << 5) | (g_u_s << 2) | b_v;
1190 break;
1191 case V4L2_PIX_FMT_YUV565:
1192 case V4L2_PIX_FMT_RGB565:
1193 buf[0][offset] = (g_u_s << 5) | b_v;
1194 buf[0][offset + 1] = (r_y_h << 3) | (g_u_s >> 3);
1195 break;
1196 case V4L2_PIX_FMT_RGB565X:
1197 buf[0][offset] = (r_y_h << 3) | (g_u_s >> 3);
1198 buf[0][offset + 1] = (g_u_s << 5) | b_v;
1199 break;
1200 case V4L2_PIX_FMT_RGB444:
1201 case V4L2_PIX_FMT_XRGB444:
1202 alpha = 0;
1203 /* fall through */
1204 case V4L2_PIX_FMT_YUV444:
1205 case V4L2_PIX_FMT_ARGB444:
1206 buf[0][offset] = (g_u_s << 4) | b_v;
1207 buf[0][offset + 1] = (alpha & 0xf0) | r_y_h;
1208 break;
1209 case V4L2_PIX_FMT_RGB555:
1210 case V4L2_PIX_FMT_XRGB555:
1211 alpha = 0;
1212 /* fall through */
1213 case V4L2_PIX_FMT_YUV555:
1214 case V4L2_PIX_FMT_ARGB555:
1215 buf[0][offset] = (g_u_s << 5) | b_v;
1216 buf[0][offset + 1] = (alpha & 0x80) | (r_y_h << 2)
1217 | (g_u_s >> 3);
1218 break;
1219 case V4L2_PIX_FMT_RGB555X:
1220 case V4L2_PIX_FMT_XRGB555X:
1221 alpha = 0;
1222 /* fall through */
1223 case V4L2_PIX_FMT_ARGB555X:
1224 buf[0][offset] = (alpha & 0x80) | (r_y_h << 2) | (g_u_s >> 3);
1225 buf[0][offset + 1] = (g_u_s << 5) | b_v;
1226 break;
1227 case V4L2_PIX_FMT_RGB24:
1228 case V4L2_PIX_FMT_HSV24:
1229 buf[0][offset] = r_y_h;
1230 buf[0][offset + 1] = g_u_s;
1231 buf[0][offset + 2] = b_v;
1232 break;
1233 case V4L2_PIX_FMT_BGR24:
1234 buf[0][offset] = b_v;
1235 buf[0][offset + 1] = g_u_s;
1236 buf[0][offset + 2] = r_y_h;
1237 break;
1238 case V4L2_PIX_FMT_BGR666:
1239 buf[0][offset] = (b_v << 2) | (g_u_s >> 4);
1240 buf[0][offset + 1] = (g_u_s << 4) | (r_y_h >> 2);
1241 buf[0][offset + 2] = r_y_h << 6;
1242 buf[0][offset + 3] = 0;
1243 break;
1244 case V4L2_PIX_FMT_RGB32:
1245 case V4L2_PIX_FMT_XRGB32:
1246 case V4L2_PIX_FMT_HSV32:
1247 alpha = 0;
1248 /* fall through */
1249 case V4L2_PIX_FMT_YUV32:
1250 case V4L2_PIX_FMT_ARGB32:
1251 buf[0][offset] = alpha;
1252 buf[0][offset + 1] = r_y_h;
1253 buf[0][offset + 2] = g_u_s;
1254 buf[0][offset + 3] = b_v;
1255 break;
1256 case V4L2_PIX_FMT_BGR32:
1257 case V4L2_PIX_FMT_XBGR32:
1258 alpha = 0;
1259 /* fall through */
1260 case V4L2_PIX_FMT_ABGR32:
1261 buf[0][offset] = b_v;
1262 buf[0][offset + 1] = g_u_s;
1263 buf[0][offset + 2] = r_y_h;
1264 buf[0][offset + 3] = alpha;
1265 break;
1266 case V4L2_PIX_FMT_SBGGR8:
1267 buf[0][offset] = odd ? g_u_s : b_v;
1268 buf[1][offset] = odd ? r_y_h : g_u_s;
1269 break;
1270 case V4L2_PIX_FMT_SGBRG8:
1271 buf[0][offset] = odd ? b_v : g_u_s;
1272 buf[1][offset] = odd ? g_u_s : r_y_h;
1273 break;
1274 case V4L2_PIX_FMT_SGRBG8:
1275 buf[0][offset] = odd ? r_y_h : g_u_s;
1276 buf[1][offset] = odd ? g_u_s : b_v;
1277 break;
1278 case V4L2_PIX_FMT_SRGGB8:
1279 buf[0][offset] = odd ? g_u_s : r_y_h;
1280 buf[1][offset] = odd ? b_v : g_u_s;
1281 break;
1282 case V4L2_PIX_FMT_SBGGR10:
1283 buf[0][offset] = odd ? g_u_s << 2 : b_v << 2;
1284 buf[0][offset + 1] = odd ? g_u_s >> 6 : b_v >> 6;
1285 buf[1][offset] = odd ? r_y_h << 2 : g_u_s << 2;
1286 buf[1][offset + 1] = odd ? r_y_h >> 6 : g_u_s >> 6;
1287 buf[0][offset] |= (buf[0][offset] >> 2) & 3;
1288 buf[1][offset] |= (buf[1][offset] >> 2) & 3;
1289 break;
1290 case V4L2_PIX_FMT_SGBRG10:
1291 buf[0][offset] = odd ? b_v << 2 : g_u_s << 2;
1292 buf[0][offset + 1] = odd ? b_v >> 6 : g_u_s >> 6;
1293 buf[1][offset] = odd ? g_u_s << 2 : r_y_h << 2;
1294 buf[1][offset + 1] = odd ? g_u_s >> 6 : r_y_h >> 6;
1295 buf[0][offset] |= (buf[0][offset] >> 2) & 3;
1296 buf[1][offset] |= (buf[1][offset] >> 2) & 3;
1297 break;
1298 case V4L2_PIX_FMT_SGRBG10:
1299 buf[0][offset] = odd ? r_y_h << 2 : g_u_s << 2;
1300 buf[0][offset + 1] = odd ? r_y_h >> 6 : g_u_s >> 6;
1301 buf[1][offset] = odd ? g_u_s << 2 : b_v << 2;
1302 buf[1][offset + 1] = odd ? g_u_s >> 6 : b_v >> 6;
1303 buf[0][offset] |= (buf[0][offset] >> 2) & 3;
1304 buf[1][offset] |= (buf[1][offset] >> 2) & 3;
1305 break;
1306 case V4L2_PIX_FMT_SRGGB10:
1307 buf[0][offset] = odd ? g_u_s << 2 : r_y_h << 2;
1308 buf[0][offset + 1] = odd ? g_u_s >> 6 : r_y_h >> 6;
1309 buf[1][offset] = odd ? b_v << 2 : g_u_s << 2;
1310 buf[1][offset + 1] = odd ? b_v >> 6 : g_u_s >> 6;
1311 buf[0][offset] |= (buf[0][offset] >> 2) & 3;
1312 buf[1][offset] |= (buf[1][offset] >> 2) & 3;
1313 break;
1314 case V4L2_PIX_FMT_SBGGR12:
1315 buf[0][offset] = odd ? g_u_s << 4 : b_v << 4;
1316 buf[0][offset + 1] = odd ? g_u_s >> 4 : b_v >> 4;
1317 buf[1][offset] = odd ? r_y_h << 4 : g_u_s << 4;
1318 buf[1][offset + 1] = odd ? r_y_h >> 4 : g_u_s >> 4;
1319 buf[0][offset] |= (buf[0][offset] >> 4) & 0xf;
1320 buf[1][offset] |= (buf[1][offset] >> 4) & 0xf;
1321 break;
1322 case V4L2_PIX_FMT_SGBRG12:
1323 buf[0][offset] = odd ? b_v << 4 : g_u_s << 4;
1324 buf[0][offset + 1] = odd ? b_v >> 4 : g_u_s >> 4;
1325 buf[1][offset] = odd ? g_u_s << 4 : r_y_h << 4;
1326 buf[1][offset + 1] = odd ? g_u_s >> 4 : r_y_h >> 4;
1327 buf[0][offset] |= (buf[0][offset] >> 4) & 0xf;
1328 buf[1][offset] |= (buf[1][offset] >> 4) & 0xf;
1329 break;
1330 case V4L2_PIX_FMT_SGRBG12:
1331 buf[0][offset] = odd ? r_y_h << 4 : g_u_s << 4;
1332 buf[0][offset + 1] = odd ? r_y_h >> 4 : g_u_s >> 4;
1333 buf[1][offset] = odd ? g_u_s << 4 : b_v << 4;
1334 buf[1][offset + 1] = odd ? g_u_s >> 4 : b_v >> 4;
1335 buf[0][offset] |= (buf[0][offset] >> 4) & 0xf;
1336 buf[1][offset] |= (buf[1][offset] >> 4) & 0xf;
1337 break;
1338 case V4L2_PIX_FMT_SRGGB12:
1339 buf[0][offset] = odd ? g_u_s << 4 : r_y_h << 4;
1340 buf[0][offset + 1] = odd ? g_u_s >> 4 : r_y_h >> 4;
1341 buf[1][offset] = odd ? b_v << 4 : g_u_s << 4;
1342 buf[1][offset + 1] = odd ? b_v >> 4 : g_u_s >> 4;
1343 buf[0][offset] |= (buf[0][offset] >> 4) & 0xf;
1344 buf[1][offset] |= (buf[1][offset] >> 4) & 0xf;
1345 break;
1349 unsigned tpg_g_interleaved_plane(const struct tpg_data *tpg, unsigned buf_line)
1351 switch (tpg->fourcc) {
1352 case V4L2_PIX_FMT_SBGGR8:
1353 case V4L2_PIX_FMT_SGBRG8:
1354 case V4L2_PIX_FMT_SGRBG8:
1355 case V4L2_PIX_FMT_SRGGB8:
1356 case V4L2_PIX_FMT_SBGGR10:
1357 case V4L2_PIX_FMT_SGBRG10:
1358 case V4L2_PIX_FMT_SGRBG10:
1359 case V4L2_PIX_FMT_SRGGB10:
1360 case V4L2_PIX_FMT_SBGGR12:
1361 case V4L2_PIX_FMT_SGBRG12:
1362 case V4L2_PIX_FMT_SGRBG12:
1363 case V4L2_PIX_FMT_SRGGB12:
1364 return buf_line & 1;
1365 default:
1366 return 0;
1369 EXPORT_SYMBOL_GPL(tpg_g_interleaved_plane);
1371 /* Return how many pattern lines are used by the current pattern. */
1372 static unsigned tpg_get_pat_lines(const struct tpg_data *tpg)
1374 switch (tpg->pattern) {
1375 case TPG_PAT_CHECKERS_16X16:
1376 case TPG_PAT_CHECKERS_2X2:
1377 case TPG_PAT_CHECKERS_1X1:
1378 case TPG_PAT_COLOR_CHECKERS_2X2:
1379 case TPG_PAT_COLOR_CHECKERS_1X1:
1380 case TPG_PAT_ALTERNATING_HLINES:
1381 case TPG_PAT_CROSS_1_PIXEL:
1382 case TPG_PAT_CROSS_2_PIXELS:
1383 case TPG_PAT_CROSS_10_PIXELS:
1384 return 2;
1385 case TPG_PAT_100_COLORSQUARES:
1386 case TPG_PAT_100_HCOLORBAR:
1387 return 8;
1388 default:
1389 return 1;
1393 /* Which pattern line should be used for the given frame line. */
1394 static unsigned tpg_get_pat_line(const struct tpg_data *tpg, unsigned line)
1396 switch (tpg->pattern) {
1397 case TPG_PAT_CHECKERS_16X16:
1398 return (line >> 4) & 1;
1399 case TPG_PAT_CHECKERS_1X1:
1400 case TPG_PAT_COLOR_CHECKERS_1X1:
1401 case TPG_PAT_ALTERNATING_HLINES:
1402 return line & 1;
1403 case TPG_PAT_CHECKERS_2X2:
1404 case TPG_PAT_COLOR_CHECKERS_2X2:
1405 return (line & 2) >> 1;
1406 case TPG_PAT_100_COLORSQUARES:
1407 case TPG_PAT_100_HCOLORBAR:
1408 return (line * 8) / tpg->src_height;
1409 case TPG_PAT_CROSS_1_PIXEL:
1410 return line == tpg->src_height / 2;
1411 case TPG_PAT_CROSS_2_PIXELS:
1412 return (line + 1) / 2 == tpg->src_height / 4;
1413 case TPG_PAT_CROSS_10_PIXELS:
1414 return (line + 10) / 20 == tpg->src_height / 40;
1415 default:
1416 return 0;
1421 * Which color should be used for the given pattern line and X coordinate.
1422 * Note: x is in the range 0 to 2 * tpg->src_width.
1424 static enum tpg_color tpg_get_color(const struct tpg_data *tpg,
1425 unsigned pat_line, unsigned x)
1427 /* Maximum number of bars are TPG_COLOR_MAX - otherwise, the input print code
1428 should be modified */
1429 static const enum tpg_color bars[3][8] = {
1430 /* Standard ITU-R 75% color bar sequence */
1431 { TPG_COLOR_CSC_WHITE, TPG_COLOR_75_YELLOW,
1432 TPG_COLOR_75_CYAN, TPG_COLOR_75_GREEN,
1433 TPG_COLOR_75_MAGENTA, TPG_COLOR_75_RED,
1434 TPG_COLOR_75_BLUE, TPG_COLOR_100_BLACK, },
1435 /* Standard ITU-R 100% color bar sequence */
1436 { TPG_COLOR_100_WHITE, TPG_COLOR_100_YELLOW,
1437 TPG_COLOR_100_CYAN, TPG_COLOR_100_GREEN,
1438 TPG_COLOR_100_MAGENTA, TPG_COLOR_100_RED,
1439 TPG_COLOR_100_BLUE, TPG_COLOR_100_BLACK, },
1440 /* Color bar sequence suitable to test CSC */
1441 { TPG_COLOR_CSC_WHITE, TPG_COLOR_CSC_YELLOW,
1442 TPG_COLOR_CSC_CYAN, TPG_COLOR_CSC_GREEN,
1443 TPG_COLOR_CSC_MAGENTA, TPG_COLOR_CSC_RED,
1444 TPG_COLOR_CSC_BLUE, TPG_COLOR_CSC_BLACK, },
1447 switch (tpg->pattern) {
1448 case TPG_PAT_75_COLORBAR:
1449 case TPG_PAT_100_COLORBAR:
1450 case TPG_PAT_CSC_COLORBAR:
1451 return bars[tpg->pattern][((x * 8) / tpg->src_width) % 8];
1452 case TPG_PAT_100_COLORSQUARES:
1453 return bars[1][(pat_line + (x * 8) / tpg->src_width) % 8];
1454 case TPG_PAT_100_HCOLORBAR:
1455 return bars[1][pat_line];
1456 case TPG_PAT_BLACK:
1457 return TPG_COLOR_100_BLACK;
1458 case TPG_PAT_WHITE:
1459 return TPG_COLOR_100_WHITE;
1460 case TPG_PAT_RED:
1461 return TPG_COLOR_100_RED;
1462 case TPG_PAT_GREEN:
1463 return TPG_COLOR_100_GREEN;
1464 case TPG_PAT_BLUE:
1465 return TPG_COLOR_100_BLUE;
1466 case TPG_PAT_CHECKERS_16X16:
1467 return (((x >> 4) & 1) ^ (pat_line & 1)) ?
1468 TPG_COLOR_100_BLACK : TPG_COLOR_100_WHITE;
1469 case TPG_PAT_CHECKERS_1X1:
1470 return ((x & 1) ^ (pat_line & 1)) ?
1471 TPG_COLOR_100_WHITE : TPG_COLOR_100_BLACK;
1472 case TPG_PAT_COLOR_CHECKERS_1X1:
1473 return ((x & 1) ^ (pat_line & 1)) ?
1474 TPG_COLOR_100_RED : TPG_COLOR_100_BLUE;
1475 case TPG_PAT_CHECKERS_2X2:
1476 return (((x >> 1) & 1) ^ (pat_line & 1)) ?
1477 TPG_COLOR_100_WHITE : TPG_COLOR_100_BLACK;
1478 case TPG_PAT_COLOR_CHECKERS_2X2:
1479 return (((x >> 1) & 1) ^ (pat_line & 1)) ?
1480 TPG_COLOR_100_RED : TPG_COLOR_100_BLUE;
1481 case TPG_PAT_ALTERNATING_HLINES:
1482 return pat_line ? TPG_COLOR_100_WHITE : TPG_COLOR_100_BLACK;
1483 case TPG_PAT_ALTERNATING_VLINES:
1484 return (x & 1) ? TPG_COLOR_100_WHITE : TPG_COLOR_100_BLACK;
1485 case TPG_PAT_CROSS_1_PIXEL:
1486 if (pat_line || (x % tpg->src_width) == tpg->src_width / 2)
1487 return TPG_COLOR_100_BLACK;
1488 return TPG_COLOR_100_WHITE;
1489 case TPG_PAT_CROSS_2_PIXELS:
1490 if (pat_line || ((x % tpg->src_width) + 1) / 2 == tpg->src_width / 4)
1491 return TPG_COLOR_100_BLACK;
1492 return TPG_COLOR_100_WHITE;
1493 case TPG_PAT_CROSS_10_PIXELS:
1494 if (pat_line || ((x % tpg->src_width) + 10) / 20 == tpg->src_width / 40)
1495 return TPG_COLOR_100_BLACK;
1496 return TPG_COLOR_100_WHITE;
1497 case TPG_PAT_GRAY_RAMP:
1498 return TPG_COLOR_RAMP + ((x % tpg->src_width) * 256) / tpg->src_width;
1499 default:
1500 return TPG_COLOR_100_RED;
1505 * Given the pixel aspect ratio and video aspect ratio calculate the
1506 * coordinates of a centered square and the coordinates of the border of
1507 * the active video area. The coordinates are relative to the source
1508 * frame rectangle.
1510 static void tpg_calculate_square_border(struct tpg_data *tpg)
1512 unsigned w = tpg->src_width;
1513 unsigned h = tpg->src_height;
1514 unsigned sq_w, sq_h;
1516 sq_w = (w * 2 / 5) & ~1;
1517 if (((w - sq_w) / 2) & 1)
1518 sq_w += 2;
1519 sq_h = sq_w;
1520 tpg->square.width = sq_w;
1521 if (tpg->vid_aspect == TPG_VIDEO_ASPECT_16X9_ANAMORPHIC) {
1522 unsigned ana_sq_w = (sq_w / 4) * 3;
1524 if (((w - ana_sq_w) / 2) & 1)
1525 ana_sq_w += 2;
1526 tpg->square.width = ana_sq_w;
1528 tpg->square.left = (w - tpg->square.width) / 2;
1529 if (tpg->pix_aspect == TPG_PIXEL_ASPECT_NTSC)
1530 sq_h = sq_w * 10 / 11;
1531 else if (tpg->pix_aspect == TPG_PIXEL_ASPECT_PAL)
1532 sq_h = sq_w * 59 / 54;
1533 tpg->square.height = sq_h;
1534 tpg->square.top = (h - sq_h) / 2;
1535 tpg->border.left = 0;
1536 tpg->border.width = w;
1537 tpg->border.top = 0;
1538 tpg->border.height = h;
1539 switch (tpg->vid_aspect) {
1540 case TPG_VIDEO_ASPECT_4X3:
1541 if (tpg->pix_aspect)
1542 return;
1543 if (3 * w >= 4 * h) {
1544 tpg->border.width = ((4 * h) / 3) & ~1;
1545 if (((w - tpg->border.width) / 2) & ~1)
1546 tpg->border.width -= 2;
1547 tpg->border.left = (w - tpg->border.width) / 2;
1548 break;
1550 tpg->border.height = ((3 * w) / 4) & ~1;
1551 tpg->border.top = (h - tpg->border.height) / 2;
1552 break;
1553 case TPG_VIDEO_ASPECT_14X9_CENTRE:
1554 if (tpg->pix_aspect) {
1555 tpg->border.height = tpg->pix_aspect == TPG_PIXEL_ASPECT_NTSC ? 420 : 506;
1556 tpg->border.top = (h - tpg->border.height) / 2;
1557 break;
1559 if (9 * w >= 14 * h) {
1560 tpg->border.width = ((14 * h) / 9) & ~1;
1561 if (((w - tpg->border.width) / 2) & ~1)
1562 tpg->border.width -= 2;
1563 tpg->border.left = (w - tpg->border.width) / 2;
1564 break;
1566 tpg->border.height = ((9 * w) / 14) & ~1;
1567 tpg->border.top = (h - tpg->border.height) / 2;
1568 break;
1569 case TPG_VIDEO_ASPECT_16X9_CENTRE:
1570 if (tpg->pix_aspect) {
1571 tpg->border.height = tpg->pix_aspect == TPG_PIXEL_ASPECT_NTSC ? 368 : 442;
1572 tpg->border.top = (h - tpg->border.height) / 2;
1573 break;
1575 if (9 * w >= 16 * h) {
1576 tpg->border.width = ((16 * h) / 9) & ~1;
1577 if (((w - tpg->border.width) / 2) & ~1)
1578 tpg->border.width -= 2;
1579 tpg->border.left = (w - tpg->border.width) / 2;
1580 break;
1582 tpg->border.height = ((9 * w) / 16) & ~1;
1583 tpg->border.top = (h - tpg->border.height) / 2;
1584 break;
1585 default:
1586 break;
1590 static void tpg_precalculate_line(struct tpg_data *tpg)
1592 enum tpg_color contrast;
1593 u8 pix[TPG_MAX_PLANES][8];
1594 unsigned pat;
1595 unsigned p;
1596 unsigned x;
1598 switch (tpg->pattern) {
1599 case TPG_PAT_GREEN:
1600 contrast = TPG_COLOR_100_RED;
1601 break;
1602 case TPG_PAT_CSC_COLORBAR:
1603 contrast = TPG_COLOR_CSC_GREEN;
1604 break;
1605 default:
1606 contrast = TPG_COLOR_100_GREEN;
1607 break;
1610 for (pat = 0; pat < tpg_get_pat_lines(tpg); pat++) {
1611 /* Coarse scaling with Bresenham */
1612 unsigned int_part = tpg->src_width / tpg->scaled_width;
1613 unsigned fract_part = tpg->src_width % tpg->scaled_width;
1614 unsigned src_x = 0;
1615 unsigned error = 0;
1617 for (x = 0; x < tpg->scaled_width * 2; x += 2) {
1618 unsigned real_x = src_x;
1619 enum tpg_color color1, color2;
1621 real_x = tpg->hflip ? tpg->src_width * 2 - real_x - 2 : real_x;
1622 color1 = tpg_get_color(tpg, pat, real_x);
1624 src_x += int_part;
1625 error += fract_part;
1626 if (error >= tpg->scaled_width) {
1627 error -= tpg->scaled_width;
1628 src_x++;
1631 real_x = src_x;
1632 real_x = tpg->hflip ? tpg->src_width * 2 - real_x - 2 : real_x;
1633 color2 = tpg_get_color(tpg, pat, real_x);
1635 src_x += int_part;
1636 error += fract_part;
1637 if (error >= tpg->scaled_width) {
1638 error -= tpg->scaled_width;
1639 src_x++;
1642 gen_twopix(tpg, pix, tpg->hflip ? color2 : color1, 0);
1643 gen_twopix(tpg, pix, tpg->hflip ? color1 : color2, 1);
1644 for (p = 0; p < tpg->planes; p++) {
1645 unsigned twopixsize = tpg->twopixelsize[p];
1646 unsigned hdiv = tpg->hdownsampling[p];
1647 u8 *pos = tpg->lines[pat][p] + tpg_hdiv(tpg, p, x);
1649 memcpy(pos, pix[p], twopixsize / hdiv);
1654 if (tpg->vdownsampling[tpg->planes - 1] > 1) {
1655 unsigned pat_lines = tpg_get_pat_lines(tpg);
1657 for (pat = 0; pat < pat_lines; pat++) {
1658 unsigned next_pat = (pat + 1) % pat_lines;
1660 for (p = 1; p < tpg->planes; p++) {
1661 unsigned w = tpg_hdiv(tpg, p, tpg->scaled_width * 2);
1662 u8 *pos1 = tpg->lines[pat][p];
1663 u8 *pos2 = tpg->lines[next_pat][p];
1664 u8 *dest = tpg->downsampled_lines[pat][p];
1666 for (x = 0; x < w; x++, pos1++, pos2++, dest++)
1667 *dest = ((u16)*pos1 + (u16)*pos2) / 2;
1672 gen_twopix(tpg, pix, contrast, 0);
1673 gen_twopix(tpg, pix, contrast, 1);
1674 for (p = 0; p < tpg->planes; p++) {
1675 unsigned twopixsize = tpg->twopixelsize[p];
1676 u8 *pos = tpg->contrast_line[p];
1678 for (x = 0; x < tpg->scaled_width; x += 2, pos += twopixsize)
1679 memcpy(pos, pix[p], twopixsize);
1682 gen_twopix(tpg, pix, TPG_COLOR_100_BLACK, 0);
1683 gen_twopix(tpg, pix, TPG_COLOR_100_BLACK, 1);
1684 for (p = 0; p < tpg->planes; p++) {
1685 unsigned twopixsize = tpg->twopixelsize[p];
1686 u8 *pos = tpg->black_line[p];
1688 for (x = 0; x < tpg->scaled_width; x += 2, pos += twopixsize)
1689 memcpy(pos, pix[p], twopixsize);
1692 for (x = 0; x < tpg->scaled_width * 2; x += 2) {
1693 gen_twopix(tpg, pix, TPG_COLOR_RANDOM, 0);
1694 gen_twopix(tpg, pix, TPG_COLOR_RANDOM, 1);
1695 for (p = 0; p < tpg->planes; p++) {
1696 unsigned twopixsize = tpg->twopixelsize[p];
1697 u8 *pos = tpg->random_line[p] + x * twopixsize / 2;
1699 memcpy(pos, pix[p], twopixsize);
1703 gen_twopix(tpg, tpg->textbg, TPG_COLOR_TEXTBG, 0);
1704 gen_twopix(tpg, tpg->textbg, TPG_COLOR_TEXTBG, 1);
1705 gen_twopix(tpg, tpg->textfg, TPG_COLOR_TEXTFG, 0);
1706 gen_twopix(tpg, tpg->textfg, TPG_COLOR_TEXTFG, 1);
1709 /* need this to do rgb24 rendering */
1710 typedef struct { u16 __; u8 _; } __packed x24;
1712 #define PRINTSTR(PIXTYPE) do { \
1713 unsigned vdiv = tpg->vdownsampling[p]; \
1714 unsigned hdiv = tpg->hdownsampling[p]; \
1715 int line; \
1716 PIXTYPE fg; \
1717 PIXTYPE bg; \
1718 memcpy(&fg, tpg->textfg[p], sizeof(PIXTYPE)); \
1719 memcpy(&bg, tpg->textbg[p], sizeof(PIXTYPE)); \
1721 for (line = first; line < 16; line += vdiv * step) { \
1722 int l = tpg->vflip ? 15 - line : line; \
1723 PIXTYPE *pos = (PIXTYPE *)(basep[p][(line / vdiv) & 1] + \
1724 ((y * step + l) / (vdiv * div)) * tpg->bytesperline[p] + \
1725 (x / hdiv) * sizeof(PIXTYPE)); \
1726 unsigned s; \
1728 for (s = 0; s < len; s++) { \
1729 u8 chr = font8x16[text[s] * 16 + line]; \
1731 if (hdiv == 2 && tpg->hflip) { \
1732 pos[3] = (chr & (0x01 << 6) ? fg : bg); \
1733 pos[2] = (chr & (0x01 << 4) ? fg : bg); \
1734 pos[1] = (chr & (0x01 << 2) ? fg : bg); \
1735 pos[0] = (chr & (0x01 << 0) ? fg : bg); \
1736 } else if (hdiv == 2) { \
1737 pos[0] = (chr & (0x01 << 7) ? fg : bg); \
1738 pos[1] = (chr & (0x01 << 5) ? fg : bg); \
1739 pos[2] = (chr & (0x01 << 3) ? fg : bg); \
1740 pos[3] = (chr & (0x01 << 1) ? fg : bg); \
1741 } else if (tpg->hflip) { \
1742 pos[7] = (chr & (0x01 << 7) ? fg : bg); \
1743 pos[6] = (chr & (0x01 << 6) ? fg : bg); \
1744 pos[5] = (chr & (0x01 << 5) ? fg : bg); \
1745 pos[4] = (chr & (0x01 << 4) ? fg : bg); \
1746 pos[3] = (chr & (0x01 << 3) ? fg : bg); \
1747 pos[2] = (chr & (0x01 << 2) ? fg : bg); \
1748 pos[1] = (chr & (0x01 << 1) ? fg : bg); \
1749 pos[0] = (chr & (0x01 << 0) ? fg : bg); \
1750 } else { \
1751 pos[0] = (chr & (0x01 << 7) ? fg : bg); \
1752 pos[1] = (chr & (0x01 << 6) ? fg : bg); \
1753 pos[2] = (chr & (0x01 << 5) ? fg : bg); \
1754 pos[3] = (chr & (0x01 << 4) ? fg : bg); \
1755 pos[4] = (chr & (0x01 << 3) ? fg : bg); \
1756 pos[5] = (chr & (0x01 << 2) ? fg : bg); \
1757 pos[6] = (chr & (0x01 << 1) ? fg : bg); \
1758 pos[7] = (chr & (0x01 << 0) ? fg : bg); \
1761 pos += (tpg->hflip ? -8 : 8) / hdiv; \
1764 } while (0)
1766 static noinline void tpg_print_str_2(const struct tpg_data *tpg, u8 *basep[TPG_MAX_PLANES][2],
1767 unsigned p, unsigned first, unsigned div, unsigned step,
1768 int y, int x, char *text, unsigned len)
1770 PRINTSTR(u8);
1773 static noinline void tpg_print_str_4(const struct tpg_data *tpg, u8 *basep[TPG_MAX_PLANES][2],
1774 unsigned p, unsigned first, unsigned div, unsigned step,
1775 int y, int x, char *text, unsigned len)
1777 PRINTSTR(u16);
1780 static noinline void tpg_print_str_6(const struct tpg_data *tpg, u8 *basep[TPG_MAX_PLANES][2],
1781 unsigned p, unsigned first, unsigned div, unsigned step,
1782 int y, int x, char *text, unsigned len)
1784 PRINTSTR(x24);
1787 static noinline void tpg_print_str_8(const struct tpg_data *tpg, u8 *basep[TPG_MAX_PLANES][2],
1788 unsigned p, unsigned first, unsigned div, unsigned step,
1789 int y, int x, char *text, unsigned len)
1791 PRINTSTR(u32);
1794 void tpg_gen_text(const struct tpg_data *tpg, u8 *basep[TPG_MAX_PLANES][2],
1795 int y, int x, char *text)
1797 unsigned step = V4L2_FIELD_HAS_T_OR_B(tpg->field) ? 2 : 1;
1798 unsigned div = step;
1799 unsigned first = 0;
1800 unsigned len = strlen(text);
1801 unsigned p;
1803 if (font8x16 == NULL || basep == NULL)
1804 return;
1806 /* Checks if it is possible to show string */
1807 if (y + 16 >= tpg->compose.height || x + 8 >= tpg->compose.width)
1808 return;
1810 if (len > (tpg->compose.width - x) / 8)
1811 len = (tpg->compose.width - x) / 8;
1812 if (tpg->vflip)
1813 y = tpg->compose.height - y - 16;
1814 if (tpg->hflip)
1815 x = tpg->compose.width - x - 8;
1816 y += tpg->compose.top;
1817 x += tpg->compose.left;
1818 if (tpg->field == V4L2_FIELD_BOTTOM)
1819 first = 1;
1820 else if (tpg->field == V4L2_FIELD_SEQ_TB || tpg->field == V4L2_FIELD_SEQ_BT)
1821 div = 2;
1823 for (p = 0; p < tpg->planes; p++) {
1824 /* Print text */
1825 switch (tpg->twopixelsize[p]) {
1826 case 2:
1827 tpg_print_str_2(tpg, basep, p, first, div, step, y, x,
1828 text, len);
1829 break;
1830 case 4:
1831 tpg_print_str_4(tpg, basep, p, first, div, step, y, x,
1832 text, len);
1833 break;
1834 case 6:
1835 tpg_print_str_6(tpg, basep, p, first, div, step, y, x,
1836 text, len);
1837 break;
1838 case 8:
1839 tpg_print_str_8(tpg, basep, p, first, div, step, y, x,
1840 text, len);
1841 break;
1845 EXPORT_SYMBOL_GPL(tpg_gen_text);
1847 void tpg_update_mv_step(struct tpg_data *tpg)
1849 int factor = tpg->mv_hor_mode > TPG_MOVE_NONE ? -1 : 1;
1851 if (tpg->hflip)
1852 factor = -factor;
1853 switch (tpg->mv_hor_mode) {
1854 case TPG_MOVE_NEG_FAST:
1855 case TPG_MOVE_POS_FAST:
1856 tpg->mv_hor_step = ((tpg->src_width + 319) / 320) * 4;
1857 break;
1858 case TPG_MOVE_NEG:
1859 case TPG_MOVE_POS:
1860 tpg->mv_hor_step = ((tpg->src_width + 639) / 640) * 4;
1861 break;
1862 case TPG_MOVE_NEG_SLOW:
1863 case TPG_MOVE_POS_SLOW:
1864 tpg->mv_hor_step = 2;
1865 break;
1866 case TPG_MOVE_NONE:
1867 tpg->mv_hor_step = 0;
1868 break;
1870 if (factor < 0)
1871 tpg->mv_hor_step = tpg->src_width - tpg->mv_hor_step;
1873 factor = tpg->mv_vert_mode > TPG_MOVE_NONE ? -1 : 1;
1874 switch (tpg->mv_vert_mode) {
1875 case TPG_MOVE_NEG_FAST:
1876 case TPG_MOVE_POS_FAST:
1877 tpg->mv_vert_step = ((tpg->src_width + 319) / 320) * 4;
1878 break;
1879 case TPG_MOVE_NEG:
1880 case TPG_MOVE_POS:
1881 tpg->mv_vert_step = ((tpg->src_width + 639) / 640) * 4;
1882 break;
1883 case TPG_MOVE_NEG_SLOW:
1884 case TPG_MOVE_POS_SLOW:
1885 tpg->mv_vert_step = 1;
1886 break;
1887 case TPG_MOVE_NONE:
1888 tpg->mv_vert_step = 0;
1889 break;
1891 if (factor < 0)
1892 tpg->mv_vert_step = tpg->src_height - tpg->mv_vert_step;
1894 EXPORT_SYMBOL_GPL(tpg_update_mv_step);
1896 /* Map the line number relative to the crop rectangle to a frame line number */
1897 static unsigned tpg_calc_frameline(const struct tpg_data *tpg, unsigned src_y,
1898 unsigned field)
1900 switch (field) {
1901 case V4L2_FIELD_TOP:
1902 return tpg->crop.top + src_y * 2;
1903 case V4L2_FIELD_BOTTOM:
1904 return tpg->crop.top + src_y * 2 + 1;
1905 default:
1906 return src_y + tpg->crop.top;
1911 * Map the line number relative to the compose rectangle to a destination
1912 * buffer line number.
1914 static unsigned tpg_calc_buffer_line(const struct tpg_data *tpg, unsigned y,
1915 unsigned field)
1917 y += tpg->compose.top;
1918 switch (field) {
1919 case V4L2_FIELD_SEQ_TB:
1920 if (y & 1)
1921 return tpg->buf_height / 2 + y / 2;
1922 return y / 2;
1923 case V4L2_FIELD_SEQ_BT:
1924 if (y & 1)
1925 return y / 2;
1926 return tpg->buf_height / 2 + y / 2;
1927 default:
1928 return y;
1932 static void tpg_recalc(struct tpg_data *tpg)
1934 if (tpg->recalc_colors) {
1935 tpg->recalc_colors = false;
1936 tpg->recalc_lines = true;
1937 tpg->real_xfer_func = tpg->xfer_func;
1938 tpg->real_ycbcr_enc = tpg->ycbcr_enc;
1939 tpg->real_hsv_enc = tpg->hsv_enc;
1940 tpg->real_quantization = tpg->quantization;
1942 if (tpg->xfer_func == V4L2_XFER_FUNC_DEFAULT)
1943 tpg->real_xfer_func =
1944 V4L2_MAP_XFER_FUNC_DEFAULT(tpg->colorspace);
1946 if (tpg->ycbcr_enc == V4L2_YCBCR_ENC_DEFAULT)
1947 tpg->real_ycbcr_enc =
1948 V4L2_MAP_YCBCR_ENC_DEFAULT(tpg->colorspace);
1950 if (tpg->quantization == V4L2_QUANTIZATION_DEFAULT)
1951 tpg->real_quantization =
1952 V4L2_MAP_QUANTIZATION_DEFAULT(
1953 tpg->color_enc != TGP_COLOR_ENC_YCBCR,
1954 tpg->colorspace, tpg->real_ycbcr_enc);
1956 tpg_precalculate_colors(tpg);
1958 if (tpg->recalc_square_border) {
1959 tpg->recalc_square_border = false;
1960 tpg_calculate_square_border(tpg);
1962 if (tpg->recalc_lines) {
1963 tpg->recalc_lines = false;
1964 tpg_precalculate_line(tpg);
1968 void tpg_calc_text_basep(struct tpg_data *tpg,
1969 u8 *basep[TPG_MAX_PLANES][2], unsigned p, u8 *vbuf)
1971 unsigned stride = tpg->bytesperline[p];
1972 unsigned h = tpg->buf_height;
1974 tpg_recalc(tpg);
1976 basep[p][0] = vbuf;
1977 basep[p][1] = vbuf;
1978 h /= tpg->vdownsampling[p];
1979 if (tpg->field == V4L2_FIELD_SEQ_TB)
1980 basep[p][1] += h * stride / 2;
1981 else if (tpg->field == V4L2_FIELD_SEQ_BT)
1982 basep[p][0] += h * stride / 2;
1983 if (p == 0 && tpg->interleaved)
1984 tpg_calc_text_basep(tpg, basep, 1, vbuf);
1986 EXPORT_SYMBOL_GPL(tpg_calc_text_basep);
1988 static int tpg_pattern_avg(const struct tpg_data *tpg,
1989 unsigned pat1, unsigned pat2)
1991 unsigned pat_lines = tpg_get_pat_lines(tpg);
1993 if (pat1 == (pat2 + 1) % pat_lines)
1994 return pat2;
1995 if (pat2 == (pat1 + 1) % pat_lines)
1996 return pat1;
1997 return -1;
2000 static const char *tpg_color_enc_str(enum tgp_color_enc
2001 color_enc)
2003 switch (color_enc) {
2004 case TGP_COLOR_ENC_HSV:
2005 return "HSV";
2006 case TGP_COLOR_ENC_YCBCR:
2007 return "Y'CbCr";
2008 case TGP_COLOR_ENC_LUMA:
2009 return "Luma";
2010 case TGP_COLOR_ENC_RGB:
2011 default:
2012 return "R'G'B";
2017 void tpg_log_status(struct tpg_data *tpg)
2019 pr_info("tpg source WxH: %ux%u (%s)\n",
2020 tpg->src_width, tpg->src_height,
2021 tpg_color_enc_str(tpg->color_enc));
2022 pr_info("tpg field: %u\n", tpg->field);
2023 pr_info("tpg crop: %ux%u@%dx%d\n", tpg->crop.width, tpg->crop.height,
2024 tpg->crop.left, tpg->crop.top);
2025 pr_info("tpg compose: %ux%u@%dx%d\n", tpg->compose.width, tpg->compose.height,
2026 tpg->compose.left, tpg->compose.top);
2027 pr_info("tpg colorspace: %d\n", tpg->colorspace);
2028 pr_info("tpg transfer function: %d/%d\n", tpg->xfer_func, tpg->real_xfer_func);
2029 pr_info("tpg Y'CbCr encoding: %d/%d\n", tpg->ycbcr_enc, tpg->real_ycbcr_enc);
2030 pr_info("tpg HSV encoding: %d/%d\n", tpg->hsv_enc, tpg->real_hsv_enc);
2031 pr_info("tpg quantization: %d/%d\n", tpg->quantization, tpg->real_quantization);
2032 pr_info("tpg RGB range: %d/%d\n", tpg->rgb_range, tpg->real_rgb_range);
2034 EXPORT_SYMBOL_GPL(tpg_log_status);
2037 * This struct contains common parameters used by both the drawing of the
2038 * test pattern and the drawing of the extras (borders, square, etc.)
2040 struct tpg_draw_params {
2041 /* common data */
2042 bool is_tv;
2043 bool is_60hz;
2044 unsigned twopixsize;
2045 unsigned img_width;
2046 unsigned stride;
2047 unsigned hmax;
2048 unsigned frame_line;
2049 unsigned frame_line_next;
2051 /* test pattern */
2052 unsigned mv_hor_old;
2053 unsigned mv_hor_new;
2054 unsigned mv_vert_old;
2055 unsigned mv_vert_new;
2057 /* extras */
2058 unsigned wss_width;
2059 unsigned wss_random_offset;
2060 unsigned sav_eav_f;
2061 unsigned left_pillar_width;
2062 unsigned right_pillar_start;
2065 static void tpg_fill_params_pattern(const struct tpg_data *tpg, unsigned p,
2066 struct tpg_draw_params *params)
2068 params->mv_hor_old =
2069 tpg_hscale_div(tpg, p, tpg->mv_hor_count % tpg->src_width);
2070 params->mv_hor_new =
2071 tpg_hscale_div(tpg, p, (tpg->mv_hor_count + tpg->mv_hor_step) %
2072 tpg->src_width);
2073 params->mv_vert_old = tpg->mv_vert_count % tpg->src_height;
2074 params->mv_vert_new =
2075 (tpg->mv_vert_count + tpg->mv_vert_step) % tpg->src_height;
2078 static void tpg_fill_params_extras(const struct tpg_data *tpg,
2079 unsigned p,
2080 struct tpg_draw_params *params)
2082 unsigned left_pillar_width = 0;
2083 unsigned right_pillar_start = params->img_width;
2085 params->wss_width = tpg->crop.left < tpg->src_width / 2 ?
2086 tpg->src_width / 2 - tpg->crop.left : 0;
2087 if (params->wss_width > tpg->crop.width)
2088 params->wss_width = tpg->crop.width;
2089 params->wss_width = tpg_hscale_div(tpg, p, params->wss_width);
2090 params->wss_random_offset =
2091 params->twopixsize * prandom_u32_max(tpg->src_width / 2);
2093 if (tpg->crop.left < tpg->border.left) {
2094 left_pillar_width = tpg->border.left - tpg->crop.left;
2095 if (left_pillar_width > tpg->crop.width)
2096 left_pillar_width = tpg->crop.width;
2097 left_pillar_width = tpg_hscale_div(tpg, p, left_pillar_width);
2099 params->left_pillar_width = left_pillar_width;
2101 if (tpg->crop.left + tpg->crop.width >
2102 tpg->border.left + tpg->border.width) {
2103 right_pillar_start =
2104 tpg->border.left + tpg->border.width - tpg->crop.left;
2105 right_pillar_start =
2106 tpg_hscale_div(tpg, p, right_pillar_start);
2107 if (right_pillar_start > params->img_width)
2108 right_pillar_start = params->img_width;
2110 params->right_pillar_start = right_pillar_start;
2112 params->sav_eav_f = tpg->field ==
2113 (params->is_60hz ? V4L2_FIELD_TOP : V4L2_FIELD_BOTTOM);
2116 static void tpg_fill_plane_extras(const struct tpg_data *tpg,
2117 const struct tpg_draw_params *params,
2118 unsigned p, unsigned h, u8 *vbuf)
2120 unsigned twopixsize = params->twopixsize;
2121 unsigned img_width = params->img_width;
2122 unsigned frame_line = params->frame_line;
2123 const struct v4l2_rect *sq = &tpg->square;
2124 const struct v4l2_rect *b = &tpg->border;
2125 const struct v4l2_rect *c = &tpg->crop;
2127 if (params->is_tv && !params->is_60hz &&
2128 frame_line == 0 && params->wss_width) {
2130 * Replace the first half of the top line of a 50 Hz frame
2131 * with random data to simulate a WSS signal.
2133 u8 *wss = tpg->random_line[p] + params->wss_random_offset;
2135 memcpy(vbuf, wss, params->wss_width);
2138 if (tpg->show_border && frame_line >= b->top &&
2139 frame_line < b->top + b->height) {
2140 unsigned bottom = b->top + b->height - 1;
2141 unsigned left = params->left_pillar_width;
2142 unsigned right = params->right_pillar_start;
2144 if (frame_line == b->top || frame_line == b->top + 1 ||
2145 frame_line == bottom || frame_line == bottom - 1) {
2146 memcpy(vbuf + left, tpg->contrast_line[p],
2147 right - left);
2148 } else {
2149 if (b->left >= c->left &&
2150 b->left < c->left + c->width)
2151 memcpy(vbuf + left,
2152 tpg->contrast_line[p], twopixsize);
2153 if (b->left + b->width > c->left &&
2154 b->left + b->width <= c->left + c->width)
2155 memcpy(vbuf + right - twopixsize,
2156 tpg->contrast_line[p], twopixsize);
2159 if (tpg->qual != TPG_QUAL_NOISE && frame_line >= b->top &&
2160 frame_line < b->top + b->height) {
2161 memcpy(vbuf, tpg->black_line[p], params->left_pillar_width);
2162 memcpy(vbuf + params->right_pillar_start, tpg->black_line[p],
2163 img_width - params->right_pillar_start);
2165 if (tpg->show_square && frame_line >= sq->top &&
2166 frame_line < sq->top + sq->height &&
2167 sq->left < c->left + c->width &&
2168 sq->left + sq->width >= c->left) {
2169 unsigned left = sq->left;
2170 unsigned width = sq->width;
2172 if (c->left > left) {
2173 width -= c->left - left;
2174 left = c->left;
2176 if (c->left + c->width < left + width)
2177 width -= left + width - c->left - c->width;
2178 left -= c->left;
2179 left = tpg_hscale_div(tpg, p, left);
2180 width = tpg_hscale_div(tpg, p, width);
2181 memcpy(vbuf + left, tpg->contrast_line[p], width);
2183 if (tpg->insert_sav) {
2184 unsigned offset = tpg_hdiv(tpg, p, tpg->compose.width / 3);
2185 u8 *p = vbuf + offset;
2186 unsigned vact = 0, hact = 0;
2188 p[0] = 0xff;
2189 p[1] = 0;
2190 p[2] = 0;
2191 p[3] = 0x80 | (params->sav_eav_f << 6) |
2192 (vact << 5) | (hact << 4) |
2193 ((hact ^ vact) << 3) |
2194 ((hact ^ params->sav_eav_f) << 2) |
2195 ((params->sav_eav_f ^ vact) << 1) |
2196 (hact ^ vact ^ params->sav_eav_f);
2198 if (tpg->insert_eav) {
2199 unsigned offset = tpg_hdiv(tpg, p, tpg->compose.width * 2 / 3);
2200 u8 *p = vbuf + offset;
2201 unsigned vact = 0, hact = 1;
2203 p[0] = 0xff;
2204 p[1] = 0;
2205 p[2] = 0;
2206 p[3] = 0x80 | (params->sav_eav_f << 6) |
2207 (vact << 5) | (hact << 4) |
2208 ((hact ^ vact) << 3) |
2209 ((hact ^ params->sav_eav_f) << 2) |
2210 ((params->sav_eav_f ^ vact) << 1) |
2211 (hact ^ vact ^ params->sav_eav_f);
2215 static void tpg_fill_plane_pattern(const struct tpg_data *tpg,
2216 const struct tpg_draw_params *params,
2217 unsigned p, unsigned h, u8 *vbuf)
2219 unsigned twopixsize = params->twopixsize;
2220 unsigned img_width = params->img_width;
2221 unsigned mv_hor_old = params->mv_hor_old;
2222 unsigned mv_hor_new = params->mv_hor_new;
2223 unsigned mv_vert_old = params->mv_vert_old;
2224 unsigned mv_vert_new = params->mv_vert_new;
2225 unsigned frame_line = params->frame_line;
2226 unsigned frame_line_next = params->frame_line_next;
2227 unsigned line_offset = tpg_hscale_div(tpg, p, tpg->crop.left);
2228 bool even;
2229 bool fill_blank = false;
2230 unsigned pat_line_old;
2231 unsigned pat_line_new;
2232 u8 *linestart_older;
2233 u8 *linestart_newer;
2234 u8 *linestart_top;
2235 u8 *linestart_bottom;
2237 even = !(frame_line & 1);
2239 if (h >= params->hmax) {
2240 if (params->hmax == tpg->compose.height)
2241 return;
2242 if (!tpg->perc_fill_blank)
2243 return;
2244 fill_blank = true;
2247 if (tpg->vflip) {
2248 frame_line = tpg->src_height - frame_line - 1;
2249 frame_line_next = tpg->src_height - frame_line_next - 1;
2252 if (fill_blank) {
2253 linestart_older = tpg->contrast_line[p];
2254 linestart_newer = tpg->contrast_line[p];
2255 } else if (tpg->qual != TPG_QUAL_NOISE &&
2256 (frame_line < tpg->border.top ||
2257 frame_line >= tpg->border.top + tpg->border.height)) {
2258 linestart_older = tpg->black_line[p];
2259 linestart_newer = tpg->black_line[p];
2260 } else if (tpg->pattern == TPG_PAT_NOISE || tpg->qual == TPG_QUAL_NOISE) {
2261 linestart_older = tpg->random_line[p] +
2262 twopixsize * prandom_u32_max(tpg->src_width / 2);
2263 linestart_newer = tpg->random_line[p] +
2264 twopixsize * prandom_u32_max(tpg->src_width / 2);
2265 } else {
2266 unsigned frame_line_old =
2267 (frame_line + mv_vert_old) % tpg->src_height;
2268 unsigned frame_line_new =
2269 (frame_line + mv_vert_new) % tpg->src_height;
2270 unsigned pat_line_next_old;
2271 unsigned pat_line_next_new;
2273 pat_line_old = tpg_get_pat_line(tpg, frame_line_old);
2274 pat_line_new = tpg_get_pat_line(tpg, frame_line_new);
2275 linestart_older = tpg->lines[pat_line_old][p] + mv_hor_old;
2276 linestart_newer = tpg->lines[pat_line_new][p] + mv_hor_new;
2278 if (tpg->vdownsampling[p] > 1 && frame_line != frame_line_next) {
2279 int avg_pat;
2282 * Now decide whether we need to use downsampled_lines[].
2283 * That's necessary if the two lines use different patterns.
2285 pat_line_next_old = tpg_get_pat_line(tpg,
2286 (frame_line_next + mv_vert_old) % tpg->src_height);
2287 pat_line_next_new = tpg_get_pat_line(tpg,
2288 (frame_line_next + mv_vert_new) % tpg->src_height);
2290 switch (tpg->field) {
2291 case V4L2_FIELD_INTERLACED:
2292 case V4L2_FIELD_INTERLACED_BT:
2293 case V4L2_FIELD_INTERLACED_TB:
2294 avg_pat = tpg_pattern_avg(tpg, pat_line_old, pat_line_new);
2295 if (avg_pat < 0)
2296 break;
2297 linestart_older = tpg->downsampled_lines[avg_pat][p] + mv_hor_old;
2298 linestart_newer = linestart_older;
2299 break;
2300 case V4L2_FIELD_NONE:
2301 case V4L2_FIELD_TOP:
2302 case V4L2_FIELD_BOTTOM:
2303 case V4L2_FIELD_SEQ_BT:
2304 case V4L2_FIELD_SEQ_TB:
2305 avg_pat = tpg_pattern_avg(tpg, pat_line_old, pat_line_next_old);
2306 if (avg_pat >= 0)
2307 linestart_older = tpg->downsampled_lines[avg_pat][p] +
2308 mv_hor_old;
2309 avg_pat = tpg_pattern_avg(tpg, pat_line_new, pat_line_next_new);
2310 if (avg_pat >= 0)
2311 linestart_newer = tpg->downsampled_lines[avg_pat][p] +
2312 mv_hor_new;
2313 break;
2316 linestart_older += line_offset;
2317 linestart_newer += line_offset;
2319 if (tpg->field_alternate) {
2320 linestart_top = linestart_bottom = linestart_older;
2321 } else if (params->is_60hz) {
2322 linestart_top = linestart_newer;
2323 linestart_bottom = linestart_older;
2324 } else {
2325 linestart_top = linestart_older;
2326 linestart_bottom = linestart_newer;
2329 switch (tpg->field) {
2330 case V4L2_FIELD_INTERLACED:
2331 case V4L2_FIELD_INTERLACED_TB:
2332 case V4L2_FIELD_SEQ_TB:
2333 case V4L2_FIELD_SEQ_BT:
2334 if (even)
2335 memcpy(vbuf, linestart_top, img_width);
2336 else
2337 memcpy(vbuf, linestart_bottom, img_width);
2338 break;
2339 case V4L2_FIELD_INTERLACED_BT:
2340 if (even)
2341 memcpy(vbuf, linestart_bottom, img_width);
2342 else
2343 memcpy(vbuf, linestart_top, img_width);
2344 break;
2345 case V4L2_FIELD_TOP:
2346 memcpy(vbuf, linestart_top, img_width);
2347 break;
2348 case V4L2_FIELD_BOTTOM:
2349 memcpy(vbuf, linestart_bottom, img_width);
2350 break;
2351 case V4L2_FIELD_NONE:
2352 default:
2353 memcpy(vbuf, linestart_older, img_width);
2354 break;
2358 void tpg_fill_plane_buffer(struct tpg_data *tpg, v4l2_std_id std,
2359 unsigned p, u8 *vbuf)
2361 struct tpg_draw_params params;
2362 unsigned factor = V4L2_FIELD_HAS_T_OR_B(tpg->field) ? 2 : 1;
2364 /* Coarse scaling with Bresenham */
2365 unsigned int_part = (tpg->crop.height / factor) / tpg->compose.height;
2366 unsigned fract_part = (tpg->crop.height / factor) % tpg->compose.height;
2367 unsigned src_y = 0;
2368 unsigned error = 0;
2369 unsigned h;
2371 tpg_recalc(tpg);
2373 params.is_tv = std;
2374 params.is_60hz = std & V4L2_STD_525_60;
2375 params.twopixsize = tpg->twopixelsize[p];
2376 params.img_width = tpg_hdiv(tpg, p, tpg->compose.width);
2377 params.stride = tpg->bytesperline[p];
2378 params.hmax = (tpg->compose.height * tpg->perc_fill) / 100;
2380 tpg_fill_params_pattern(tpg, p, &params);
2381 tpg_fill_params_extras(tpg, p, &params);
2383 vbuf += tpg_hdiv(tpg, p, tpg->compose.left);
2385 for (h = 0; h < tpg->compose.height; h++) {
2386 unsigned buf_line;
2388 params.frame_line = tpg_calc_frameline(tpg, src_y, tpg->field);
2389 params.frame_line_next = params.frame_line;
2390 buf_line = tpg_calc_buffer_line(tpg, h, tpg->field);
2391 src_y += int_part;
2392 error += fract_part;
2393 if (error >= tpg->compose.height) {
2394 error -= tpg->compose.height;
2395 src_y++;
2399 * For line-interleaved formats determine the 'plane'
2400 * based on the buffer line.
2402 if (tpg_g_interleaved(tpg))
2403 p = tpg_g_interleaved_plane(tpg, buf_line);
2405 if (tpg->vdownsampling[p] > 1) {
2407 * When doing vertical downsampling the field setting
2408 * matters: for SEQ_BT/TB we downsample each field
2409 * separately (i.e. lines 0+2 are combined, as are
2410 * lines 1+3), for the other field settings we combine
2411 * odd and even lines. Doing that for SEQ_BT/TB would
2412 * be really weird.
2414 if (tpg->field == V4L2_FIELD_SEQ_BT ||
2415 tpg->field == V4L2_FIELD_SEQ_TB) {
2416 unsigned next_src_y = src_y;
2418 if ((h & 3) >= 2)
2419 continue;
2420 next_src_y += int_part;
2421 if (error + fract_part >= tpg->compose.height)
2422 next_src_y++;
2423 params.frame_line_next =
2424 tpg_calc_frameline(tpg, next_src_y, tpg->field);
2425 } else {
2426 if (h & 1)
2427 continue;
2428 params.frame_line_next =
2429 tpg_calc_frameline(tpg, src_y, tpg->field);
2432 buf_line /= tpg->vdownsampling[p];
2434 tpg_fill_plane_pattern(tpg, &params, p, h,
2435 vbuf + buf_line * params.stride);
2436 tpg_fill_plane_extras(tpg, &params, p, h,
2437 vbuf + buf_line * params.stride);
2440 EXPORT_SYMBOL_GPL(tpg_fill_plane_buffer);
2442 void tpg_fillbuffer(struct tpg_data *tpg, v4l2_std_id std, unsigned p, u8 *vbuf)
2444 unsigned offset = 0;
2445 unsigned i;
2447 if (tpg->buffers > 1) {
2448 tpg_fill_plane_buffer(tpg, std, p, vbuf);
2449 return;
2452 for (i = 0; i < tpg_g_planes(tpg); i++) {
2453 tpg_fill_plane_buffer(tpg, std, i, vbuf + offset);
2454 offset += tpg_calc_plane_size(tpg, i);
2457 EXPORT_SYMBOL_GPL(tpg_fillbuffer);
2459 MODULE_DESCRIPTION("V4L2 Test Pattern Generator");
2460 MODULE_AUTHOR("Hans Verkuil");
2461 MODULE_LICENSE("GPL");