1 // SPDX-License-Identifier: GPL-2.0-only
3 * v4l2-tpg-core.c - Test Pattern Generator
5 * Note: gen_twopix and tpg_gen_text are based on code from vivi.c. See the
6 * vivi.c source for the copyright information of those functions.
8 * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
11 #include <linux/module.h>
12 #include <media/tpg/v4l2-tpg.h>
14 /* Must remain in sync with enum tpg_pattern */
15 const char * const tpg_pattern_strings
[] = {
19 "Horizontal 100% Colorbar",
29 "2x2 Red/Green Checkers",
30 "1x1 Red/Green Checkers",
31 "Alternating Hor Lines",
32 "Alternating Vert Lines",
33 "One Pixel Wide Cross",
34 "Two Pixels Wide Cross",
35 "Ten Pixels Wide Cross",
40 EXPORT_SYMBOL_GPL(tpg_pattern_strings
);
42 /* Must remain in sync with enum tpg_aspect */
43 const char * const tpg_aspect_strings
[] = {
44 "Source Width x Height",
51 EXPORT_SYMBOL_GPL(tpg_aspect_strings
);
54 * Sine table: sin[0] = 127 * sin(-180 degrees)
55 * sin[128] = 127 * sin(0 degrees)
56 * sin[256] = 127 * sin(180 degrees)
58 static const s8 sin
[257] = {
59 0, -4, -7, -11, -13, -18, -20, -22, -26, -29, -33, -35, -37, -41, -43, -48,
60 -50, -52, -56, -58, -62, -63, -65, -69, -71, -75, -76, -78, -82, -83, -87, -88,
61 -90, -93, -94, -97, -99, -101, -103, -104, -107, -108, -110, -111, -112, -114, -115, -117,
62 -118, -119, -120, -121, -122, -123, -123, -124, -125, -125, -126, -126, -127, -127, -127, -127,
63 -127, -127, -127, -127, -126, -126, -125, -125, -124, -124, -123, -122, -121, -120, -119, -118,
64 -117, -116, -114, -113, -111, -110, -109, -107, -105, -103, -101, -100, -97, -96, -93, -91,
65 -90, -87, -85, -82, -80, -76, -75, -73, -69, -67, -63, -62, -60, -56, -54, -50,
66 -48, -46, -41, -39, -35, -33, -31, -26, -24, -20, -18, -15, -11, -9, -4, -2,
67 0, 2, 4, 9, 11, 15, 18, 20, 24, 26, 31, 33, 35, 39, 41, 46,
68 48, 50, 54, 56, 60, 62, 64, 67, 69, 73, 75, 76, 80, 82, 85, 87,
69 90, 91, 93, 96, 97, 100, 101, 103, 105, 107, 109, 110, 111, 113, 114, 116,
70 117, 118, 119, 120, 121, 122, 123, 124, 124, 125, 125, 126, 126, 127, 127, 127,
71 127, 127, 127, 127, 127, 126, 126, 125, 125, 124, 123, 123, 122, 121, 120, 119,
72 118, 117, 115, 114, 112, 111, 110, 108, 107, 104, 103, 101, 99, 97, 94, 93,
73 90, 88, 87, 83, 82, 78, 76, 75, 71, 69, 65, 64, 62, 58, 56, 52,
74 50, 48, 43, 41, 37, 35, 33, 29, 26, 22, 20, 18, 13, 11, 7, 4,
78 #define cos(idx) sin[((idx) + 64) % sizeof(sin)]
80 /* Global font descriptor */
81 static const u8
*font8x16
;
83 void tpg_set_font(const u8
*f
)
87 EXPORT_SYMBOL_GPL(tpg_set_font
);
89 void tpg_init(struct tpg_data
*tpg
, unsigned w
, unsigned h
)
91 memset(tpg
, 0, sizeof(*tpg
));
92 tpg
->scaled_width
= tpg
->src_width
= w
;
93 tpg
->src_height
= tpg
->buf_height
= h
;
94 tpg
->crop
.width
= tpg
->compose
.width
= w
;
95 tpg
->crop
.height
= tpg
->compose
.height
= h
;
96 tpg
->recalc_colors
= true;
97 tpg
->recalc_square_border
= true;
98 tpg
->brightness
= 128;
100 tpg
->saturation
= 128;
102 tpg
->mv_hor_mode
= TPG_MOVE_NONE
;
103 tpg
->mv_vert_mode
= TPG_MOVE_NONE
;
104 tpg
->field
= V4L2_FIELD_NONE
;
105 tpg_s_fourcc(tpg
, V4L2_PIX_FMT_RGB24
);
106 tpg
->colorspace
= V4L2_COLORSPACE_SRGB
;
107 tpg
->perc_fill
= 100;
108 tpg
->hsv_enc
= V4L2_HSV_ENC_180
;
110 EXPORT_SYMBOL_GPL(tpg_init
);
112 int tpg_alloc(struct tpg_data
*tpg
, unsigned max_w
)
117 tpg
->max_line_width
= max_w
;
118 for (pat
= 0; pat
< TPG_MAX_PAT_LINES
; pat
++) {
119 for (plane
= 0; plane
< TPG_MAX_PLANES
; plane
++) {
120 unsigned pixelsz
= plane
? 2 : 4;
122 tpg
->lines
[pat
][plane
] =
123 vzalloc(array3_size(max_w
, 2, pixelsz
));
124 if (!tpg
->lines
[pat
][plane
])
128 tpg
->downsampled_lines
[pat
][plane
] =
129 vzalloc(array3_size(max_w
, 2, pixelsz
));
130 if (!tpg
->downsampled_lines
[pat
][plane
])
134 for (plane
= 0; plane
< TPG_MAX_PLANES
; plane
++) {
135 unsigned pixelsz
= plane
? 2 : 4;
137 tpg
->contrast_line
[plane
] =
138 vzalloc(array_size(pixelsz
, max_w
));
139 if (!tpg
->contrast_line
[plane
])
141 tpg
->black_line
[plane
] =
142 vzalloc(array_size(pixelsz
, max_w
));
143 if (!tpg
->black_line
[plane
])
145 tpg
->random_line
[plane
] =
146 vzalloc(array3_size(max_w
, 2, pixelsz
));
147 if (!tpg
->random_line
[plane
])
152 EXPORT_SYMBOL_GPL(tpg_alloc
);
154 void tpg_free(struct tpg_data
*tpg
)
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
;
165 vfree(tpg
->downsampled_lines
[pat
][plane
]);
166 tpg
->downsampled_lines
[pat
][plane
] = NULL
;
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
;
177 EXPORT_SYMBOL_GPL(tpg_free
);
179 bool tpg_s_fourcc(struct tpg_data
*tpg
, u32 fourcc
)
181 tpg
->fourcc
= fourcc
;
184 tpg
->recalc_colors
= true;
185 tpg
->interleaved
= false;
186 tpg
->vdownsampling
[0] = 1;
187 tpg
->hdownsampling
[0] = 1;
193 case V4L2_PIX_FMT_SBGGR8
:
194 case V4L2_PIX_FMT_SGBRG8
:
195 case V4L2_PIX_FMT_SGRBG8
:
196 case V4L2_PIX_FMT_SRGGB8
:
197 case V4L2_PIX_FMT_SBGGR10
:
198 case V4L2_PIX_FMT_SGBRG10
:
199 case V4L2_PIX_FMT_SGRBG10
:
200 case V4L2_PIX_FMT_SRGGB10
:
201 case V4L2_PIX_FMT_SBGGR12
:
202 case V4L2_PIX_FMT_SGBRG12
:
203 case V4L2_PIX_FMT_SGRBG12
:
204 case V4L2_PIX_FMT_SRGGB12
:
205 case V4L2_PIX_FMT_SBGGR16
:
206 case V4L2_PIX_FMT_SGBRG16
:
207 case V4L2_PIX_FMT_SGRBG16
:
208 case V4L2_PIX_FMT_SRGGB16
:
209 tpg
->interleaved
= true;
210 tpg
->vdownsampling
[1] = 1;
211 tpg
->hdownsampling
[1] = 1;
214 case V4L2_PIX_FMT_RGB332
:
215 case V4L2_PIX_FMT_RGB565
:
216 case V4L2_PIX_FMT_RGB565X
:
217 case V4L2_PIX_FMT_RGB444
:
218 case V4L2_PIX_FMT_XRGB444
:
219 case V4L2_PIX_FMT_ARGB444
:
220 case V4L2_PIX_FMT_RGB555
:
221 case V4L2_PIX_FMT_XRGB555
:
222 case V4L2_PIX_FMT_ARGB555
:
223 case V4L2_PIX_FMT_RGB555X
:
224 case V4L2_PIX_FMT_XRGB555X
:
225 case V4L2_PIX_FMT_ARGB555X
:
226 case V4L2_PIX_FMT_BGR666
:
227 case V4L2_PIX_FMT_RGB24
:
228 case V4L2_PIX_FMT_BGR24
:
229 case V4L2_PIX_FMT_RGB32
:
230 case V4L2_PIX_FMT_BGR32
:
231 case V4L2_PIX_FMT_XRGB32
:
232 case V4L2_PIX_FMT_XBGR32
:
233 case V4L2_PIX_FMT_ARGB32
:
234 case V4L2_PIX_FMT_ABGR32
:
235 tpg
->color_enc
= TGP_COLOR_ENC_RGB
;
237 case V4L2_PIX_FMT_GREY
:
238 case V4L2_PIX_FMT_Y10
:
239 case V4L2_PIX_FMT_Y12
:
240 case V4L2_PIX_FMT_Y16
:
241 case V4L2_PIX_FMT_Y16_BE
:
242 case V4L2_PIX_FMT_Z16
:
243 tpg
->color_enc
= TGP_COLOR_ENC_LUMA
;
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
;
251 case V4L2_PIX_FMT_YUV420M
:
252 case V4L2_PIX_FMT_YVU420M
:
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;
262 tpg
->color_enc
= TGP_COLOR_ENC_YCBCR
;
264 case V4L2_PIX_FMT_YUV422M
:
265 case V4L2_PIX_FMT_YVU422M
:
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;
274 tpg
->color_enc
= TGP_COLOR_ENC_YCBCR
;
276 case V4L2_PIX_FMT_NV16M
:
277 case V4L2_PIX_FMT_NV61M
:
280 case V4L2_PIX_FMT_NV16
:
281 case V4L2_PIX_FMT_NV61
:
282 tpg
->vdownsampling
[1] = 1;
283 tpg
->hdownsampling
[1] = 1;
286 tpg
->color_enc
= TGP_COLOR_ENC_YCBCR
;
288 case V4L2_PIX_FMT_NV12M
:
289 case V4L2_PIX_FMT_NV21M
:
292 case V4L2_PIX_FMT_NV12
:
293 case V4L2_PIX_FMT_NV21
:
294 tpg
->vdownsampling
[1] = 2;
295 tpg
->hdownsampling
[1] = 1;
298 tpg
->color_enc
= TGP_COLOR_ENC_YCBCR
;
300 case V4L2_PIX_FMT_YUV444M
:
301 case V4L2_PIX_FMT_YVU444M
:
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
;
310 case V4L2_PIX_FMT_NV24
:
311 case V4L2_PIX_FMT_NV42
:
312 tpg
->vdownsampling
[1] = 1;
313 tpg
->hdownsampling
[1] = 1;
315 tpg
->color_enc
= TGP_COLOR_ENC_YCBCR
;
317 case V4L2_PIX_FMT_YUYV
:
318 case V4L2_PIX_FMT_UYVY
:
319 case V4L2_PIX_FMT_YVYU
:
320 case V4L2_PIX_FMT_VYUY
:
322 tpg
->color_enc
= TGP_COLOR_ENC_YCBCR
;
324 case V4L2_PIX_FMT_HSV24
:
325 case V4L2_PIX_FMT_HSV32
:
326 tpg
->color_enc
= TGP_COLOR_ENC_HSV
;
333 case V4L2_PIX_FMT_GREY
:
334 case V4L2_PIX_FMT_RGB332
:
335 tpg
->twopixelsize
[0] = 2;
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_Y10
:
356 case V4L2_PIX_FMT_Y12
:
357 case V4L2_PIX_FMT_Y16
:
358 case V4L2_PIX_FMT_Y16_BE
:
359 case V4L2_PIX_FMT_Z16
:
360 tpg
->twopixelsize
[0] = 2 * 2;
362 case V4L2_PIX_FMT_RGB24
:
363 case V4L2_PIX_FMT_BGR24
:
364 case V4L2_PIX_FMT_HSV24
:
365 tpg
->twopixelsize
[0] = 2 * 3;
367 case V4L2_PIX_FMT_BGR666
:
368 case V4L2_PIX_FMT_RGB32
:
369 case V4L2_PIX_FMT_BGR32
:
370 case V4L2_PIX_FMT_XRGB32
:
371 case V4L2_PIX_FMT_XBGR32
:
372 case V4L2_PIX_FMT_ARGB32
:
373 case V4L2_PIX_FMT_ABGR32
:
374 case V4L2_PIX_FMT_YUV32
:
375 case V4L2_PIX_FMT_HSV32
:
376 tpg
->twopixelsize
[0] = 2 * 4;
378 case V4L2_PIX_FMT_NV12
:
379 case V4L2_PIX_FMT_NV21
:
380 case V4L2_PIX_FMT_NV12M
:
381 case V4L2_PIX_FMT_NV21M
:
382 case V4L2_PIX_FMT_NV16
:
383 case V4L2_PIX_FMT_NV61
:
384 case V4L2_PIX_FMT_NV16M
:
385 case V4L2_PIX_FMT_NV61M
:
386 case V4L2_PIX_FMT_SBGGR8
:
387 case V4L2_PIX_FMT_SGBRG8
:
388 case V4L2_PIX_FMT_SGRBG8
:
389 case V4L2_PIX_FMT_SRGGB8
:
390 tpg
->twopixelsize
[0] = 2;
391 tpg
->twopixelsize
[1] = 2;
393 case V4L2_PIX_FMT_SRGGB10
:
394 case V4L2_PIX_FMT_SGRBG10
:
395 case V4L2_PIX_FMT_SGBRG10
:
396 case V4L2_PIX_FMT_SBGGR10
:
397 case V4L2_PIX_FMT_SRGGB12
:
398 case V4L2_PIX_FMT_SGRBG12
:
399 case V4L2_PIX_FMT_SGBRG12
:
400 case V4L2_PIX_FMT_SBGGR12
:
401 case V4L2_PIX_FMT_SRGGB16
:
402 case V4L2_PIX_FMT_SGRBG16
:
403 case V4L2_PIX_FMT_SGBRG16
:
404 case V4L2_PIX_FMT_SBGGR16
:
405 tpg
->twopixelsize
[0] = 4;
406 tpg
->twopixelsize
[1] = 4;
408 case V4L2_PIX_FMT_YUV444M
:
409 case V4L2_PIX_FMT_YVU444M
:
410 case V4L2_PIX_FMT_YUV422M
:
411 case V4L2_PIX_FMT_YVU422M
:
412 case V4L2_PIX_FMT_YUV422P
:
413 case V4L2_PIX_FMT_YUV420
:
414 case V4L2_PIX_FMT_YVU420
:
415 case V4L2_PIX_FMT_YUV420M
:
416 case V4L2_PIX_FMT_YVU420M
:
417 tpg
->twopixelsize
[0] = 2;
418 tpg
->twopixelsize
[1] = 2;
419 tpg
->twopixelsize
[2] = 2;
421 case V4L2_PIX_FMT_NV24
:
422 case V4L2_PIX_FMT_NV42
:
423 tpg
->twopixelsize
[0] = 2;
424 tpg
->twopixelsize
[1] = 4;
429 EXPORT_SYMBOL_GPL(tpg_s_fourcc
);
431 void tpg_s_crop_compose(struct tpg_data
*tpg
, const struct v4l2_rect
*crop
,
432 const struct v4l2_rect
*compose
)
435 tpg
->compose
= *compose
;
436 tpg
->scaled_width
= (tpg
->src_width
* tpg
->compose
.width
+
437 tpg
->crop
.width
- 1) / tpg
->crop
.width
;
438 tpg
->scaled_width
&= ~1;
439 if (tpg
->scaled_width
> tpg
->max_line_width
)
440 tpg
->scaled_width
= tpg
->max_line_width
;
441 if (tpg
->scaled_width
< 2)
442 tpg
->scaled_width
= 2;
443 tpg
->recalc_lines
= true;
445 EXPORT_SYMBOL_GPL(tpg_s_crop_compose
);
447 void tpg_reset_source(struct tpg_data
*tpg
, unsigned width
, unsigned height
,
452 tpg
->src_width
= width
;
453 tpg
->src_height
= height
;
455 tpg
->buf_height
= height
;
456 if (V4L2_FIELD_HAS_T_OR_B(field
))
457 tpg
->buf_height
/= 2;
458 tpg
->scaled_width
= width
;
459 tpg
->crop
.top
= tpg
->crop
.left
= 0;
460 tpg
->crop
.width
= width
;
461 tpg
->crop
.height
= height
;
462 tpg
->compose
.top
= tpg
->compose
.left
= 0;
463 tpg
->compose
.width
= width
;
464 tpg
->compose
.height
= tpg
->buf_height
;
465 for (p
= 0; p
< tpg
->planes
; p
++)
466 tpg
->bytesperline
[p
] = (width
* tpg
->twopixelsize
[p
]) /
467 (2 * tpg
->hdownsampling
[p
]);
468 tpg
->recalc_square_border
= true;
470 EXPORT_SYMBOL_GPL(tpg_reset_source
);
472 static enum tpg_color
tpg_get_textbg_color(struct tpg_data
*tpg
)
474 switch (tpg
->pattern
) {
476 return TPG_COLOR_100_WHITE
;
477 case TPG_PAT_CSC_COLORBAR
:
478 return TPG_COLOR_CSC_BLACK
;
480 return TPG_COLOR_100_BLACK
;
484 static enum tpg_color
tpg_get_textfg_color(struct tpg_data
*tpg
)
486 switch (tpg
->pattern
) {
487 case TPG_PAT_75_COLORBAR
:
488 case TPG_PAT_CSC_COLORBAR
:
489 return TPG_COLOR_CSC_WHITE
;
491 return TPG_COLOR_100_BLACK
;
493 return TPG_COLOR_100_WHITE
;
497 static inline int rec709_to_linear(int v
)
499 v
= clamp(v
, 0, 0xff0);
500 return tpg_rec709_to_linear
[v
];
503 static inline int linear_to_rec709(int v
)
505 v
= clamp(v
, 0, 0xff0);
506 return tpg_linear_to_rec709
[v
];
509 static void color_to_hsv(struct tpg_data
*tpg
, int r
, int g
, int b
,
510 int *h
, int *s
, int *v
)
512 int max_rgb
, min_rgb
, diff_rgb
;
522 max_rgb
= max3(r
, g
, b
);
531 min_rgb
= min3(r
, g
, b
);
532 diff_rgb
= max_rgb
- min_rgb
;
533 aux
= 255 * diff_rgb
;
542 third_size
= (tpg
->real_hsv_enc
== V4L2_HSV_ENC_180
) ? 60 : 85;
548 } else if (max_rgb
== g
) {
553 third
= third_size
* 2;
556 aux
*= third_size
/ 2;
562 if (tpg
->real_hsv_enc
== V4L2_HSV_ENC_180
) {
574 static void rgb2ycbcr(const int m
[3][3], int r
, int g
, int b
,
575 int y_offset
, int *y
, int *cb
, int *cr
)
577 *y
= ((m
[0][0] * r
+ m
[0][1] * g
+ m
[0][2] * b
) >> 16) + (y_offset
<< 4);
578 *cb
= ((m
[1][0] * r
+ m
[1][1] * g
+ m
[1][2] * b
) >> 16) + (128 << 4);
579 *cr
= ((m
[2][0] * r
+ m
[2][1] * g
+ m
[2][2] * b
) >> 16) + (128 << 4);
582 static void color_to_ycbcr(struct tpg_data
*tpg
, int r
, int g
, int b
,
583 int *y
, int *cb
, int *cr
)
585 #define COEFF(v, r) ((int)(0.5 + (v) * (r) * 256.0))
587 static const int bt601
[3][3] = {
588 { COEFF(0.299, 219), COEFF(0.587, 219), COEFF(0.114, 219) },
589 { COEFF(-0.1687, 224), COEFF(-0.3313, 224), COEFF(0.5, 224) },
590 { COEFF(0.5, 224), COEFF(-0.4187, 224), COEFF(-0.0813, 224) },
592 static const int bt601_full
[3][3] = {
593 { COEFF(0.299, 255), COEFF(0.587, 255), COEFF(0.114, 255) },
594 { COEFF(-0.1687, 255), COEFF(-0.3313, 255), COEFF(0.5, 255) },
595 { COEFF(0.5, 255), COEFF(-0.4187, 255), COEFF(-0.0813, 255) },
597 static const int rec709
[3][3] = {
598 { COEFF(0.2126, 219), COEFF(0.7152, 219), COEFF(0.0722, 219) },
599 { COEFF(-0.1146, 224), COEFF(-0.3854, 224), COEFF(0.5, 224) },
600 { COEFF(0.5, 224), COEFF(-0.4542, 224), COEFF(-0.0458, 224) },
602 static const int rec709_full
[3][3] = {
603 { COEFF(0.2126, 255), COEFF(0.7152, 255), COEFF(0.0722, 255) },
604 { COEFF(-0.1146, 255), COEFF(-0.3854, 255), COEFF(0.5, 255) },
605 { COEFF(0.5, 255), COEFF(-0.4542, 255), COEFF(-0.0458, 255) },
607 static const int smpte240m
[3][3] = {
608 { COEFF(0.212, 219), COEFF(0.701, 219), COEFF(0.087, 219) },
609 { COEFF(-0.116, 224), COEFF(-0.384, 224), COEFF(0.5, 224) },
610 { COEFF(0.5, 224), COEFF(-0.445, 224), COEFF(-0.055, 224) },
612 static const int smpte240m_full
[3][3] = {
613 { COEFF(0.212, 255), COEFF(0.701, 255), COEFF(0.087, 255) },
614 { COEFF(-0.116, 255), COEFF(-0.384, 255), COEFF(0.5, 255) },
615 { COEFF(0.5, 255), COEFF(-0.445, 255), COEFF(-0.055, 255) },
617 static const int bt2020
[3][3] = {
618 { COEFF(0.2627, 219), COEFF(0.6780, 219), COEFF(0.0593, 219) },
619 { COEFF(-0.1396, 224), COEFF(-0.3604, 224), COEFF(0.5, 224) },
620 { COEFF(0.5, 224), COEFF(-0.4598, 224), COEFF(-0.0402, 224) },
622 static const int bt2020_full
[3][3] = {
623 { COEFF(0.2627, 255), COEFF(0.6780, 255), COEFF(0.0593, 255) },
624 { COEFF(-0.1396, 255), COEFF(-0.3604, 255), COEFF(0.5, 255) },
625 { COEFF(0.5, 255), COEFF(-0.4598, 255), COEFF(-0.0402, 255) },
627 static const int bt2020c
[4] = {
628 COEFF(1.0 / 1.9404, 224), COEFF(1.0 / 1.5816, 224),
629 COEFF(1.0 / 1.7184, 224), COEFF(1.0 / 0.9936, 224),
631 static const int bt2020c_full
[4] = {
632 COEFF(1.0 / 1.9404, 255), COEFF(1.0 / 1.5816, 255),
633 COEFF(1.0 / 1.7184, 255), COEFF(1.0 / 0.9936, 255),
636 bool full
= tpg
->real_quantization
== V4L2_QUANTIZATION_FULL_RANGE
;
637 unsigned y_offset
= full
? 0 : 16;
640 switch (tpg
->real_ycbcr_enc
) {
641 case V4L2_YCBCR_ENC_601
:
642 rgb2ycbcr(full
? bt601_full
: bt601
, r
, g
, b
, y_offset
, y
, cb
, cr
);
644 case V4L2_YCBCR_ENC_XV601
:
645 /* Ignore quantization range, there is only one possible
646 * Y'CbCr encoding. */
647 rgb2ycbcr(bt601
, r
, g
, b
, 16, y
, cb
, cr
);
649 case V4L2_YCBCR_ENC_XV709
:
650 /* Ignore quantization range, there is only one possible
651 * Y'CbCr encoding. */
652 rgb2ycbcr(rec709
, r
, g
, b
, 16, y
, cb
, cr
);
654 case V4L2_YCBCR_ENC_BT2020
:
655 rgb2ycbcr(full
? bt2020_full
: bt2020
, r
, g
, b
, y_offset
, y
, cb
, cr
);
657 case V4L2_YCBCR_ENC_BT2020_CONST_LUM
:
658 lin_y
= (COEFF(0.2627, 255) * rec709_to_linear(r
) +
659 COEFF(0.6780, 255) * rec709_to_linear(g
) +
660 COEFF(0.0593, 255) * rec709_to_linear(b
)) >> 16;
661 yc
= linear_to_rec709(lin_y
);
662 *y
= full
? yc
: (yc
* 219) / 255 + (16 << 4);
664 *cb
= (((b
- yc
) * (full
? bt2020c_full
[0] : bt2020c
[0])) >> 16) + (128 << 4);
666 *cb
= (((b
- yc
) * (full
? bt2020c_full
[1] : bt2020c
[1])) >> 16) + (128 << 4);
668 *cr
= (((r
- yc
) * (full
? bt2020c_full
[2] : bt2020c
[2])) >> 16) + (128 << 4);
670 *cr
= (((r
- yc
) * (full
? bt2020c_full
[3] : bt2020c
[3])) >> 16) + (128 << 4);
672 case V4L2_YCBCR_ENC_SMPTE240M
:
673 rgb2ycbcr(full
? smpte240m_full
: smpte240m
, r
, g
, b
, y_offset
, y
, cb
, cr
);
675 case V4L2_YCBCR_ENC_709
:
677 rgb2ycbcr(full
? rec709_full
: rec709
, r
, g
, b
, y_offset
, y
, cb
, cr
);
682 static void ycbcr2rgb(const int m
[3][3], int y
, int cb
, int cr
,
683 int y_offset
, int *r
, int *g
, int *b
)
688 *r
= m
[0][0] * y
+ m
[0][1] * cb
+ m
[0][2] * cr
;
689 *g
= m
[1][0] * y
+ m
[1][1] * cb
+ m
[1][2] * cr
;
690 *b
= m
[2][0] * y
+ m
[2][1] * cb
+ m
[2][2] * cr
;
691 *r
= clamp(*r
>> 12, 0, 0xff0);
692 *g
= clamp(*g
>> 12, 0, 0xff0);
693 *b
= clamp(*b
>> 12, 0, 0xff0);
696 static void ycbcr_to_color(struct tpg_data
*tpg
, int y
, int cb
, int cr
,
697 int *r
, int *g
, int *b
)
700 #define COEFF(v, r) ((int)(0.5 + (v) * ((255.0 * 255.0 * 16.0) / (r))))
701 static const int bt601
[3][3] = {
702 { COEFF(1, 219), COEFF(0, 224), COEFF(1.4020, 224) },
703 { COEFF(1, 219), COEFF(-0.3441, 224), COEFF(-0.7141, 224) },
704 { COEFF(1, 219), COEFF(1.7720, 224), COEFF(0, 224) },
706 static const int bt601_full
[3][3] = {
707 { COEFF(1, 255), COEFF(0, 255), COEFF(1.4020, 255) },
708 { COEFF(1, 255), COEFF(-0.3441, 255), COEFF(-0.7141, 255) },
709 { COEFF(1, 255), COEFF(1.7720, 255), COEFF(0, 255) },
711 static const int rec709
[3][3] = {
712 { COEFF(1, 219), COEFF(0, 224), COEFF(1.5748, 224) },
713 { COEFF(1, 219), COEFF(-0.1873, 224), COEFF(-0.4681, 224) },
714 { COEFF(1, 219), COEFF(1.8556, 224), COEFF(0, 224) },
716 static const int rec709_full
[3][3] = {
717 { COEFF(1, 255), COEFF(0, 255), COEFF(1.5748, 255) },
718 { COEFF(1, 255), COEFF(-0.1873, 255), COEFF(-0.4681, 255) },
719 { COEFF(1, 255), COEFF(1.8556, 255), COEFF(0, 255) },
721 static const int smpte240m
[3][3] = {
722 { COEFF(1, 219), COEFF(0, 224), COEFF(1.5756, 224) },
723 { COEFF(1, 219), COEFF(-0.2253, 224), COEFF(-0.4767, 224) },
724 { COEFF(1, 219), COEFF(1.8270, 224), COEFF(0, 224) },
726 static const int smpte240m_full
[3][3] = {
727 { COEFF(1, 255), COEFF(0, 255), COEFF(1.5756, 255) },
728 { COEFF(1, 255), COEFF(-0.2253, 255), COEFF(-0.4767, 255) },
729 { COEFF(1, 255), COEFF(1.8270, 255), COEFF(0, 255) },
731 static const int bt2020
[3][3] = {
732 { COEFF(1, 219), COEFF(0, 224), COEFF(1.4746, 224) },
733 { COEFF(1, 219), COEFF(-0.1646, 224), COEFF(-0.5714, 224) },
734 { COEFF(1, 219), COEFF(1.8814, 224), COEFF(0, 224) },
736 static const int bt2020_full
[3][3] = {
737 { COEFF(1, 255), COEFF(0, 255), COEFF(1.4746, 255) },
738 { COEFF(1, 255), COEFF(-0.1646, 255), COEFF(-0.5714, 255) },
739 { COEFF(1, 255), COEFF(1.8814, 255), COEFF(0, 255) },
741 static const int bt2020c
[4] = {
742 COEFF(1.9404, 224), COEFF(1.5816, 224),
743 COEFF(1.7184, 224), COEFF(0.9936, 224),
745 static const int bt2020c_full
[4] = {
746 COEFF(1.9404, 255), COEFF(1.5816, 255),
747 COEFF(1.7184, 255), COEFF(0.9936, 255),
750 bool full
= tpg
->real_quantization
== V4L2_QUANTIZATION_FULL_RANGE
;
751 unsigned y_offset
= full
? 0 : 16;
752 int y_fac
= full
? COEFF(1.0, 255) : COEFF(1.0, 219);
753 int lin_r
, lin_g
, lin_b
, lin_y
;
755 switch (tpg
->real_ycbcr_enc
) {
756 case V4L2_YCBCR_ENC_601
:
757 ycbcr2rgb(full
? bt601_full
: bt601
, y
, cb
, cr
, y_offset
, r
, g
, b
);
759 case V4L2_YCBCR_ENC_XV601
:
760 /* Ignore quantization range, there is only one possible
761 * Y'CbCr encoding. */
762 ycbcr2rgb(bt601
, y
, cb
, cr
, 16, r
, g
, b
);
764 case V4L2_YCBCR_ENC_XV709
:
765 /* Ignore quantization range, there is only one possible
766 * Y'CbCr encoding. */
767 ycbcr2rgb(rec709
, y
, cb
, cr
, 16, r
, g
, b
);
769 case V4L2_YCBCR_ENC_BT2020
:
770 ycbcr2rgb(full
? bt2020_full
: bt2020
, y
, cb
, cr
, y_offset
, r
, g
, b
);
772 case V4L2_YCBCR_ENC_BT2020_CONST_LUM
:
773 y
-= full
? 0 : 16 << 4;
778 *b
= y_fac
* y
+ (full
? bt2020c_full
[0] : bt2020c
[0]) * cb
;
780 *b
= y_fac
* y
+ (full
? bt2020c_full
[1] : bt2020c
[1]) * cb
;
783 *r
= y_fac
* y
+ (full
? bt2020c_full
[2] : bt2020c
[2]) * cr
;
785 *r
= y_fac
* y
+ (full
? bt2020c_full
[3] : bt2020c
[3]) * cr
;
787 lin_r
= rec709_to_linear(*r
);
788 lin_b
= rec709_to_linear(*b
);
789 lin_y
= rec709_to_linear((y
* 255) / (full
? 255 : 219));
791 lin_g
= COEFF(1.0 / 0.6780, 255) * lin_y
-
792 COEFF(0.2627 / 0.6780, 255) * lin_r
-
793 COEFF(0.0593 / 0.6780, 255) * lin_b
;
794 *g
= linear_to_rec709(lin_g
>> 12);
796 case V4L2_YCBCR_ENC_SMPTE240M
:
797 ycbcr2rgb(full
? smpte240m_full
: smpte240m
, y
, cb
, cr
, y_offset
, r
, g
, b
);
799 case V4L2_YCBCR_ENC_709
:
801 ycbcr2rgb(full
? rec709_full
: rec709
, y
, cb
, cr
, y_offset
, r
, g
, b
);
806 /* precalculate color bar values to speed up rendering */
807 static void precalculate_color(struct tpg_data
*tpg
, int k
)
810 int r
= tpg_colors
[col
].r
;
811 int g
= tpg_colors
[col
].g
;
812 int b
= tpg_colors
[col
].b
;
814 bool ycbcr_valid
= false;
816 if (k
== TPG_COLOR_TEXTBG
) {
817 col
= tpg_get_textbg_color(tpg
);
819 r
= tpg_colors
[col
].r
;
820 g
= tpg_colors
[col
].g
;
821 b
= tpg_colors
[col
].b
;
822 } else if (k
== TPG_COLOR_TEXTFG
) {
823 col
= tpg_get_textfg_color(tpg
);
825 r
= tpg_colors
[col
].r
;
826 g
= tpg_colors
[col
].g
;
827 b
= tpg_colors
[col
].b
;
828 } else if (tpg
->pattern
== TPG_PAT_NOISE
) {
829 r
= g
= b
= prandom_u32_max(256);
830 } else if (k
== TPG_COLOR_RANDOM
) {
831 r
= g
= b
= tpg
->qual_offset
+ prandom_u32_max(196);
832 } else if (k
>= TPG_COLOR_RAMP
) {
833 r
= g
= b
= k
- TPG_COLOR_RAMP
;
836 if (tpg
->pattern
== TPG_PAT_CSC_COLORBAR
&& col
<= TPG_COLOR_CSC_BLACK
) {
837 r
= tpg_csc_colors
[tpg
->colorspace
][tpg
->real_xfer_func
][col
].r
;
838 g
= tpg_csc_colors
[tpg
->colorspace
][tpg
->real_xfer_func
][col
].g
;
839 b
= tpg_csc_colors
[tpg
->colorspace
][tpg
->real_xfer_func
][col
].b
;
846 if (tpg
->qual
== TPG_QUAL_GRAY
||
847 tpg
->color_enc
== TGP_COLOR_ENC_LUMA
) {
848 /* Rec. 709 Luma function */
849 /* (0.2126, 0.7152, 0.0722) * (255 * 256) */
850 r
= g
= b
= (13879 * r
+ 46688 * g
+ 4713 * b
) >> 16;
854 * The assumption is that the RGB output is always full range,
855 * so only if the rgb_range overrides the 'real' rgb range do
856 * we need to convert the RGB values.
858 * Remember that r, g and b are still in the 0 - 0xff0 range.
860 if (tpg
->real_rgb_range
== V4L2_DV_RGB_RANGE_LIMITED
&&
861 tpg
->rgb_range
== V4L2_DV_RGB_RANGE_FULL
&&
862 tpg
->color_enc
== TGP_COLOR_ENC_RGB
) {
864 * Convert from full range (which is what r, g and b are)
865 * to limited range (which is the 'real' RGB range), which
866 * is then interpreted as full range.
868 r
= (r
* 219) / 255 + (16 << 4);
869 g
= (g
* 219) / 255 + (16 << 4);
870 b
= (b
* 219) / 255 + (16 << 4);
871 } else if (tpg
->real_rgb_range
!= V4L2_DV_RGB_RANGE_LIMITED
&&
872 tpg
->rgb_range
== V4L2_DV_RGB_RANGE_LIMITED
&&
873 tpg
->color_enc
== TGP_COLOR_ENC_RGB
) {
876 * Clamp r, g and b to the limited range and convert to full
877 * range since that's what we deliver.
879 r
= clamp(r
, 16 << 4, 235 << 4);
880 g
= clamp(g
, 16 << 4, 235 << 4);
881 b
= clamp(b
, 16 << 4, 235 << 4);
882 r
= (r
- (16 << 4)) * 255 / 219;
883 g
= (g
- (16 << 4)) * 255 / 219;
884 b
= (b
- (16 << 4)) * 255 / 219;
887 if ((tpg
->brightness
!= 128 || tpg
->contrast
!= 128 ||
888 tpg
->saturation
!= 128 || tpg
->hue
) &&
889 tpg
->color_enc
!= TGP_COLOR_ENC_LUMA
) {
890 /* Implement these operations */
893 /* First convert to YCbCr */
895 color_to_ycbcr(tpg
, r
, g
, b
, &y
, &cb
, &cr
);
897 y
= (16 << 4) + ((y
- (16 << 4)) * tpg
->contrast
) / 128;
898 y
+= (tpg
->brightness
<< 4) - (128 << 4);
902 tmp_cb
= (cb
* cos(128 + tpg
->hue
)) / 127 + (cr
* sin
[128 + tpg
->hue
]) / 127;
903 tmp_cr
= (cr
* cos(128 + tpg
->hue
)) / 127 - (cb
* sin
[128 + tpg
->hue
]) / 127;
905 cb
= (128 << 4) + (tmp_cb
* tpg
->contrast
* tpg
->saturation
) / (128 * 128);
906 cr
= (128 << 4) + (tmp_cr
* tpg
->contrast
* tpg
->saturation
) / (128 * 128);
907 if (tpg
->color_enc
== TGP_COLOR_ENC_YCBCR
)
910 ycbcr_to_color(tpg
, y
, cb
, cr
, &r
, &g
, &b
);
911 } else if ((tpg
->brightness
!= 128 || tpg
->contrast
!= 128) &&
912 tpg
->color_enc
== TGP_COLOR_ENC_LUMA
) {
913 r
= (16 << 4) + ((r
- (16 << 4)) * tpg
->contrast
) / 128;
914 r
+= (tpg
->brightness
<< 4) - (128 << 4);
917 switch (tpg
->color_enc
) {
918 case TGP_COLOR_ENC_HSV
:
922 color_to_hsv(tpg
, r
, g
, b
, &h
, &s
, &v
);
923 tpg
->colors
[k
][0] = h
;
924 tpg
->colors
[k
][1] = s
;
925 tpg
->colors
[k
][2] = v
;
928 case TGP_COLOR_ENC_YCBCR
:
930 /* Convert to YCbCr */
932 color_to_ycbcr(tpg
, r
, g
, b
, &y
, &cb
, &cr
);
938 * XV601/709 use the header/footer margins to encode R', G'
939 * and B' values outside the range [0-1]. So do not clamp
942 if (tpg
->real_quantization
== V4L2_QUANTIZATION_LIM_RANGE
&&
943 tpg
->real_ycbcr_enc
!= V4L2_YCBCR_ENC_XV601
&&
944 tpg
->real_ycbcr_enc
!= V4L2_YCBCR_ENC_XV709
) {
945 y
= clamp(y
, 16, 235);
946 cb
= clamp(cb
, 16, 240);
947 cr
= clamp(cr
, 16, 240);
949 y
= clamp(y
, 1, 254);
950 cb
= clamp(cb
, 1, 254);
951 cr
= clamp(cr
, 1, 254);
953 switch (tpg
->fourcc
) {
954 case V4L2_PIX_FMT_YUV444
:
959 case V4L2_PIX_FMT_YUV555
:
964 case V4L2_PIX_FMT_YUV565
:
970 tpg
->colors
[k
][0] = y
;
971 tpg
->colors
[k
][1] = cb
;
972 tpg
->colors
[k
][2] = cr
;
975 case TGP_COLOR_ENC_LUMA
:
977 tpg
->colors
[k
][0] = r
>> 4;
980 case TGP_COLOR_ENC_RGB
:
982 if (tpg
->real_quantization
== V4L2_QUANTIZATION_LIM_RANGE
) {
983 r
= (r
* 219) / 255 + (16 << 4);
984 g
= (g
* 219) / 255 + (16 << 4);
985 b
= (b
* 219) / 255 + (16 << 4);
987 switch (tpg
->fourcc
) {
988 case V4L2_PIX_FMT_RGB332
:
993 case V4L2_PIX_FMT_RGB565
:
994 case V4L2_PIX_FMT_RGB565X
:
999 case V4L2_PIX_FMT_RGB444
:
1000 case V4L2_PIX_FMT_XRGB444
:
1001 case V4L2_PIX_FMT_ARGB444
:
1006 case V4L2_PIX_FMT_RGB555
:
1007 case V4L2_PIX_FMT_XRGB555
:
1008 case V4L2_PIX_FMT_ARGB555
:
1009 case V4L2_PIX_FMT_RGB555X
:
1010 case V4L2_PIX_FMT_XRGB555X
:
1011 case V4L2_PIX_FMT_ARGB555X
:
1016 case V4L2_PIX_FMT_BGR666
:
1028 tpg
->colors
[k
][0] = r
;
1029 tpg
->colors
[k
][1] = g
;
1030 tpg
->colors
[k
][2] = b
;
1036 static void tpg_precalculate_colors(struct tpg_data
*tpg
)
1040 for (k
= 0; k
< TPG_COLOR_MAX
; k
++)
1041 precalculate_color(tpg
, k
);
1044 /* 'odd' is true for pixels 1, 3, 5, etc. and false for pixels 0, 2, 4, etc. */
1045 static void gen_twopix(struct tpg_data
*tpg
,
1046 u8 buf
[TPG_MAX_PLANES
][8], int color
, bool odd
)
1048 unsigned offset
= odd
* tpg
->twopixelsize
[0] / 2;
1049 u8 alpha
= tpg
->alpha_component
;
1050 u8 r_y_h
, g_u_s
, b_v
;
1052 if (tpg
->alpha_red_only
&& color
!= TPG_COLOR_CSC_RED
&&
1053 color
!= TPG_COLOR_100_RED
&&
1054 color
!= TPG_COLOR_75_RED
)
1056 if (color
== TPG_COLOR_RANDOM
)
1057 precalculate_color(tpg
, color
);
1058 r_y_h
= tpg
->colors
[color
][0]; /* R or precalculated Y, H */
1059 g_u_s
= tpg
->colors
[color
][1]; /* G or precalculated U, V */
1060 b_v
= tpg
->colors
[color
][2]; /* B or precalculated V */
1062 switch (tpg
->fourcc
) {
1063 case V4L2_PIX_FMT_GREY
:
1064 buf
[0][offset
] = r_y_h
;
1066 case V4L2_PIX_FMT_Y10
:
1067 buf
[0][offset
] = (r_y_h
<< 2) & 0xff;
1068 buf
[0][offset
+1] = r_y_h
>> 6;
1070 case V4L2_PIX_FMT_Y12
:
1071 buf
[0][offset
] = (r_y_h
<< 4) & 0xff;
1072 buf
[0][offset
+1] = r_y_h
>> 4;
1074 case V4L2_PIX_FMT_Y16
:
1075 case V4L2_PIX_FMT_Z16
:
1077 * Ideally both bytes should be set to r_y_h, but then you won't
1078 * be able to detect endian problems. So keep it 0 except for
1079 * the corner case where r_y_h is 0xff so white really will be
1082 buf
[0][offset
] = r_y_h
== 0xff ? r_y_h
: 0;
1083 buf
[0][offset
+1] = r_y_h
;
1085 case V4L2_PIX_FMT_Y16_BE
:
1086 /* See comment for V4L2_PIX_FMT_Y16 above */
1087 buf
[0][offset
] = r_y_h
;
1088 buf
[0][offset
+1] = r_y_h
== 0xff ? r_y_h
: 0;
1090 case V4L2_PIX_FMT_YUV422M
:
1091 case V4L2_PIX_FMT_YUV422P
:
1092 case V4L2_PIX_FMT_YUV420
:
1093 case V4L2_PIX_FMT_YUV420M
:
1094 buf
[0][offset
] = r_y_h
;
1096 buf
[1][0] = (buf
[1][0] + g_u_s
) / 2;
1097 buf
[2][0] = (buf
[2][0] + b_v
) / 2;
1098 buf
[1][1] = buf
[1][0];
1099 buf
[2][1] = buf
[2][0];
1105 case V4L2_PIX_FMT_YVU422M
:
1106 case V4L2_PIX_FMT_YVU420
:
1107 case V4L2_PIX_FMT_YVU420M
:
1108 buf
[0][offset
] = r_y_h
;
1110 buf
[1][0] = (buf
[1][0] + b_v
) / 2;
1111 buf
[2][0] = (buf
[2][0] + g_u_s
) / 2;
1112 buf
[1][1] = buf
[1][0];
1113 buf
[2][1] = buf
[2][0];
1120 case V4L2_PIX_FMT_NV12
:
1121 case V4L2_PIX_FMT_NV12M
:
1122 case V4L2_PIX_FMT_NV16
:
1123 case V4L2_PIX_FMT_NV16M
:
1124 buf
[0][offset
] = r_y_h
;
1126 buf
[1][0] = (buf
[1][0] + g_u_s
) / 2;
1127 buf
[1][1] = (buf
[1][1] + b_v
) / 2;
1133 case V4L2_PIX_FMT_NV21
:
1134 case V4L2_PIX_FMT_NV21M
:
1135 case V4L2_PIX_FMT_NV61
:
1136 case V4L2_PIX_FMT_NV61M
:
1137 buf
[0][offset
] = r_y_h
;
1139 buf
[1][0] = (buf
[1][0] + b_v
) / 2;
1140 buf
[1][1] = (buf
[1][1] + g_u_s
) / 2;
1147 case V4L2_PIX_FMT_YUV444M
:
1148 buf
[0][offset
] = r_y_h
;
1149 buf
[1][offset
] = g_u_s
;
1150 buf
[2][offset
] = b_v
;
1153 case V4L2_PIX_FMT_YVU444M
:
1154 buf
[0][offset
] = r_y_h
;
1155 buf
[1][offset
] = b_v
;
1156 buf
[2][offset
] = g_u_s
;
1159 case V4L2_PIX_FMT_NV24
:
1160 buf
[0][offset
] = r_y_h
;
1161 buf
[1][2 * offset
] = g_u_s
;
1162 buf
[1][(2 * offset
+ 1) % 8] = b_v
;
1165 case V4L2_PIX_FMT_NV42
:
1166 buf
[0][offset
] = r_y_h
;
1167 buf
[1][2 * offset
] = b_v
;
1168 buf
[1][(2 * offset
+ 1) % 8] = g_u_s
;
1171 case V4L2_PIX_FMT_YUYV
:
1172 buf
[0][offset
] = r_y_h
;
1174 buf
[0][1] = (buf
[0][1] + g_u_s
) / 2;
1175 buf
[0][3] = (buf
[0][3] + b_v
) / 2;
1181 case V4L2_PIX_FMT_UYVY
:
1182 buf
[0][offset
+ 1] = r_y_h
;
1184 buf
[0][0] = (buf
[0][0] + g_u_s
) / 2;
1185 buf
[0][2] = (buf
[0][2] + b_v
) / 2;
1191 case V4L2_PIX_FMT_YVYU
:
1192 buf
[0][offset
] = r_y_h
;
1194 buf
[0][1] = (buf
[0][1] + b_v
) / 2;
1195 buf
[0][3] = (buf
[0][3] + g_u_s
) / 2;
1201 case V4L2_PIX_FMT_VYUY
:
1202 buf
[0][offset
+ 1] = r_y_h
;
1204 buf
[0][0] = (buf
[0][0] + b_v
) / 2;
1205 buf
[0][2] = (buf
[0][2] + g_u_s
) / 2;
1211 case V4L2_PIX_FMT_RGB332
:
1212 buf
[0][offset
] = (r_y_h
<< 5) | (g_u_s
<< 2) | b_v
;
1214 case V4L2_PIX_FMT_YUV565
:
1215 case V4L2_PIX_FMT_RGB565
:
1216 buf
[0][offset
] = (g_u_s
<< 5) | b_v
;
1217 buf
[0][offset
+ 1] = (r_y_h
<< 3) | (g_u_s
>> 3);
1219 case V4L2_PIX_FMT_RGB565X
:
1220 buf
[0][offset
] = (r_y_h
<< 3) | (g_u_s
>> 3);
1221 buf
[0][offset
+ 1] = (g_u_s
<< 5) | b_v
;
1223 case V4L2_PIX_FMT_RGB444
:
1224 case V4L2_PIX_FMT_XRGB444
:
1227 case V4L2_PIX_FMT_YUV444
:
1228 case V4L2_PIX_FMT_ARGB444
:
1229 buf
[0][offset
] = (g_u_s
<< 4) | b_v
;
1230 buf
[0][offset
+ 1] = (alpha
& 0xf0) | r_y_h
;
1232 case V4L2_PIX_FMT_RGB555
:
1233 case V4L2_PIX_FMT_XRGB555
:
1236 case V4L2_PIX_FMT_YUV555
:
1237 case V4L2_PIX_FMT_ARGB555
:
1238 buf
[0][offset
] = (g_u_s
<< 5) | b_v
;
1239 buf
[0][offset
+ 1] = (alpha
& 0x80) | (r_y_h
<< 2)
1242 case V4L2_PIX_FMT_RGB555X
:
1243 case V4L2_PIX_FMT_XRGB555X
:
1246 case V4L2_PIX_FMT_ARGB555X
:
1247 buf
[0][offset
] = (alpha
& 0x80) | (r_y_h
<< 2) | (g_u_s
>> 3);
1248 buf
[0][offset
+ 1] = (g_u_s
<< 5) | b_v
;
1250 case V4L2_PIX_FMT_RGB24
:
1251 case V4L2_PIX_FMT_HSV24
:
1252 buf
[0][offset
] = r_y_h
;
1253 buf
[0][offset
+ 1] = g_u_s
;
1254 buf
[0][offset
+ 2] = b_v
;
1256 case V4L2_PIX_FMT_BGR24
:
1257 buf
[0][offset
] = b_v
;
1258 buf
[0][offset
+ 1] = g_u_s
;
1259 buf
[0][offset
+ 2] = r_y_h
;
1261 case V4L2_PIX_FMT_BGR666
:
1262 buf
[0][offset
] = (b_v
<< 2) | (g_u_s
>> 4);
1263 buf
[0][offset
+ 1] = (g_u_s
<< 4) | (r_y_h
>> 2);
1264 buf
[0][offset
+ 2] = r_y_h
<< 6;
1265 buf
[0][offset
+ 3] = 0;
1267 case V4L2_PIX_FMT_RGB32
:
1268 case V4L2_PIX_FMT_XRGB32
:
1269 case V4L2_PIX_FMT_HSV32
:
1272 case V4L2_PIX_FMT_YUV32
:
1273 case V4L2_PIX_FMT_ARGB32
:
1274 buf
[0][offset
] = alpha
;
1275 buf
[0][offset
+ 1] = r_y_h
;
1276 buf
[0][offset
+ 2] = g_u_s
;
1277 buf
[0][offset
+ 3] = b_v
;
1279 case V4L2_PIX_FMT_BGR32
:
1280 case V4L2_PIX_FMT_XBGR32
:
1283 case V4L2_PIX_FMT_ABGR32
:
1284 buf
[0][offset
] = b_v
;
1285 buf
[0][offset
+ 1] = g_u_s
;
1286 buf
[0][offset
+ 2] = r_y_h
;
1287 buf
[0][offset
+ 3] = alpha
;
1289 case V4L2_PIX_FMT_SBGGR8
:
1290 buf
[0][offset
] = odd
? g_u_s
: b_v
;
1291 buf
[1][offset
] = odd
? r_y_h
: g_u_s
;
1293 case V4L2_PIX_FMT_SGBRG8
:
1294 buf
[0][offset
] = odd
? b_v
: g_u_s
;
1295 buf
[1][offset
] = odd
? g_u_s
: r_y_h
;
1297 case V4L2_PIX_FMT_SGRBG8
:
1298 buf
[0][offset
] = odd
? r_y_h
: g_u_s
;
1299 buf
[1][offset
] = odd
? g_u_s
: b_v
;
1301 case V4L2_PIX_FMT_SRGGB8
:
1302 buf
[0][offset
] = odd
? g_u_s
: r_y_h
;
1303 buf
[1][offset
] = odd
? b_v
: g_u_s
;
1305 case V4L2_PIX_FMT_SBGGR10
:
1306 buf
[0][offset
] = odd
? g_u_s
<< 2 : b_v
<< 2;
1307 buf
[0][offset
+ 1] = odd
? g_u_s
>> 6 : b_v
>> 6;
1308 buf
[1][offset
] = odd
? r_y_h
<< 2 : g_u_s
<< 2;
1309 buf
[1][offset
+ 1] = odd
? r_y_h
>> 6 : g_u_s
>> 6;
1310 buf
[0][offset
] |= (buf
[0][offset
] >> 2) & 3;
1311 buf
[1][offset
] |= (buf
[1][offset
] >> 2) & 3;
1313 case V4L2_PIX_FMT_SGBRG10
:
1314 buf
[0][offset
] = odd
? b_v
<< 2 : g_u_s
<< 2;
1315 buf
[0][offset
+ 1] = odd
? b_v
>> 6 : g_u_s
>> 6;
1316 buf
[1][offset
] = odd
? g_u_s
<< 2 : r_y_h
<< 2;
1317 buf
[1][offset
+ 1] = odd
? g_u_s
>> 6 : r_y_h
>> 6;
1318 buf
[0][offset
] |= (buf
[0][offset
] >> 2) & 3;
1319 buf
[1][offset
] |= (buf
[1][offset
] >> 2) & 3;
1321 case V4L2_PIX_FMT_SGRBG10
:
1322 buf
[0][offset
] = odd
? r_y_h
<< 2 : g_u_s
<< 2;
1323 buf
[0][offset
+ 1] = odd
? r_y_h
>> 6 : g_u_s
>> 6;
1324 buf
[1][offset
] = odd
? g_u_s
<< 2 : b_v
<< 2;
1325 buf
[1][offset
+ 1] = odd
? g_u_s
>> 6 : b_v
>> 6;
1326 buf
[0][offset
] |= (buf
[0][offset
] >> 2) & 3;
1327 buf
[1][offset
] |= (buf
[1][offset
] >> 2) & 3;
1329 case V4L2_PIX_FMT_SRGGB10
:
1330 buf
[0][offset
] = odd
? g_u_s
<< 2 : r_y_h
<< 2;
1331 buf
[0][offset
+ 1] = odd
? g_u_s
>> 6 : r_y_h
>> 6;
1332 buf
[1][offset
] = odd
? b_v
<< 2 : g_u_s
<< 2;
1333 buf
[1][offset
+ 1] = odd
? b_v
>> 6 : g_u_s
>> 6;
1334 buf
[0][offset
] |= (buf
[0][offset
] >> 2) & 3;
1335 buf
[1][offset
] |= (buf
[1][offset
] >> 2) & 3;
1337 case V4L2_PIX_FMT_SBGGR12
:
1338 buf
[0][offset
] = odd
? g_u_s
<< 4 : b_v
<< 4;
1339 buf
[0][offset
+ 1] = odd
? g_u_s
>> 4 : b_v
>> 4;
1340 buf
[1][offset
] = odd
? r_y_h
<< 4 : g_u_s
<< 4;
1341 buf
[1][offset
+ 1] = odd
? r_y_h
>> 4 : g_u_s
>> 4;
1342 buf
[0][offset
] |= (buf
[0][offset
] >> 4) & 0xf;
1343 buf
[1][offset
] |= (buf
[1][offset
] >> 4) & 0xf;
1345 case V4L2_PIX_FMT_SGBRG12
:
1346 buf
[0][offset
] = odd
? b_v
<< 4 : g_u_s
<< 4;
1347 buf
[0][offset
+ 1] = odd
? b_v
>> 4 : g_u_s
>> 4;
1348 buf
[1][offset
] = odd
? g_u_s
<< 4 : r_y_h
<< 4;
1349 buf
[1][offset
+ 1] = odd
? g_u_s
>> 4 : r_y_h
>> 4;
1350 buf
[0][offset
] |= (buf
[0][offset
] >> 4) & 0xf;
1351 buf
[1][offset
] |= (buf
[1][offset
] >> 4) & 0xf;
1353 case V4L2_PIX_FMT_SGRBG12
:
1354 buf
[0][offset
] = odd
? r_y_h
<< 4 : g_u_s
<< 4;
1355 buf
[0][offset
+ 1] = odd
? r_y_h
>> 4 : g_u_s
>> 4;
1356 buf
[1][offset
] = odd
? g_u_s
<< 4 : b_v
<< 4;
1357 buf
[1][offset
+ 1] = odd
? g_u_s
>> 4 : b_v
>> 4;
1358 buf
[0][offset
] |= (buf
[0][offset
] >> 4) & 0xf;
1359 buf
[1][offset
] |= (buf
[1][offset
] >> 4) & 0xf;
1361 case V4L2_PIX_FMT_SRGGB12
:
1362 buf
[0][offset
] = odd
? g_u_s
<< 4 : r_y_h
<< 4;
1363 buf
[0][offset
+ 1] = odd
? g_u_s
>> 4 : r_y_h
>> 4;
1364 buf
[1][offset
] = odd
? b_v
<< 4 : g_u_s
<< 4;
1365 buf
[1][offset
+ 1] = odd
? b_v
>> 4 : g_u_s
>> 4;
1366 buf
[0][offset
] |= (buf
[0][offset
] >> 4) & 0xf;
1367 buf
[1][offset
] |= (buf
[1][offset
] >> 4) & 0xf;
1369 case V4L2_PIX_FMT_SBGGR16
:
1370 buf
[0][offset
] = buf
[0][offset
+ 1] = odd
? g_u_s
: b_v
;
1371 buf
[1][offset
] = buf
[1][offset
+ 1] = odd
? r_y_h
: g_u_s
;
1373 case V4L2_PIX_FMT_SGBRG16
:
1374 buf
[0][offset
] = buf
[0][offset
+ 1] = odd
? b_v
: g_u_s
;
1375 buf
[1][offset
] = buf
[1][offset
+ 1] = odd
? g_u_s
: r_y_h
;
1377 case V4L2_PIX_FMT_SGRBG16
:
1378 buf
[0][offset
] = buf
[0][offset
+ 1] = odd
? r_y_h
: g_u_s
;
1379 buf
[1][offset
] = buf
[1][offset
+ 1] = odd
? g_u_s
: b_v
;
1381 case V4L2_PIX_FMT_SRGGB16
:
1382 buf
[0][offset
] = buf
[0][offset
+ 1] = odd
? g_u_s
: r_y_h
;
1383 buf
[1][offset
] = buf
[1][offset
+ 1] = odd
? b_v
: g_u_s
;
1388 unsigned tpg_g_interleaved_plane(const struct tpg_data
*tpg
, unsigned buf_line
)
1390 switch (tpg
->fourcc
) {
1391 case V4L2_PIX_FMT_SBGGR8
:
1392 case V4L2_PIX_FMT_SGBRG8
:
1393 case V4L2_PIX_FMT_SGRBG8
:
1394 case V4L2_PIX_FMT_SRGGB8
:
1395 case V4L2_PIX_FMT_SBGGR10
:
1396 case V4L2_PIX_FMT_SGBRG10
:
1397 case V4L2_PIX_FMT_SGRBG10
:
1398 case V4L2_PIX_FMT_SRGGB10
:
1399 case V4L2_PIX_FMT_SBGGR12
:
1400 case V4L2_PIX_FMT_SGBRG12
:
1401 case V4L2_PIX_FMT_SGRBG12
:
1402 case V4L2_PIX_FMT_SRGGB12
:
1403 case V4L2_PIX_FMT_SBGGR16
:
1404 case V4L2_PIX_FMT_SGBRG16
:
1405 case V4L2_PIX_FMT_SGRBG16
:
1406 case V4L2_PIX_FMT_SRGGB16
:
1407 return buf_line
& 1;
1412 EXPORT_SYMBOL_GPL(tpg_g_interleaved_plane
);
1414 /* Return how many pattern lines are used by the current pattern. */
1415 static unsigned tpg_get_pat_lines(const struct tpg_data
*tpg
)
1417 switch (tpg
->pattern
) {
1418 case TPG_PAT_CHECKERS_16X16
:
1419 case TPG_PAT_CHECKERS_2X2
:
1420 case TPG_PAT_CHECKERS_1X1
:
1421 case TPG_PAT_COLOR_CHECKERS_2X2
:
1422 case TPG_PAT_COLOR_CHECKERS_1X1
:
1423 case TPG_PAT_ALTERNATING_HLINES
:
1424 case TPG_PAT_CROSS_1_PIXEL
:
1425 case TPG_PAT_CROSS_2_PIXELS
:
1426 case TPG_PAT_CROSS_10_PIXELS
:
1428 case TPG_PAT_100_COLORSQUARES
:
1429 case TPG_PAT_100_HCOLORBAR
:
1436 /* Which pattern line should be used for the given frame line. */
1437 static unsigned tpg_get_pat_line(const struct tpg_data
*tpg
, unsigned line
)
1439 switch (tpg
->pattern
) {
1440 case TPG_PAT_CHECKERS_16X16
:
1441 return (line
>> 4) & 1;
1442 case TPG_PAT_CHECKERS_1X1
:
1443 case TPG_PAT_COLOR_CHECKERS_1X1
:
1444 case TPG_PAT_ALTERNATING_HLINES
:
1446 case TPG_PAT_CHECKERS_2X2
:
1447 case TPG_PAT_COLOR_CHECKERS_2X2
:
1448 return (line
& 2) >> 1;
1449 case TPG_PAT_100_COLORSQUARES
:
1450 case TPG_PAT_100_HCOLORBAR
:
1451 return (line
* 8) / tpg
->src_height
;
1452 case TPG_PAT_CROSS_1_PIXEL
:
1453 return line
== tpg
->src_height
/ 2;
1454 case TPG_PAT_CROSS_2_PIXELS
:
1455 return (line
+ 1) / 2 == tpg
->src_height
/ 4;
1456 case TPG_PAT_CROSS_10_PIXELS
:
1457 return (line
+ 10) / 20 == tpg
->src_height
/ 40;
1464 * Which color should be used for the given pattern line and X coordinate.
1465 * Note: x is in the range 0 to 2 * tpg->src_width.
1467 static enum tpg_color
tpg_get_color(const struct tpg_data
*tpg
,
1468 unsigned pat_line
, unsigned x
)
1470 /* Maximum number of bars are TPG_COLOR_MAX - otherwise, the input print code
1471 should be modified */
1472 static const enum tpg_color bars
[3][8] = {
1473 /* Standard ITU-R 75% color bar sequence */
1474 { TPG_COLOR_CSC_WHITE
, TPG_COLOR_75_YELLOW
,
1475 TPG_COLOR_75_CYAN
, TPG_COLOR_75_GREEN
,
1476 TPG_COLOR_75_MAGENTA
, TPG_COLOR_75_RED
,
1477 TPG_COLOR_75_BLUE
, TPG_COLOR_100_BLACK
, },
1478 /* Standard ITU-R 100% color bar sequence */
1479 { TPG_COLOR_100_WHITE
, TPG_COLOR_100_YELLOW
,
1480 TPG_COLOR_100_CYAN
, TPG_COLOR_100_GREEN
,
1481 TPG_COLOR_100_MAGENTA
, TPG_COLOR_100_RED
,
1482 TPG_COLOR_100_BLUE
, TPG_COLOR_100_BLACK
, },
1483 /* Color bar sequence suitable to test CSC */
1484 { TPG_COLOR_CSC_WHITE
, TPG_COLOR_CSC_YELLOW
,
1485 TPG_COLOR_CSC_CYAN
, TPG_COLOR_CSC_GREEN
,
1486 TPG_COLOR_CSC_MAGENTA
, TPG_COLOR_CSC_RED
,
1487 TPG_COLOR_CSC_BLUE
, TPG_COLOR_CSC_BLACK
, },
1490 switch (tpg
->pattern
) {
1491 case TPG_PAT_75_COLORBAR
:
1492 case TPG_PAT_100_COLORBAR
:
1493 case TPG_PAT_CSC_COLORBAR
:
1494 return bars
[tpg
->pattern
][((x
* 8) / tpg
->src_width
) % 8];
1495 case TPG_PAT_100_COLORSQUARES
:
1496 return bars
[1][(pat_line
+ (x
* 8) / tpg
->src_width
) % 8];
1497 case TPG_PAT_100_HCOLORBAR
:
1498 return bars
[1][pat_line
];
1500 return TPG_COLOR_100_BLACK
;
1502 return TPG_COLOR_100_WHITE
;
1504 return TPG_COLOR_100_RED
;
1506 return TPG_COLOR_100_GREEN
;
1508 return TPG_COLOR_100_BLUE
;
1509 case TPG_PAT_CHECKERS_16X16
:
1510 return (((x
>> 4) & 1) ^ (pat_line
& 1)) ?
1511 TPG_COLOR_100_BLACK
: TPG_COLOR_100_WHITE
;
1512 case TPG_PAT_CHECKERS_1X1
:
1513 return ((x
& 1) ^ (pat_line
& 1)) ?
1514 TPG_COLOR_100_WHITE
: TPG_COLOR_100_BLACK
;
1515 case TPG_PAT_COLOR_CHECKERS_1X1
:
1516 return ((x
& 1) ^ (pat_line
& 1)) ?
1517 TPG_COLOR_100_RED
: TPG_COLOR_100_BLUE
;
1518 case TPG_PAT_CHECKERS_2X2
:
1519 return (((x
>> 1) & 1) ^ (pat_line
& 1)) ?
1520 TPG_COLOR_100_WHITE
: TPG_COLOR_100_BLACK
;
1521 case TPG_PAT_COLOR_CHECKERS_2X2
:
1522 return (((x
>> 1) & 1) ^ (pat_line
& 1)) ?
1523 TPG_COLOR_100_RED
: TPG_COLOR_100_BLUE
;
1524 case TPG_PAT_ALTERNATING_HLINES
:
1525 return pat_line
? TPG_COLOR_100_WHITE
: TPG_COLOR_100_BLACK
;
1526 case TPG_PAT_ALTERNATING_VLINES
:
1527 return (x
& 1) ? TPG_COLOR_100_WHITE
: TPG_COLOR_100_BLACK
;
1528 case TPG_PAT_CROSS_1_PIXEL
:
1529 if (pat_line
|| (x
% tpg
->src_width
) == tpg
->src_width
/ 2)
1530 return TPG_COLOR_100_BLACK
;
1531 return TPG_COLOR_100_WHITE
;
1532 case TPG_PAT_CROSS_2_PIXELS
:
1533 if (pat_line
|| ((x
% tpg
->src_width
) + 1) / 2 == tpg
->src_width
/ 4)
1534 return TPG_COLOR_100_BLACK
;
1535 return TPG_COLOR_100_WHITE
;
1536 case TPG_PAT_CROSS_10_PIXELS
:
1537 if (pat_line
|| ((x
% tpg
->src_width
) + 10) / 20 == tpg
->src_width
/ 40)
1538 return TPG_COLOR_100_BLACK
;
1539 return TPG_COLOR_100_WHITE
;
1540 case TPG_PAT_GRAY_RAMP
:
1541 return TPG_COLOR_RAMP
+ ((x
% tpg
->src_width
) * 256) / tpg
->src_width
;
1543 return TPG_COLOR_100_RED
;
1548 * Given the pixel aspect ratio and video aspect ratio calculate the
1549 * coordinates of a centered square and the coordinates of the border of
1550 * the active video area. The coordinates are relative to the source
1553 static void tpg_calculate_square_border(struct tpg_data
*tpg
)
1555 unsigned w
= tpg
->src_width
;
1556 unsigned h
= tpg
->src_height
;
1557 unsigned sq_w
, sq_h
;
1559 sq_w
= (w
* 2 / 5) & ~1;
1560 if (((w
- sq_w
) / 2) & 1)
1563 tpg
->square
.width
= sq_w
;
1564 if (tpg
->vid_aspect
== TPG_VIDEO_ASPECT_16X9_ANAMORPHIC
) {
1565 unsigned ana_sq_w
= (sq_w
/ 4) * 3;
1567 if (((w
- ana_sq_w
) / 2) & 1)
1569 tpg
->square
.width
= ana_sq_w
;
1571 tpg
->square
.left
= (w
- tpg
->square
.width
) / 2;
1572 if (tpg
->pix_aspect
== TPG_PIXEL_ASPECT_NTSC
)
1573 sq_h
= sq_w
* 10 / 11;
1574 else if (tpg
->pix_aspect
== TPG_PIXEL_ASPECT_PAL
)
1575 sq_h
= sq_w
* 59 / 54;
1576 tpg
->square
.height
= sq_h
;
1577 tpg
->square
.top
= (h
- sq_h
) / 2;
1578 tpg
->border
.left
= 0;
1579 tpg
->border
.width
= w
;
1580 tpg
->border
.top
= 0;
1581 tpg
->border
.height
= h
;
1582 switch (tpg
->vid_aspect
) {
1583 case TPG_VIDEO_ASPECT_4X3
:
1584 if (tpg
->pix_aspect
)
1586 if (3 * w
>= 4 * h
) {
1587 tpg
->border
.width
= ((4 * h
) / 3) & ~1;
1588 if (((w
- tpg
->border
.width
) / 2) & ~1)
1589 tpg
->border
.width
-= 2;
1590 tpg
->border
.left
= (w
- tpg
->border
.width
) / 2;
1593 tpg
->border
.height
= ((3 * w
) / 4) & ~1;
1594 tpg
->border
.top
= (h
- tpg
->border
.height
) / 2;
1596 case TPG_VIDEO_ASPECT_14X9_CENTRE
:
1597 if (tpg
->pix_aspect
) {
1598 tpg
->border
.height
= tpg
->pix_aspect
== TPG_PIXEL_ASPECT_NTSC
? 420 : 506;
1599 tpg
->border
.top
= (h
- tpg
->border
.height
) / 2;
1602 if (9 * w
>= 14 * h
) {
1603 tpg
->border
.width
= ((14 * h
) / 9) & ~1;
1604 if (((w
- tpg
->border
.width
) / 2) & ~1)
1605 tpg
->border
.width
-= 2;
1606 tpg
->border
.left
= (w
- tpg
->border
.width
) / 2;
1609 tpg
->border
.height
= ((9 * w
) / 14) & ~1;
1610 tpg
->border
.top
= (h
- tpg
->border
.height
) / 2;
1612 case TPG_VIDEO_ASPECT_16X9_CENTRE
:
1613 if (tpg
->pix_aspect
) {
1614 tpg
->border
.height
= tpg
->pix_aspect
== TPG_PIXEL_ASPECT_NTSC
? 368 : 442;
1615 tpg
->border
.top
= (h
- tpg
->border
.height
) / 2;
1618 if (9 * w
>= 16 * h
) {
1619 tpg
->border
.width
= ((16 * h
) / 9) & ~1;
1620 if (((w
- tpg
->border
.width
) / 2) & ~1)
1621 tpg
->border
.width
-= 2;
1622 tpg
->border
.left
= (w
- tpg
->border
.width
) / 2;
1625 tpg
->border
.height
= ((9 * w
) / 16) & ~1;
1626 tpg
->border
.top
= (h
- tpg
->border
.height
) / 2;
1633 static void tpg_precalculate_line(struct tpg_data
*tpg
)
1635 enum tpg_color contrast
;
1636 u8 pix
[TPG_MAX_PLANES
][8];
1641 switch (tpg
->pattern
) {
1643 contrast
= TPG_COLOR_100_RED
;
1645 case TPG_PAT_CSC_COLORBAR
:
1646 contrast
= TPG_COLOR_CSC_GREEN
;
1649 contrast
= TPG_COLOR_100_GREEN
;
1653 for (pat
= 0; pat
< tpg_get_pat_lines(tpg
); pat
++) {
1654 /* Coarse scaling with Bresenham */
1655 unsigned int_part
= tpg
->src_width
/ tpg
->scaled_width
;
1656 unsigned fract_part
= tpg
->src_width
% tpg
->scaled_width
;
1660 for (x
= 0; x
< tpg
->scaled_width
* 2; x
+= 2) {
1661 unsigned real_x
= src_x
;
1662 enum tpg_color color1
, color2
;
1664 real_x
= tpg
->hflip
? tpg
->src_width
* 2 - real_x
- 2 : real_x
;
1665 color1
= tpg_get_color(tpg
, pat
, real_x
);
1668 error
+= fract_part
;
1669 if (error
>= tpg
->scaled_width
) {
1670 error
-= tpg
->scaled_width
;
1675 real_x
= tpg
->hflip
? tpg
->src_width
* 2 - real_x
- 2 : real_x
;
1676 color2
= tpg_get_color(tpg
, pat
, real_x
);
1679 error
+= fract_part
;
1680 if (error
>= tpg
->scaled_width
) {
1681 error
-= tpg
->scaled_width
;
1685 gen_twopix(tpg
, pix
, tpg
->hflip
? color2
: color1
, 0);
1686 gen_twopix(tpg
, pix
, tpg
->hflip
? color1
: color2
, 1);
1687 for (p
= 0; p
< tpg
->planes
; p
++) {
1688 unsigned twopixsize
= tpg
->twopixelsize
[p
];
1689 unsigned hdiv
= tpg
->hdownsampling
[p
];
1690 u8
*pos
= tpg
->lines
[pat
][p
] + tpg_hdiv(tpg
, p
, x
);
1692 memcpy(pos
, pix
[p
], twopixsize
/ hdiv
);
1697 if (tpg
->vdownsampling
[tpg
->planes
- 1] > 1) {
1698 unsigned pat_lines
= tpg_get_pat_lines(tpg
);
1700 for (pat
= 0; pat
< pat_lines
; pat
++) {
1701 unsigned next_pat
= (pat
+ 1) % pat_lines
;
1703 for (p
= 1; p
< tpg
->planes
; p
++) {
1704 unsigned w
= tpg_hdiv(tpg
, p
, tpg
->scaled_width
* 2);
1705 u8
*pos1
= tpg
->lines
[pat
][p
];
1706 u8
*pos2
= tpg
->lines
[next_pat
][p
];
1707 u8
*dest
= tpg
->downsampled_lines
[pat
][p
];
1709 for (x
= 0; x
< w
; x
++, pos1
++, pos2
++, dest
++)
1710 *dest
= ((u16
)*pos1
+ (u16
)*pos2
) / 2;
1715 gen_twopix(tpg
, pix
, contrast
, 0);
1716 gen_twopix(tpg
, pix
, contrast
, 1);
1717 for (p
= 0; p
< tpg
->planes
; p
++) {
1718 unsigned twopixsize
= tpg
->twopixelsize
[p
];
1719 u8
*pos
= tpg
->contrast_line
[p
];
1721 for (x
= 0; x
< tpg
->scaled_width
; x
+= 2, pos
+= twopixsize
)
1722 memcpy(pos
, pix
[p
], twopixsize
);
1725 gen_twopix(tpg
, pix
, TPG_COLOR_100_BLACK
, 0);
1726 gen_twopix(tpg
, pix
, TPG_COLOR_100_BLACK
, 1);
1727 for (p
= 0; p
< tpg
->planes
; p
++) {
1728 unsigned twopixsize
= tpg
->twopixelsize
[p
];
1729 u8
*pos
= tpg
->black_line
[p
];
1731 for (x
= 0; x
< tpg
->scaled_width
; x
+= 2, pos
+= twopixsize
)
1732 memcpy(pos
, pix
[p
], twopixsize
);
1735 for (x
= 0; x
< tpg
->scaled_width
* 2; x
+= 2) {
1736 gen_twopix(tpg
, pix
, TPG_COLOR_RANDOM
, 0);
1737 gen_twopix(tpg
, pix
, TPG_COLOR_RANDOM
, 1);
1738 for (p
= 0; p
< tpg
->planes
; p
++) {
1739 unsigned twopixsize
= tpg
->twopixelsize
[p
];
1740 u8
*pos
= tpg
->random_line
[p
] + x
* twopixsize
/ 2;
1742 memcpy(pos
, pix
[p
], twopixsize
);
1746 gen_twopix(tpg
, tpg
->textbg
, TPG_COLOR_TEXTBG
, 0);
1747 gen_twopix(tpg
, tpg
->textbg
, TPG_COLOR_TEXTBG
, 1);
1748 gen_twopix(tpg
, tpg
->textfg
, TPG_COLOR_TEXTFG
, 0);
1749 gen_twopix(tpg
, tpg
->textfg
, TPG_COLOR_TEXTFG
, 1);
1752 /* need this to do rgb24 rendering */
1753 typedef struct { u16 __
; u8 _
; } __packed x24
;
1755 #define PRINTSTR(PIXTYPE) do { \
1756 unsigned vdiv = tpg->vdownsampling[p]; \
1757 unsigned hdiv = tpg->hdownsampling[p]; \
1761 memcpy(&fg, tpg->textfg[p], sizeof(PIXTYPE)); \
1762 memcpy(&bg, tpg->textbg[p], sizeof(PIXTYPE)); \
1764 for (line = first; line < 16; line += vdiv * step) { \
1765 int l = tpg->vflip ? 15 - line : line; \
1766 PIXTYPE *pos = (PIXTYPE *)(basep[p][(line / vdiv) & 1] + \
1767 ((y * step + l) / (vdiv * div)) * tpg->bytesperline[p] + \
1768 (x / hdiv) * sizeof(PIXTYPE)); \
1771 for (s = 0; s < len; s++) { \
1772 u8 chr = font8x16[(u8)text[s] * 16 + line]; \
1774 if (hdiv == 2 && tpg->hflip) { \
1775 pos[3] = (chr & (0x01 << 6) ? fg : bg); \
1776 pos[2] = (chr & (0x01 << 4) ? fg : bg); \
1777 pos[1] = (chr & (0x01 << 2) ? fg : bg); \
1778 pos[0] = (chr & (0x01 << 0) ? fg : bg); \
1779 } else if (hdiv == 2) { \
1780 pos[0] = (chr & (0x01 << 7) ? fg : bg); \
1781 pos[1] = (chr & (0x01 << 5) ? fg : bg); \
1782 pos[2] = (chr & (0x01 << 3) ? fg : bg); \
1783 pos[3] = (chr & (0x01 << 1) ? fg : bg); \
1784 } else if (tpg->hflip) { \
1785 pos[7] = (chr & (0x01 << 7) ? fg : bg); \
1786 pos[6] = (chr & (0x01 << 6) ? fg : bg); \
1787 pos[5] = (chr & (0x01 << 5) ? fg : bg); \
1788 pos[4] = (chr & (0x01 << 4) ? fg : bg); \
1789 pos[3] = (chr & (0x01 << 3) ? fg : bg); \
1790 pos[2] = (chr & (0x01 << 2) ? fg : bg); \
1791 pos[1] = (chr & (0x01 << 1) ? fg : bg); \
1792 pos[0] = (chr & (0x01 << 0) ? fg : bg); \
1794 pos[0] = (chr & (0x01 << 7) ? fg : bg); \
1795 pos[1] = (chr & (0x01 << 6) ? fg : bg); \
1796 pos[2] = (chr & (0x01 << 5) ? fg : bg); \
1797 pos[3] = (chr & (0x01 << 4) ? fg : bg); \
1798 pos[4] = (chr & (0x01 << 3) ? fg : bg); \
1799 pos[5] = (chr & (0x01 << 2) ? fg : bg); \
1800 pos[6] = (chr & (0x01 << 1) ? fg : bg); \
1801 pos[7] = (chr & (0x01 << 0) ? fg : bg); \
1804 pos += (tpg->hflip ? -8 : 8) / (int)hdiv; \
1809 static noinline
void tpg_print_str_2(const struct tpg_data
*tpg
, u8
*basep
[TPG_MAX_PLANES
][2],
1810 unsigned p
, unsigned first
, unsigned div
, unsigned step
,
1811 int y
, int x
, char *text
, unsigned len
)
1816 static noinline
void tpg_print_str_4(const struct tpg_data
*tpg
, u8
*basep
[TPG_MAX_PLANES
][2],
1817 unsigned p
, unsigned first
, unsigned div
, unsigned step
,
1818 int y
, int x
, char *text
, unsigned len
)
1823 static noinline
void tpg_print_str_6(const struct tpg_data
*tpg
, u8
*basep
[TPG_MAX_PLANES
][2],
1824 unsigned p
, unsigned first
, unsigned div
, unsigned step
,
1825 int y
, int x
, char *text
, unsigned len
)
1830 static noinline
void tpg_print_str_8(const struct tpg_data
*tpg
, u8
*basep
[TPG_MAX_PLANES
][2],
1831 unsigned p
, unsigned first
, unsigned div
, unsigned step
,
1832 int y
, int x
, char *text
, unsigned len
)
1837 void tpg_gen_text(const struct tpg_data
*tpg
, u8
*basep
[TPG_MAX_PLANES
][2],
1838 int y
, int x
, char *text
)
1840 unsigned step
= V4L2_FIELD_HAS_T_OR_B(tpg
->field
) ? 2 : 1;
1841 unsigned div
= step
;
1843 unsigned len
= strlen(text
);
1846 if (font8x16
== NULL
|| basep
== NULL
)
1849 /* Checks if it is possible to show string */
1850 if (y
+ 16 >= tpg
->compose
.height
|| x
+ 8 >= tpg
->compose
.width
)
1853 if (len
> (tpg
->compose
.width
- x
) / 8)
1854 len
= (tpg
->compose
.width
- x
) / 8;
1856 y
= tpg
->compose
.height
- y
- 16;
1858 x
= tpg
->compose
.width
- x
- 8;
1859 y
+= tpg
->compose
.top
;
1860 x
+= tpg
->compose
.left
;
1861 if (tpg
->field
== V4L2_FIELD_BOTTOM
)
1863 else if (tpg
->field
== V4L2_FIELD_SEQ_TB
|| tpg
->field
== V4L2_FIELD_SEQ_BT
)
1866 for (p
= 0; p
< tpg
->planes
; p
++) {
1868 switch (tpg
->twopixelsize
[p
]) {
1870 tpg_print_str_2(tpg
, basep
, p
, first
, div
, step
, y
, x
,
1874 tpg_print_str_4(tpg
, basep
, p
, first
, div
, step
, y
, x
,
1878 tpg_print_str_6(tpg
, basep
, p
, first
, div
, step
, y
, x
,
1882 tpg_print_str_8(tpg
, basep
, p
, first
, div
, step
, y
, x
,
1888 EXPORT_SYMBOL_GPL(tpg_gen_text
);
1890 void tpg_update_mv_step(struct tpg_data
*tpg
)
1892 int factor
= tpg
->mv_hor_mode
> TPG_MOVE_NONE
? -1 : 1;
1896 switch (tpg
->mv_hor_mode
) {
1897 case TPG_MOVE_NEG_FAST
:
1898 case TPG_MOVE_POS_FAST
:
1899 tpg
->mv_hor_step
= ((tpg
->src_width
+ 319) / 320) * 4;
1903 tpg
->mv_hor_step
= ((tpg
->src_width
+ 639) / 640) * 4;
1905 case TPG_MOVE_NEG_SLOW
:
1906 case TPG_MOVE_POS_SLOW
:
1907 tpg
->mv_hor_step
= 2;
1910 tpg
->mv_hor_step
= 0;
1914 tpg
->mv_hor_step
= tpg
->src_width
- tpg
->mv_hor_step
;
1916 factor
= tpg
->mv_vert_mode
> TPG_MOVE_NONE
? -1 : 1;
1917 switch (tpg
->mv_vert_mode
) {
1918 case TPG_MOVE_NEG_FAST
:
1919 case TPG_MOVE_POS_FAST
:
1920 tpg
->mv_vert_step
= ((tpg
->src_width
+ 319) / 320) * 4;
1924 tpg
->mv_vert_step
= ((tpg
->src_width
+ 639) / 640) * 4;
1926 case TPG_MOVE_NEG_SLOW
:
1927 case TPG_MOVE_POS_SLOW
:
1928 tpg
->mv_vert_step
= 1;
1931 tpg
->mv_vert_step
= 0;
1935 tpg
->mv_vert_step
= tpg
->src_height
- tpg
->mv_vert_step
;
1937 EXPORT_SYMBOL_GPL(tpg_update_mv_step
);
1939 /* Map the line number relative to the crop rectangle to a frame line number */
1940 static unsigned tpg_calc_frameline(const struct tpg_data
*tpg
, unsigned src_y
,
1944 case V4L2_FIELD_TOP
:
1945 return tpg
->crop
.top
+ src_y
* 2;
1946 case V4L2_FIELD_BOTTOM
:
1947 return tpg
->crop
.top
+ src_y
* 2 + 1;
1949 return src_y
+ tpg
->crop
.top
;
1954 * Map the line number relative to the compose rectangle to a destination
1955 * buffer line number.
1957 static unsigned tpg_calc_buffer_line(const struct tpg_data
*tpg
, unsigned y
,
1960 y
+= tpg
->compose
.top
;
1962 case V4L2_FIELD_SEQ_TB
:
1964 return tpg
->buf_height
/ 2 + y
/ 2;
1966 case V4L2_FIELD_SEQ_BT
:
1969 return tpg
->buf_height
/ 2 + y
/ 2;
1975 static void tpg_recalc(struct tpg_data
*tpg
)
1977 if (tpg
->recalc_colors
) {
1978 tpg
->recalc_colors
= false;
1979 tpg
->recalc_lines
= true;
1980 tpg
->real_xfer_func
= tpg
->xfer_func
;
1981 tpg
->real_ycbcr_enc
= tpg
->ycbcr_enc
;
1982 tpg
->real_hsv_enc
= tpg
->hsv_enc
;
1983 tpg
->real_quantization
= tpg
->quantization
;
1985 if (tpg
->xfer_func
== V4L2_XFER_FUNC_DEFAULT
)
1986 tpg
->real_xfer_func
=
1987 V4L2_MAP_XFER_FUNC_DEFAULT(tpg
->colorspace
);
1989 if (tpg
->ycbcr_enc
== V4L2_YCBCR_ENC_DEFAULT
)
1990 tpg
->real_ycbcr_enc
=
1991 V4L2_MAP_YCBCR_ENC_DEFAULT(tpg
->colorspace
);
1993 if (tpg
->quantization
== V4L2_QUANTIZATION_DEFAULT
)
1994 tpg
->real_quantization
=
1995 V4L2_MAP_QUANTIZATION_DEFAULT(
1996 tpg
->color_enc
!= TGP_COLOR_ENC_YCBCR
,
1997 tpg
->colorspace
, tpg
->real_ycbcr_enc
);
1999 tpg_precalculate_colors(tpg
);
2001 if (tpg
->recalc_square_border
) {
2002 tpg
->recalc_square_border
= false;
2003 tpg_calculate_square_border(tpg
);
2005 if (tpg
->recalc_lines
) {
2006 tpg
->recalc_lines
= false;
2007 tpg_precalculate_line(tpg
);
2011 void tpg_calc_text_basep(struct tpg_data
*tpg
,
2012 u8
*basep
[TPG_MAX_PLANES
][2], unsigned p
, u8
*vbuf
)
2014 unsigned stride
= tpg
->bytesperline
[p
];
2015 unsigned h
= tpg
->buf_height
;
2021 h
/= tpg
->vdownsampling
[p
];
2022 if (tpg
->field
== V4L2_FIELD_SEQ_TB
)
2023 basep
[p
][1] += h
* stride
/ 2;
2024 else if (tpg
->field
== V4L2_FIELD_SEQ_BT
)
2025 basep
[p
][0] += h
* stride
/ 2;
2026 if (p
== 0 && tpg
->interleaved
)
2027 tpg_calc_text_basep(tpg
, basep
, 1, vbuf
);
2029 EXPORT_SYMBOL_GPL(tpg_calc_text_basep
);
2031 static int tpg_pattern_avg(const struct tpg_data
*tpg
,
2032 unsigned pat1
, unsigned pat2
)
2034 unsigned pat_lines
= tpg_get_pat_lines(tpg
);
2036 if (pat1
== (pat2
+ 1) % pat_lines
)
2038 if (pat2
== (pat1
+ 1) % pat_lines
)
2043 static const char *tpg_color_enc_str(enum tgp_color_enc
2046 switch (color_enc
) {
2047 case TGP_COLOR_ENC_HSV
:
2049 case TGP_COLOR_ENC_YCBCR
:
2051 case TGP_COLOR_ENC_LUMA
:
2053 case TGP_COLOR_ENC_RGB
:
2060 void tpg_log_status(struct tpg_data
*tpg
)
2062 pr_info("tpg source WxH: %ux%u (%s)\n",
2063 tpg
->src_width
, tpg
->src_height
,
2064 tpg_color_enc_str(tpg
->color_enc
));
2065 pr_info("tpg field: %u\n", tpg
->field
);
2066 pr_info("tpg crop: %ux%u@%dx%d\n", tpg
->crop
.width
, tpg
->crop
.height
,
2067 tpg
->crop
.left
, tpg
->crop
.top
);
2068 pr_info("tpg compose: %ux%u@%dx%d\n", tpg
->compose
.width
, tpg
->compose
.height
,
2069 tpg
->compose
.left
, tpg
->compose
.top
);
2070 pr_info("tpg colorspace: %d\n", tpg
->colorspace
);
2071 pr_info("tpg transfer function: %d/%d\n", tpg
->xfer_func
, tpg
->real_xfer_func
);
2072 if (tpg
->color_enc
== TGP_COLOR_ENC_HSV
)
2073 pr_info("tpg HSV encoding: %d/%d\n",
2074 tpg
->hsv_enc
, tpg
->real_hsv_enc
);
2075 else if (tpg
->color_enc
== TGP_COLOR_ENC_YCBCR
)
2076 pr_info("tpg Y'CbCr encoding: %d/%d\n",
2077 tpg
->ycbcr_enc
, tpg
->real_ycbcr_enc
);
2078 pr_info("tpg quantization: %d/%d\n", tpg
->quantization
, tpg
->real_quantization
);
2079 pr_info("tpg RGB range: %d/%d\n", tpg
->rgb_range
, tpg
->real_rgb_range
);
2081 EXPORT_SYMBOL_GPL(tpg_log_status
);
2084 * This struct contains common parameters used by both the drawing of the
2085 * test pattern and the drawing of the extras (borders, square, etc.)
2087 struct tpg_draw_params
{
2091 unsigned twopixsize
;
2095 unsigned frame_line
;
2096 unsigned frame_line_next
;
2099 unsigned mv_hor_old
;
2100 unsigned mv_hor_new
;
2101 unsigned mv_vert_old
;
2102 unsigned mv_vert_new
;
2106 unsigned wss_random_offset
;
2108 unsigned left_pillar_width
;
2109 unsigned right_pillar_start
;
2112 static void tpg_fill_params_pattern(const struct tpg_data
*tpg
, unsigned p
,
2113 struct tpg_draw_params
*params
)
2115 params
->mv_hor_old
=
2116 tpg_hscale_div(tpg
, p
, tpg
->mv_hor_count
% tpg
->src_width
);
2117 params
->mv_hor_new
=
2118 tpg_hscale_div(tpg
, p
, (tpg
->mv_hor_count
+ tpg
->mv_hor_step
) %
2120 params
->mv_vert_old
= tpg
->mv_vert_count
% tpg
->src_height
;
2121 params
->mv_vert_new
=
2122 (tpg
->mv_vert_count
+ tpg
->mv_vert_step
) % tpg
->src_height
;
2125 static void tpg_fill_params_extras(const struct tpg_data
*tpg
,
2127 struct tpg_draw_params
*params
)
2129 unsigned left_pillar_width
= 0;
2130 unsigned right_pillar_start
= params
->img_width
;
2132 params
->wss_width
= tpg
->crop
.left
< tpg
->src_width
/ 2 ?
2133 tpg
->src_width
/ 2 - tpg
->crop
.left
: 0;
2134 if (params
->wss_width
> tpg
->crop
.width
)
2135 params
->wss_width
= tpg
->crop
.width
;
2136 params
->wss_width
= tpg_hscale_div(tpg
, p
, params
->wss_width
);
2137 params
->wss_random_offset
=
2138 params
->twopixsize
* prandom_u32_max(tpg
->src_width
/ 2);
2140 if (tpg
->crop
.left
< tpg
->border
.left
) {
2141 left_pillar_width
= tpg
->border
.left
- tpg
->crop
.left
;
2142 if (left_pillar_width
> tpg
->crop
.width
)
2143 left_pillar_width
= tpg
->crop
.width
;
2144 left_pillar_width
= tpg_hscale_div(tpg
, p
, left_pillar_width
);
2146 params
->left_pillar_width
= left_pillar_width
;
2148 if (tpg
->crop
.left
+ tpg
->crop
.width
>
2149 tpg
->border
.left
+ tpg
->border
.width
) {
2150 right_pillar_start
=
2151 tpg
->border
.left
+ tpg
->border
.width
- tpg
->crop
.left
;
2152 right_pillar_start
=
2153 tpg_hscale_div(tpg
, p
, right_pillar_start
);
2154 if (right_pillar_start
> params
->img_width
)
2155 right_pillar_start
= params
->img_width
;
2157 params
->right_pillar_start
= right_pillar_start
;
2159 params
->sav_eav_f
= tpg
->field
==
2160 (params
->is_60hz
? V4L2_FIELD_TOP
: V4L2_FIELD_BOTTOM
);
2163 static void tpg_fill_plane_extras(const struct tpg_data
*tpg
,
2164 const struct tpg_draw_params
*params
,
2165 unsigned p
, unsigned h
, u8
*vbuf
)
2167 unsigned twopixsize
= params
->twopixsize
;
2168 unsigned img_width
= params
->img_width
;
2169 unsigned frame_line
= params
->frame_line
;
2170 const struct v4l2_rect
*sq
= &tpg
->square
;
2171 const struct v4l2_rect
*b
= &tpg
->border
;
2172 const struct v4l2_rect
*c
= &tpg
->crop
;
2174 if (params
->is_tv
&& !params
->is_60hz
&&
2175 frame_line
== 0 && params
->wss_width
) {
2177 * Replace the first half of the top line of a 50 Hz frame
2178 * with random data to simulate a WSS signal.
2180 u8
*wss
= tpg
->random_line
[p
] + params
->wss_random_offset
;
2182 memcpy(vbuf
, wss
, params
->wss_width
);
2185 if (tpg
->show_border
&& frame_line
>= b
->top
&&
2186 frame_line
< b
->top
+ b
->height
) {
2187 unsigned bottom
= b
->top
+ b
->height
- 1;
2188 unsigned left
= params
->left_pillar_width
;
2189 unsigned right
= params
->right_pillar_start
;
2191 if (frame_line
== b
->top
|| frame_line
== b
->top
+ 1 ||
2192 frame_line
== bottom
|| frame_line
== bottom
- 1) {
2193 memcpy(vbuf
+ left
, tpg
->contrast_line
[p
],
2196 if (b
->left
>= c
->left
&&
2197 b
->left
< c
->left
+ c
->width
)
2199 tpg
->contrast_line
[p
], twopixsize
);
2200 if (b
->left
+ b
->width
> c
->left
&&
2201 b
->left
+ b
->width
<= c
->left
+ c
->width
)
2202 memcpy(vbuf
+ right
- twopixsize
,
2203 tpg
->contrast_line
[p
], twopixsize
);
2206 if (tpg
->qual
!= TPG_QUAL_NOISE
&& frame_line
>= b
->top
&&
2207 frame_line
< b
->top
+ b
->height
) {
2208 memcpy(vbuf
, tpg
->black_line
[p
], params
->left_pillar_width
);
2209 memcpy(vbuf
+ params
->right_pillar_start
, tpg
->black_line
[p
],
2210 img_width
- params
->right_pillar_start
);
2212 if (tpg
->show_square
&& frame_line
>= sq
->top
&&
2213 frame_line
< sq
->top
+ sq
->height
&&
2214 sq
->left
< c
->left
+ c
->width
&&
2215 sq
->left
+ sq
->width
>= c
->left
) {
2216 unsigned left
= sq
->left
;
2217 unsigned width
= sq
->width
;
2219 if (c
->left
> left
) {
2220 width
-= c
->left
- left
;
2223 if (c
->left
+ c
->width
< left
+ width
)
2224 width
-= left
+ width
- c
->left
- c
->width
;
2226 left
= tpg_hscale_div(tpg
, p
, left
);
2227 width
= tpg_hscale_div(tpg
, p
, width
);
2228 memcpy(vbuf
+ left
, tpg
->contrast_line
[p
], width
);
2230 if (tpg
->insert_sav
) {
2231 unsigned offset
= tpg_hdiv(tpg
, p
, tpg
->compose
.width
/ 3);
2232 u8
*p
= vbuf
+ offset
;
2233 unsigned vact
= 0, hact
= 0;
2238 p
[3] = 0x80 | (params
->sav_eav_f
<< 6) |
2239 (vact
<< 5) | (hact
<< 4) |
2240 ((hact
^ vact
) << 3) |
2241 ((hact
^ params
->sav_eav_f
) << 2) |
2242 ((params
->sav_eav_f
^ vact
) << 1) |
2243 (hact
^ vact
^ params
->sav_eav_f
);
2245 if (tpg
->insert_eav
) {
2246 unsigned offset
= tpg_hdiv(tpg
, p
, tpg
->compose
.width
* 2 / 3);
2247 u8
*p
= vbuf
+ offset
;
2248 unsigned vact
= 0, hact
= 1;
2253 p
[3] = 0x80 | (params
->sav_eav_f
<< 6) |
2254 (vact
<< 5) | (hact
<< 4) |
2255 ((hact
^ vact
) << 3) |
2256 ((hact
^ params
->sav_eav_f
) << 2) |
2257 ((params
->sav_eav_f
^ vact
) << 1) |
2258 (hact
^ vact
^ params
->sav_eav_f
);
2262 static void tpg_fill_plane_pattern(const struct tpg_data
*tpg
,
2263 const struct tpg_draw_params
*params
,
2264 unsigned p
, unsigned h
, u8
*vbuf
)
2266 unsigned twopixsize
= params
->twopixsize
;
2267 unsigned img_width
= params
->img_width
;
2268 unsigned mv_hor_old
= params
->mv_hor_old
;
2269 unsigned mv_hor_new
= params
->mv_hor_new
;
2270 unsigned mv_vert_old
= params
->mv_vert_old
;
2271 unsigned mv_vert_new
= params
->mv_vert_new
;
2272 unsigned frame_line
= params
->frame_line
;
2273 unsigned frame_line_next
= params
->frame_line_next
;
2274 unsigned line_offset
= tpg_hscale_div(tpg
, p
, tpg
->crop
.left
);
2276 bool fill_blank
= false;
2277 unsigned pat_line_old
;
2278 unsigned pat_line_new
;
2279 u8
*linestart_older
;
2280 u8
*linestart_newer
;
2282 u8
*linestart_bottom
;
2284 even
= !(frame_line
& 1);
2286 if (h
>= params
->hmax
) {
2287 if (params
->hmax
== tpg
->compose
.height
)
2289 if (!tpg
->perc_fill_blank
)
2295 frame_line
= tpg
->src_height
- frame_line
- 1;
2296 frame_line_next
= tpg
->src_height
- frame_line_next
- 1;
2300 linestart_older
= tpg
->contrast_line
[p
];
2301 linestart_newer
= tpg
->contrast_line
[p
];
2302 } else if (tpg
->qual
!= TPG_QUAL_NOISE
&&
2303 (frame_line
< tpg
->border
.top
||
2304 frame_line
>= tpg
->border
.top
+ tpg
->border
.height
)) {
2305 linestart_older
= tpg
->black_line
[p
];
2306 linestart_newer
= tpg
->black_line
[p
];
2307 } else if (tpg
->pattern
== TPG_PAT_NOISE
|| tpg
->qual
== TPG_QUAL_NOISE
) {
2308 linestart_older
= tpg
->random_line
[p
] +
2309 twopixsize
* prandom_u32_max(tpg
->src_width
/ 2);
2310 linestart_newer
= tpg
->random_line
[p
] +
2311 twopixsize
* prandom_u32_max(tpg
->src_width
/ 2);
2313 unsigned frame_line_old
=
2314 (frame_line
+ mv_vert_old
) % tpg
->src_height
;
2315 unsigned frame_line_new
=
2316 (frame_line
+ mv_vert_new
) % tpg
->src_height
;
2317 unsigned pat_line_next_old
;
2318 unsigned pat_line_next_new
;
2320 pat_line_old
= tpg_get_pat_line(tpg
, frame_line_old
);
2321 pat_line_new
= tpg_get_pat_line(tpg
, frame_line_new
);
2322 linestart_older
= tpg
->lines
[pat_line_old
][p
] + mv_hor_old
;
2323 linestart_newer
= tpg
->lines
[pat_line_new
][p
] + mv_hor_new
;
2325 if (tpg
->vdownsampling
[p
] > 1 && frame_line
!= frame_line_next
) {
2329 * Now decide whether we need to use downsampled_lines[].
2330 * That's necessary if the two lines use different patterns.
2332 pat_line_next_old
= tpg_get_pat_line(tpg
,
2333 (frame_line_next
+ mv_vert_old
) % tpg
->src_height
);
2334 pat_line_next_new
= tpg_get_pat_line(tpg
,
2335 (frame_line_next
+ mv_vert_new
) % tpg
->src_height
);
2337 switch (tpg
->field
) {
2338 case V4L2_FIELD_INTERLACED
:
2339 case V4L2_FIELD_INTERLACED_BT
:
2340 case V4L2_FIELD_INTERLACED_TB
:
2341 avg_pat
= tpg_pattern_avg(tpg
, pat_line_old
, pat_line_new
);
2344 linestart_older
= tpg
->downsampled_lines
[avg_pat
][p
] + mv_hor_old
;
2345 linestart_newer
= linestart_older
;
2347 case V4L2_FIELD_NONE
:
2348 case V4L2_FIELD_TOP
:
2349 case V4L2_FIELD_BOTTOM
:
2350 case V4L2_FIELD_SEQ_BT
:
2351 case V4L2_FIELD_SEQ_TB
:
2352 avg_pat
= tpg_pattern_avg(tpg
, pat_line_old
, pat_line_next_old
);
2354 linestart_older
= tpg
->downsampled_lines
[avg_pat
][p
] +
2356 avg_pat
= tpg_pattern_avg(tpg
, pat_line_new
, pat_line_next_new
);
2358 linestart_newer
= tpg
->downsampled_lines
[avg_pat
][p
] +
2363 linestart_older
+= line_offset
;
2364 linestart_newer
+= line_offset
;
2366 if (tpg
->field_alternate
) {
2367 linestart_top
= linestart_bottom
= linestart_older
;
2368 } else if (params
->is_60hz
) {
2369 linestart_top
= linestart_newer
;
2370 linestart_bottom
= linestart_older
;
2372 linestart_top
= linestart_older
;
2373 linestart_bottom
= linestart_newer
;
2376 switch (tpg
->field
) {
2377 case V4L2_FIELD_INTERLACED
:
2378 case V4L2_FIELD_INTERLACED_TB
:
2379 case V4L2_FIELD_SEQ_TB
:
2380 case V4L2_FIELD_SEQ_BT
:
2382 memcpy(vbuf
, linestart_top
, img_width
);
2384 memcpy(vbuf
, linestart_bottom
, img_width
);
2386 case V4L2_FIELD_INTERLACED_BT
:
2388 memcpy(vbuf
, linestart_bottom
, img_width
);
2390 memcpy(vbuf
, linestart_top
, img_width
);
2392 case V4L2_FIELD_TOP
:
2393 memcpy(vbuf
, linestart_top
, img_width
);
2395 case V4L2_FIELD_BOTTOM
:
2396 memcpy(vbuf
, linestart_bottom
, img_width
);
2398 case V4L2_FIELD_NONE
:
2400 memcpy(vbuf
, linestart_older
, img_width
);
2405 void tpg_fill_plane_buffer(struct tpg_data
*tpg
, v4l2_std_id std
,
2406 unsigned p
, u8
*vbuf
)
2408 struct tpg_draw_params params
;
2409 unsigned factor
= V4L2_FIELD_HAS_T_OR_B(tpg
->field
) ? 2 : 1;
2411 /* Coarse scaling with Bresenham */
2412 unsigned int_part
= (tpg
->crop
.height
/ factor
) / tpg
->compose
.height
;
2413 unsigned fract_part
= (tpg
->crop
.height
/ factor
) % tpg
->compose
.height
;
2421 params
.is_60hz
= std
& V4L2_STD_525_60
;
2422 params
.twopixsize
= tpg
->twopixelsize
[p
];
2423 params
.img_width
= tpg_hdiv(tpg
, p
, tpg
->compose
.width
);
2424 params
.stride
= tpg
->bytesperline
[p
];
2425 params
.hmax
= (tpg
->compose
.height
* tpg
->perc_fill
) / 100;
2427 tpg_fill_params_pattern(tpg
, p
, ¶ms
);
2428 tpg_fill_params_extras(tpg
, p
, ¶ms
);
2430 vbuf
+= tpg_hdiv(tpg
, p
, tpg
->compose
.left
);
2432 for (h
= 0; h
< tpg
->compose
.height
; h
++) {
2435 params
.frame_line
= tpg_calc_frameline(tpg
, src_y
, tpg
->field
);
2436 params
.frame_line_next
= params
.frame_line
;
2437 buf_line
= tpg_calc_buffer_line(tpg
, h
, tpg
->field
);
2439 error
+= fract_part
;
2440 if (error
>= tpg
->compose
.height
) {
2441 error
-= tpg
->compose
.height
;
2446 * For line-interleaved formats determine the 'plane'
2447 * based on the buffer line.
2449 if (tpg_g_interleaved(tpg
))
2450 p
= tpg_g_interleaved_plane(tpg
, buf_line
);
2452 if (tpg
->vdownsampling
[p
] > 1) {
2454 * When doing vertical downsampling the field setting
2455 * matters: for SEQ_BT/TB we downsample each field
2456 * separately (i.e. lines 0+2 are combined, as are
2457 * lines 1+3), for the other field settings we combine
2458 * odd and even lines. Doing that for SEQ_BT/TB would
2461 if (tpg
->field
== V4L2_FIELD_SEQ_BT
||
2462 tpg
->field
== V4L2_FIELD_SEQ_TB
) {
2463 unsigned next_src_y
= src_y
;
2467 next_src_y
+= int_part
;
2468 if (error
+ fract_part
>= tpg
->compose
.height
)
2470 params
.frame_line_next
=
2471 tpg_calc_frameline(tpg
, next_src_y
, tpg
->field
);
2475 params
.frame_line_next
=
2476 tpg_calc_frameline(tpg
, src_y
, tpg
->field
);
2479 buf_line
/= tpg
->vdownsampling
[p
];
2481 tpg_fill_plane_pattern(tpg
, ¶ms
, p
, h
,
2482 vbuf
+ buf_line
* params
.stride
);
2483 tpg_fill_plane_extras(tpg
, ¶ms
, p
, h
,
2484 vbuf
+ buf_line
* params
.stride
);
2487 EXPORT_SYMBOL_GPL(tpg_fill_plane_buffer
);
2489 void tpg_fillbuffer(struct tpg_data
*tpg
, v4l2_std_id std
, unsigned p
, u8
*vbuf
)
2491 unsigned offset
= 0;
2494 if (tpg
->buffers
> 1) {
2495 tpg_fill_plane_buffer(tpg
, std
, p
, vbuf
);
2499 for (i
= 0; i
< tpg_g_planes(tpg
); i
++) {
2500 tpg_fill_plane_buffer(tpg
, std
, i
, vbuf
+ offset
);
2501 offset
+= tpg_calc_plane_size(tpg
, i
);
2504 EXPORT_SYMBOL_GPL(tpg_fillbuffer
);
2506 MODULE_DESCRIPTION("V4L2 Test Pattern Generator");
2507 MODULE_AUTHOR("Hans Verkuil");
2508 MODULE_LICENSE("GPL");