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
23 #include <linux/module.h>
24 #include <media/tpg/v4l2-tpg.h>
26 /* Must remain in sync with enum tpg_pattern */
27 const char * const tpg_pattern_strings
[] = {
31 "Horizontal 100% Colorbar",
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",
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",
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
)
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;
112 tpg
->saturation
= 128;
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
)
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
])
139 tpg
->downsampled_lines
[pat
][plane
] = vzalloc(max_w
* 2 * pixelsz
);
140 if (!tpg
->downsampled_lines
[pat
][plane
])
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
])
150 tpg
->black_line
[plane
] = vzalloc(max_w
* pixelsz
);
151 if (!tpg
->black_line
[plane
])
153 tpg
->random_line
[plane
] = vzalloc(max_w
* 2 * pixelsz
);
154 if (!tpg
->random_line
[plane
])
159 EXPORT_SYMBOL_GPL(tpg_alloc
);
161 void tpg_free(struct tpg_data
*tpg
)
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
;
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
;
191 tpg
->recalc_colors
= true;
192 tpg
->interleaved
= false;
193 tpg
->vdownsampling
[0] = 1;
194 tpg
->hdownsampling
[0] = 1;
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;
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
;
240 case V4L2_PIX_FMT_GREY
:
241 case V4L2_PIX_FMT_Y10
:
242 case V4L2_PIX_FMT_Y12
:
243 case V4L2_PIX_FMT_Y16
:
244 case V4L2_PIX_FMT_Y16_BE
:
245 tpg
->color_enc
= TGP_COLOR_ENC_LUMA
;
247 case V4L2_PIX_FMT_YUV444
:
248 case V4L2_PIX_FMT_YUV555
:
249 case V4L2_PIX_FMT_YUV565
:
250 case V4L2_PIX_FMT_YUV32
:
251 tpg
->color_enc
= TGP_COLOR_ENC_YCBCR
;
253 case V4L2_PIX_FMT_YUV420M
:
254 case V4L2_PIX_FMT_YVU420M
:
257 case V4L2_PIX_FMT_YUV420
:
258 case V4L2_PIX_FMT_YVU420
:
259 tpg
->vdownsampling
[1] = 2;
260 tpg
->vdownsampling
[2] = 2;
261 tpg
->hdownsampling
[1] = 2;
262 tpg
->hdownsampling
[2] = 2;
264 tpg
->color_enc
= TGP_COLOR_ENC_YCBCR
;
266 case V4L2_PIX_FMT_YUV422M
:
267 case V4L2_PIX_FMT_YVU422M
:
270 case V4L2_PIX_FMT_YUV422P
:
271 tpg
->vdownsampling
[1] = 1;
272 tpg
->vdownsampling
[2] = 1;
273 tpg
->hdownsampling
[1] = 2;
274 tpg
->hdownsampling
[2] = 2;
276 tpg
->color_enc
= TGP_COLOR_ENC_YCBCR
;
278 case V4L2_PIX_FMT_NV16M
:
279 case V4L2_PIX_FMT_NV61M
:
282 case V4L2_PIX_FMT_NV16
:
283 case V4L2_PIX_FMT_NV61
:
284 tpg
->vdownsampling
[1] = 1;
285 tpg
->hdownsampling
[1] = 1;
288 tpg
->color_enc
= TGP_COLOR_ENC_YCBCR
;
290 case V4L2_PIX_FMT_NV12M
:
291 case V4L2_PIX_FMT_NV21M
:
294 case V4L2_PIX_FMT_NV12
:
295 case V4L2_PIX_FMT_NV21
:
296 tpg
->vdownsampling
[1] = 2;
297 tpg
->hdownsampling
[1] = 1;
300 tpg
->color_enc
= TGP_COLOR_ENC_YCBCR
;
302 case V4L2_PIX_FMT_YUV444M
:
303 case V4L2_PIX_FMT_YVU444M
:
306 tpg
->vdownsampling
[1] = 1;
307 tpg
->vdownsampling
[2] = 1;
308 tpg
->hdownsampling
[1] = 1;
309 tpg
->hdownsampling
[2] = 1;
310 tpg
->color_enc
= TGP_COLOR_ENC_YCBCR
;
312 case V4L2_PIX_FMT_NV24
:
313 case V4L2_PIX_FMT_NV42
:
314 tpg
->vdownsampling
[1] = 1;
315 tpg
->hdownsampling
[1] = 1;
317 tpg
->color_enc
= TGP_COLOR_ENC_YCBCR
;
319 case V4L2_PIX_FMT_YUYV
:
320 case V4L2_PIX_FMT_UYVY
:
321 case V4L2_PIX_FMT_YVYU
:
322 case V4L2_PIX_FMT_VYUY
:
324 tpg
->color_enc
= TGP_COLOR_ENC_YCBCR
;
326 case V4L2_PIX_FMT_HSV24
:
327 case V4L2_PIX_FMT_HSV32
:
328 tpg
->color_enc
= TGP_COLOR_ENC_HSV
;
335 case V4L2_PIX_FMT_GREY
:
336 case V4L2_PIX_FMT_RGB332
:
337 tpg
->twopixelsize
[0] = 2;
339 case V4L2_PIX_FMT_RGB565
:
340 case V4L2_PIX_FMT_RGB565X
:
341 case V4L2_PIX_FMT_RGB444
:
342 case V4L2_PIX_FMT_XRGB444
:
343 case V4L2_PIX_FMT_ARGB444
:
344 case V4L2_PIX_FMT_RGB555
:
345 case V4L2_PIX_FMT_XRGB555
:
346 case V4L2_PIX_FMT_ARGB555
:
347 case V4L2_PIX_FMT_RGB555X
:
348 case V4L2_PIX_FMT_XRGB555X
:
349 case V4L2_PIX_FMT_ARGB555X
:
350 case V4L2_PIX_FMT_YUYV
:
351 case V4L2_PIX_FMT_UYVY
:
352 case V4L2_PIX_FMT_YVYU
:
353 case V4L2_PIX_FMT_VYUY
:
354 case V4L2_PIX_FMT_YUV444
:
355 case V4L2_PIX_FMT_YUV555
:
356 case V4L2_PIX_FMT_YUV565
:
357 case V4L2_PIX_FMT_Y10
:
358 case V4L2_PIX_FMT_Y12
:
359 case V4L2_PIX_FMT_Y16
:
360 case V4L2_PIX_FMT_Y16_BE
:
361 tpg
->twopixelsize
[0] = 2 * 2;
363 case V4L2_PIX_FMT_RGB24
:
364 case V4L2_PIX_FMT_BGR24
:
365 case V4L2_PIX_FMT_HSV24
:
366 tpg
->twopixelsize
[0] = 2 * 3;
368 case V4L2_PIX_FMT_BGR666
:
369 case V4L2_PIX_FMT_RGB32
:
370 case V4L2_PIX_FMT_BGR32
:
371 case V4L2_PIX_FMT_XRGB32
:
372 case V4L2_PIX_FMT_XBGR32
:
373 case V4L2_PIX_FMT_ARGB32
:
374 case V4L2_PIX_FMT_ABGR32
:
375 case V4L2_PIX_FMT_YUV32
:
376 case V4L2_PIX_FMT_HSV32
:
377 tpg
->twopixelsize
[0] = 2 * 4;
379 case V4L2_PIX_FMT_NV12
:
380 case V4L2_PIX_FMT_NV21
:
381 case V4L2_PIX_FMT_NV12M
:
382 case V4L2_PIX_FMT_NV21M
:
383 case V4L2_PIX_FMT_NV16
:
384 case V4L2_PIX_FMT_NV61
:
385 case V4L2_PIX_FMT_NV16M
:
386 case V4L2_PIX_FMT_NV61M
:
387 case V4L2_PIX_FMT_SBGGR8
:
388 case V4L2_PIX_FMT_SGBRG8
:
389 case V4L2_PIX_FMT_SGRBG8
:
390 case V4L2_PIX_FMT_SRGGB8
:
391 tpg
->twopixelsize
[0] = 2;
392 tpg
->twopixelsize
[1] = 2;
394 case V4L2_PIX_FMT_SRGGB10
:
395 case V4L2_PIX_FMT_SGRBG10
:
396 case V4L2_PIX_FMT_SGBRG10
:
397 case V4L2_PIX_FMT_SBGGR10
:
398 case V4L2_PIX_FMT_SRGGB12
:
399 case V4L2_PIX_FMT_SGRBG12
:
400 case V4L2_PIX_FMT_SGBRG12
:
401 case V4L2_PIX_FMT_SBGGR12
:
402 tpg
->twopixelsize
[0] = 4;
403 tpg
->twopixelsize
[1] = 4;
405 case V4L2_PIX_FMT_YUV444M
:
406 case V4L2_PIX_FMT_YVU444M
:
407 case V4L2_PIX_FMT_YUV422M
:
408 case V4L2_PIX_FMT_YVU422M
:
409 case V4L2_PIX_FMT_YUV422P
:
410 case V4L2_PIX_FMT_YUV420
:
411 case V4L2_PIX_FMT_YVU420
:
412 case V4L2_PIX_FMT_YUV420M
:
413 case V4L2_PIX_FMT_YVU420M
:
414 tpg
->twopixelsize
[0] = 2;
415 tpg
->twopixelsize
[1] = 2;
416 tpg
->twopixelsize
[2] = 2;
418 case V4L2_PIX_FMT_NV24
:
419 case V4L2_PIX_FMT_NV42
:
420 tpg
->twopixelsize
[0] = 2;
421 tpg
->twopixelsize
[1] = 4;
426 EXPORT_SYMBOL_GPL(tpg_s_fourcc
);
428 void tpg_s_crop_compose(struct tpg_data
*tpg
, const struct v4l2_rect
*crop
,
429 const struct v4l2_rect
*compose
)
432 tpg
->compose
= *compose
;
433 tpg
->scaled_width
= (tpg
->src_width
* tpg
->compose
.width
+
434 tpg
->crop
.width
- 1) / tpg
->crop
.width
;
435 tpg
->scaled_width
&= ~1;
436 if (tpg
->scaled_width
> tpg
->max_line_width
)
437 tpg
->scaled_width
= tpg
->max_line_width
;
438 if (tpg
->scaled_width
< 2)
439 tpg
->scaled_width
= 2;
440 tpg
->recalc_lines
= true;
442 EXPORT_SYMBOL_GPL(tpg_s_crop_compose
);
444 void tpg_reset_source(struct tpg_data
*tpg
, unsigned width
, unsigned height
,
449 tpg
->src_width
= width
;
450 tpg
->src_height
= height
;
452 tpg
->buf_height
= height
;
453 if (V4L2_FIELD_HAS_T_OR_B(field
))
454 tpg
->buf_height
/= 2;
455 tpg
->scaled_width
= width
;
456 tpg
->crop
.top
= tpg
->crop
.left
= 0;
457 tpg
->crop
.width
= width
;
458 tpg
->crop
.height
= height
;
459 tpg
->compose
.top
= tpg
->compose
.left
= 0;
460 tpg
->compose
.width
= width
;
461 tpg
->compose
.height
= tpg
->buf_height
;
462 for (p
= 0; p
< tpg
->planes
; p
++)
463 tpg
->bytesperline
[p
] = (width
* tpg
->twopixelsize
[p
]) /
464 (2 * tpg
->hdownsampling
[p
]);
465 tpg
->recalc_square_border
= true;
467 EXPORT_SYMBOL_GPL(tpg_reset_source
);
469 static enum tpg_color
tpg_get_textbg_color(struct tpg_data
*tpg
)
471 switch (tpg
->pattern
) {
473 return TPG_COLOR_100_WHITE
;
474 case TPG_PAT_CSC_COLORBAR
:
475 return TPG_COLOR_CSC_BLACK
;
477 return TPG_COLOR_100_BLACK
;
481 static enum tpg_color
tpg_get_textfg_color(struct tpg_data
*tpg
)
483 switch (tpg
->pattern
) {
484 case TPG_PAT_75_COLORBAR
:
485 case TPG_PAT_CSC_COLORBAR
:
486 return TPG_COLOR_CSC_WHITE
;
488 return TPG_COLOR_100_BLACK
;
490 return TPG_COLOR_100_WHITE
;
494 static inline int rec709_to_linear(int v
)
496 v
= clamp(v
, 0, 0xff0);
497 return tpg_rec709_to_linear
[v
];
500 static inline int linear_to_rec709(int v
)
502 v
= clamp(v
, 0, 0xff0);
503 return tpg_linear_to_rec709
[v
];
506 static void color_to_hsv(struct tpg_data
*tpg
, int r
, int g
, int b
,
507 int *h
, int *s
, int *v
)
509 int max_rgb
, min_rgb
, diff_rgb
;
519 max_rgb
= max3(r
, g
, b
);
528 min_rgb
= min3(r
, g
, b
);
529 diff_rgb
= max_rgb
- min_rgb
;
530 aux
= 255 * diff_rgb
;
539 third_size
= (tpg
->real_hsv_enc
== V4L2_HSV_ENC_180
) ? 60 : 85;
545 } else if (max_rgb
== g
) {
550 third
= third_size
* 2;
553 aux
*= third_size
/ 2;
559 if (tpg
->real_hsv_enc
== V4L2_HSV_ENC_180
) {
571 static void rgb2ycbcr(const int m
[3][3], int r
, int g
, int b
,
572 int y_offset
, int *y
, int *cb
, int *cr
)
574 *y
= ((m
[0][0] * r
+ m
[0][1] * g
+ m
[0][2] * b
) >> 16) + (y_offset
<< 4);
575 *cb
= ((m
[1][0] * r
+ m
[1][1] * g
+ m
[1][2] * b
) >> 16) + (128 << 4);
576 *cr
= ((m
[2][0] * r
+ m
[2][1] * g
+ m
[2][2] * b
) >> 16) + (128 << 4);
579 static void color_to_ycbcr(struct tpg_data
*tpg
, int r
, int g
, int b
,
580 int *y
, int *cb
, int *cr
)
582 #define COEFF(v, r) ((int)(0.5 + (v) * (r) * 256.0))
584 static const int bt601
[3][3] = {
585 { COEFF(0.299, 219), COEFF(0.587, 219), COEFF(0.114, 219) },
586 { COEFF(-0.1687, 224), COEFF(-0.3313, 224), COEFF(0.5, 224) },
587 { COEFF(0.5, 224), COEFF(-0.4187, 224), COEFF(-0.0813, 224) },
589 static const int bt601_full
[3][3] = {
590 { COEFF(0.299, 255), COEFF(0.587, 255), COEFF(0.114, 255) },
591 { COEFF(-0.1687, 255), COEFF(-0.3313, 255), COEFF(0.5, 255) },
592 { COEFF(0.5, 255), COEFF(-0.4187, 255), COEFF(-0.0813, 255) },
594 static const int rec709
[3][3] = {
595 { COEFF(0.2126, 219), COEFF(0.7152, 219), COEFF(0.0722, 219) },
596 { COEFF(-0.1146, 224), COEFF(-0.3854, 224), COEFF(0.5, 224) },
597 { COEFF(0.5, 224), COEFF(-0.4542, 224), COEFF(-0.0458, 224) },
599 static const int rec709_full
[3][3] = {
600 { COEFF(0.2126, 255), COEFF(0.7152, 255), COEFF(0.0722, 255) },
601 { COEFF(-0.1146, 255), COEFF(-0.3854, 255), COEFF(0.5, 255) },
602 { COEFF(0.5, 255), COEFF(-0.4542, 255), COEFF(-0.0458, 255) },
604 static const int smpte240m
[3][3] = {
605 { COEFF(0.212, 219), COEFF(0.701, 219), COEFF(0.087, 219) },
606 { COEFF(-0.116, 224), COEFF(-0.384, 224), COEFF(0.5, 224) },
607 { COEFF(0.5, 224), COEFF(-0.445, 224), COEFF(-0.055, 224) },
609 static const int smpte240m_full
[3][3] = {
610 { COEFF(0.212, 255), COEFF(0.701, 255), COEFF(0.087, 255) },
611 { COEFF(-0.116, 255), COEFF(-0.384, 255), COEFF(0.5, 255) },
612 { COEFF(0.5, 255), COEFF(-0.445, 255), COEFF(-0.055, 255) },
614 static const int bt2020
[3][3] = {
615 { COEFF(0.2627, 219), COEFF(0.6780, 219), COEFF(0.0593, 219) },
616 { COEFF(-0.1396, 224), COEFF(-0.3604, 224), COEFF(0.5, 224) },
617 { COEFF(0.5, 224), COEFF(-0.4598, 224), COEFF(-0.0402, 224) },
619 static const int bt2020_full
[3][3] = {
620 { COEFF(0.2627, 255), COEFF(0.6780, 255), COEFF(0.0593, 255) },
621 { COEFF(-0.1396, 255), COEFF(-0.3604, 255), COEFF(0.5, 255) },
622 { COEFF(0.5, 255), COEFF(-0.4598, 255), COEFF(-0.0402, 255) },
624 static const int bt2020c
[4] = {
625 COEFF(1.0 / 1.9404, 224), COEFF(1.0 / 1.5816, 224),
626 COEFF(1.0 / 1.7184, 224), COEFF(1.0 / 0.9936, 224),
628 static const int bt2020c_full
[4] = {
629 COEFF(1.0 / 1.9404, 255), COEFF(1.0 / 1.5816, 255),
630 COEFF(1.0 / 1.7184, 255), COEFF(1.0 / 0.9936, 255),
633 bool full
= tpg
->real_quantization
== V4L2_QUANTIZATION_FULL_RANGE
;
634 unsigned y_offset
= full
? 0 : 16;
637 switch (tpg
->real_ycbcr_enc
) {
638 case V4L2_YCBCR_ENC_601
:
639 rgb2ycbcr(full
? bt601_full
: bt601
, r
, g
, b
, y_offset
, y
, cb
, cr
);
641 case V4L2_YCBCR_ENC_XV601
:
642 /* Ignore quantization range, there is only one possible
643 * Y'CbCr encoding. */
644 rgb2ycbcr(bt601
, r
, g
, b
, 16, y
, cb
, cr
);
646 case V4L2_YCBCR_ENC_XV709
:
647 /* Ignore quantization range, there is only one possible
648 * Y'CbCr encoding. */
649 rgb2ycbcr(rec709
, r
, g
, b
, 16, y
, cb
, cr
);
651 case V4L2_YCBCR_ENC_BT2020
:
652 rgb2ycbcr(full
? bt2020_full
: bt2020
, r
, g
, b
, y_offset
, y
, cb
, cr
);
654 case V4L2_YCBCR_ENC_BT2020_CONST_LUM
:
655 lin_y
= (COEFF(0.2627, 255) * rec709_to_linear(r
) +
656 COEFF(0.6780, 255) * rec709_to_linear(g
) +
657 COEFF(0.0593, 255) * rec709_to_linear(b
)) >> 16;
658 yc
= linear_to_rec709(lin_y
);
659 *y
= full
? yc
: (yc
* 219) / 255 + (16 << 4);
661 *cb
= (((b
- yc
) * (full
? bt2020c_full
[0] : bt2020c
[0])) >> 16) + (128 << 4);
663 *cb
= (((b
- yc
) * (full
? bt2020c_full
[1] : bt2020c
[1])) >> 16) + (128 << 4);
665 *cr
= (((r
- yc
) * (full
? bt2020c_full
[2] : bt2020c
[2])) >> 16) + (128 << 4);
667 *cr
= (((r
- yc
) * (full
? bt2020c_full
[3] : bt2020c
[3])) >> 16) + (128 << 4);
669 case V4L2_YCBCR_ENC_SMPTE240M
:
670 rgb2ycbcr(full
? smpte240m_full
: smpte240m
, r
, g
, b
, y_offset
, y
, cb
, cr
);
672 case V4L2_YCBCR_ENC_709
:
674 rgb2ycbcr(full
? rec709_full
: rec709
, r
, g
, b
, y_offset
, y
, cb
, cr
);
679 static void ycbcr2rgb(const int m
[3][3], int y
, int cb
, int cr
,
680 int y_offset
, int *r
, int *g
, int *b
)
685 *r
= m
[0][0] * y
+ m
[0][1] * cb
+ m
[0][2] * cr
;
686 *g
= m
[1][0] * y
+ m
[1][1] * cb
+ m
[1][2] * cr
;
687 *b
= m
[2][0] * y
+ m
[2][1] * cb
+ m
[2][2] * cr
;
688 *r
= clamp(*r
>> 12, 0, 0xff0);
689 *g
= clamp(*g
>> 12, 0, 0xff0);
690 *b
= clamp(*b
>> 12, 0, 0xff0);
693 static void ycbcr_to_color(struct tpg_data
*tpg
, int y
, int cb
, int cr
,
694 int *r
, int *g
, int *b
)
697 #define COEFF(v, r) ((int)(0.5 + (v) * ((255.0 * 255.0 * 16.0) / (r))))
698 static const int bt601
[3][3] = {
699 { COEFF(1, 219), COEFF(0, 224), COEFF(1.4020, 224) },
700 { COEFF(1, 219), COEFF(-0.3441, 224), COEFF(-0.7141, 224) },
701 { COEFF(1, 219), COEFF(1.7720, 224), COEFF(0, 224) },
703 static const int bt601_full
[3][3] = {
704 { COEFF(1, 255), COEFF(0, 255), COEFF(1.4020, 255) },
705 { COEFF(1, 255), COEFF(-0.3441, 255), COEFF(-0.7141, 255) },
706 { COEFF(1, 255), COEFF(1.7720, 255), COEFF(0, 255) },
708 static const int rec709
[3][3] = {
709 { COEFF(1, 219), COEFF(0, 224), COEFF(1.5748, 224) },
710 { COEFF(1, 219), COEFF(-0.1873, 224), COEFF(-0.4681, 224) },
711 { COEFF(1, 219), COEFF(1.8556, 224), COEFF(0, 224) },
713 static const int rec709_full
[3][3] = {
714 { COEFF(1, 255), COEFF(0, 255), COEFF(1.5748, 255) },
715 { COEFF(1, 255), COEFF(-0.1873, 255), COEFF(-0.4681, 255) },
716 { COEFF(1, 255), COEFF(1.8556, 255), COEFF(0, 255) },
718 static const int smpte240m
[3][3] = {
719 { COEFF(1, 219), COEFF(0, 224), COEFF(1.5756, 224) },
720 { COEFF(1, 219), COEFF(-0.2253, 224), COEFF(-0.4767, 224) },
721 { COEFF(1, 219), COEFF(1.8270, 224), COEFF(0, 224) },
723 static const int smpte240m_full
[3][3] = {
724 { COEFF(1, 255), COEFF(0, 255), COEFF(1.5756, 255) },
725 { COEFF(1, 255), COEFF(-0.2253, 255), COEFF(-0.4767, 255) },
726 { COEFF(1, 255), COEFF(1.8270, 255), COEFF(0, 255) },
728 static const int bt2020
[3][3] = {
729 { COEFF(1, 219), COEFF(0, 224), COEFF(1.4746, 224) },
730 { COEFF(1, 219), COEFF(-0.1646, 224), COEFF(-0.5714, 224) },
731 { COEFF(1, 219), COEFF(1.8814, 224), COEFF(0, 224) },
733 static const int bt2020_full
[3][3] = {
734 { COEFF(1, 255), COEFF(0, 255), COEFF(1.4746, 255) },
735 { COEFF(1, 255), COEFF(-0.1646, 255), COEFF(-0.5714, 255) },
736 { COEFF(1, 255), COEFF(1.8814, 255), COEFF(0, 255) },
738 static const int bt2020c
[4] = {
739 COEFF(1.9404, 224), COEFF(1.5816, 224),
740 COEFF(1.7184, 224), COEFF(0.9936, 224),
742 static const int bt2020c_full
[4] = {
743 COEFF(1.9404, 255), COEFF(1.5816, 255),
744 COEFF(1.7184, 255), COEFF(0.9936, 255),
747 bool full
= tpg
->real_quantization
== V4L2_QUANTIZATION_FULL_RANGE
;
748 unsigned y_offset
= full
? 0 : 16;
749 int y_fac
= full
? COEFF(1.0, 255) : COEFF(1.0, 219);
750 int lin_r
, lin_g
, lin_b
, lin_y
;
752 switch (tpg
->real_ycbcr_enc
) {
753 case V4L2_YCBCR_ENC_601
:
754 ycbcr2rgb(full
? bt601_full
: bt601
, y
, cb
, cr
, y_offset
, r
, g
, b
);
756 case V4L2_YCBCR_ENC_XV601
:
757 /* Ignore quantization range, there is only one possible
758 * Y'CbCr encoding. */
759 ycbcr2rgb(bt601
, y
, cb
, cr
, 16, r
, g
, b
);
761 case V4L2_YCBCR_ENC_XV709
:
762 /* Ignore quantization range, there is only one possible
763 * Y'CbCr encoding. */
764 ycbcr2rgb(rec709
, y
, cb
, cr
, 16, r
, g
, b
);
766 case V4L2_YCBCR_ENC_BT2020
:
767 ycbcr2rgb(full
? bt2020_full
: bt2020
, y
, cb
, cr
, y_offset
, r
, g
, b
);
769 case V4L2_YCBCR_ENC_BT2020_CONST_LUM
:
770 y
-= full
? 0 : 16 << 4;
775 *b
= y_fac
* y
+ (full
? bt2020c_full
[0] : bt2020c
[0]) * cb
;
777 *b
= y_fac
* y
+ (full
? bt2020c_full
[1] : bt2020c
[1]) * cb
;
780 *r
= y_fac
* y
+ (full
? bt2020c_full
[2] : bt2020c
[2]) * cr
;
782 *r
= y_fac
* y
+ (full
? bt2020c_full
[3] : bt2020c
[3]) * cr
;
784 lin_r
= rec709_to_linear(*r
);
785 lin_b
= rec709_to_linear(*b
);
786 lin_y
= rec709_to_linear((y
* 255) / (full
? 255 : 219));
788 lin_g
= COEFF(1.0 / 0.6780, 255) * lin_y
-
789 COEFF(0.2627 / 0.6780, 255) * lin_r
-
790 COEFF(0.0593 / 0.6780, 255) * lin_b
;
791 *g
= linear_to_rec709(lin_g
>> 12);
793 case V4L2_YCBCR_ENC_SMPTE240M
:
794 ycbcr2rgb(full
? smpte240m_full
: smpte240m
, y
, cb
, cr
, y_offset
, r
, g
, b
);
796 case V4L2_YCBCR_ENC_709
:
798 ycbcr2rgb(full
? rec709_full
: rec709
, y
, cb
, cr
, y_offset
, r
, g
, b
);
803 /* precalculate color bar values to speed up rendering */
804 static void precalculate_color(struct tpg_data
*tpg
, int k
)
807 int r
= tpg_colors
[col
].r
;
808 int g
= tpg_colors
[col
].g
;
809 int b
= tpg_colors
[col
].b
;
811 bool ycbcr_valid
= false;
813 if (k
== TPG_COLOR_TEXTBG
) {
814 col
= tpg_get_textbg_color(tpg
);
816 r
= tpg_colors
[col
].r
;
817 g
= tpg_colors
[col
].g
;
818 b
= tpg_colors
[col
].b
;
819 } else if (k
== TPG_COLOR_TEXTFG
) {
820 col
= tpg_get_textfg_color(tpg
);
822 r
= tpg_colors
[col
].r
;
823 g
= tpg_colors
[col
].g
;
824 b
= tpg_colors
[col
].b
;
825 } else if (tpg
->pattern
== TPG_PAT_NOISE
) {
826 r
= g
= b
= prandom_u32_max(256);
827 } else if (k
== TPG_COLOR_RANDOM
) {
828 r
= g
= b
= tpg
->qual_offset
+ prandom_u32_max(196);
829 } else if (k
>= TPG_COLOR_RAMP
) {
830 r
= g
= b
= k
- TPG_COLOR_RAMP
;
833 if (tpg
->pattern
== TPG_PAT_CSC_COLORBAR
&& col
<= TPG_COLOR_CSC_BLACK
) {
834 r
= tpg_csc_colors
[tpg
->colorspace
][tpg
->real_xfer_func
][col
].r
;
835 g
= tpg_csc_colors
[tpg
->colorspace
][tpg
->real_xfer_func
][col
].g
;
836 b
= tpg_csc_colors
[tpg
->colorspace
][tpg
->real_xfer_func
][col
].b
;
843 if (tpg
->qual
== TPG_QUAL_GRAY
||
844 tpg
->color_enc
== TGP_COLOR_ENC_LUMA
) {
845 /* Rec. 709 Luma function */
846 /* (0.2126, 0.7152, 0.0722) * (255 * 256) */
847 r
= g
= b
= (13879 * r
+ 46688 * g
+ 4713 * b
) >> 16;
851 * The assumption is that the RGB output is always full range,
852 * so only if the rgb_range overrides the 'real' rgb range do
853 * we need to convert the RGB values.
855 * Remember that r, g and b are still in the 0 - 0xff0 range.
857 if (tpg
->real_rgb_range
== V4L2_DV_RGB_RANGE_LIMITED
&&
858 tpg
->rgb_range
== V4L2_DV_RGB_RANGE_FULL
&&
859 tpg
->color_enc
== TGP_COLOR_ENC_RGB
) {
861 * Convert from full range (which is what r, g and b are)
862 * to limited range (which is the 'real' RGB range), which
863 * is then interpreted as full range.
865 r
= (r
* 219) / 255 + (16 << 4);
866 g
= (g
* 219) / 255 + (16 << 4);
867 b
= (b
* 219) / 255 + (16 << 4);
868 } else if (tpg
->real_rgb_range
!= V4L2_DV_RGB_RANGE_LIMITED
&&
869 tpg
->rgb_range
== V4L2_DV_RGB_RANGE_LIMITED
&&
870 tpg
->color_enc
== TGP_COLOR_ENC_RGB
) {
873 * Clamp r, g and b to the limited range and convert to full
874 * range since that's what we deliver.
876 r
= clamp(r
, 16 << 4, 235 << 4);
877 g
= clamp(g
, 16 << 4, 235 << 4);
878 b
= clamp(b
, 16 << 4, 235 << 4);
879 r
= (r
- (16 << 4)) * 255 / 219;
880 g
= (g
- (16 << 4)) * 255 / 219;
881 b
= (b
- (16 << 4)) * 255 / 219;
884 if ((tpg
->brightness
!= 128 || tpg
->contrast
!= 128 ||
885 tpg
->saturation
!= 128 || tpg
->hue
) &&
886 tpg
->color_enc
!= TGP_COLOR_ENC_LUMA
) {
887 /* Implement these operations */
890 /* First convert to YCbCr */
892 color_to_ycbcr(tpg
, r
, g
, b
, &y
, &cb
, &cr
);
894 y
= (16 << 4) + ((y
- (16 << 4)) * tpg
->contrast
) / 128;
895 y
+= (tpg
->brightness
<< 4) - (128 << 4);
899 tmp_cb
= (cb
* cos(128 + tpg
->hue
)) / 127 + (cr
* sin
[128 + tpg
->hue
]) / 127;
900 tmp_cr
= (cr
* cos(128 + tpg
->hue
)) / 127 - (cb
* sin
[128 + tpg
->hue
]) / 127;
902 cb
= (128 << 4) + (tmp_cb
* tpg
->contrast
* tpg
->saturation
) / (128 * 128);
903 cr
= (128 << 4) + (tmp_cr
* tpg
->contrast
* tpg
->saturation
) / (128 * 128);
904 if (tpg
->color_enc
== TGP_COLOR_ENC_YCBCR
)
907 ycbcr_to_color(tpg
, y
, cb
, cr
, &r
, &g
, &b
);
908 } else if ((tpg
->brightness
!= 128 || tpg
->contrast
!= 128) &&
909 tpg
->color_enc
== TGP_COLOR_ENC_LUMA
) {
910 r
= (16 << 4) + ((r
- (16 << 4)) * tpg
->contrast
) / 128;
911 r
+= (tpg
->brightness
<< 4) - (128 << 4);
914 switch (tpg
->color_enc
) {
915 case TGP_COLOR_ENC_HSV
:
919 color_to_hsv(tpg
, r
, g
, b
, &h
, &s
, &v
);
920 tpg
->colors
[k
][0] = h
;
921 tpg
->colors
[k
][1] = s
;
922 tpg
->colors
[k
][2] = v
;
925 case TGP_COLOR_ENC_YCBCR
:
927 /* Convert to YCbCr */
929 color_to_ycbcr(tpg
, r
, g
, b
, &y
, &cb
, &cr
);
935 * XV601/709 use the header/footer margins to encode R', G'
936 * and B' values outside the range [0-1]. So do not clamp
939 if (tpg
->real_quantization
== V4L2_QUANTIZATION_LIM_RANGE
&&
940 tpg
->real_ycbcr_enc
!= V4L2_YCBCR_ENC_XV601
&&
941 tpg
->real_ycbcr_enc
!= V4L2_YCBCR_ENC_XV709
) {
942 y
= clamp(y
, 16, 235);
943 cb
= clamp(cb
, 16, 240);
944 cr
= clamp(cr
, 16, 240);
946 y
= clamp(y
, 1, 254);
947 cb
= clamp(cb
, 1, 254);
948 cr
= clamp(cr
, 1, 254);
950 switch (tpg
->fourcc
) {
951 case V4L2_PIX_FMT_YUV444
:
956 case V4L2_PIX_FMT_YUV555
:
961 case V4L2_PIX_FMT_YUV565
:
967 tpg
->colors
[k
][0] = y
;
968 tpg
->colors
[k
][1] = cb
;
969 tpg
->colors
[k
][2] = cr
;
972 case TGP_COLOR_ENC_LUMA
:
974 tpg
->colors
[k
][0] = r
>> 4;
977 case TGP_COLOR_ENC_RGB
:
979 if (tpg
->real_quantization
== V4L2_QUANTIZATION_LIM_RANGE
) {
980 r
= (r
* 219) / 255 + (16 << 4);
981 g
= (g
* 219) / 255 + (16 << 4);
982 b
= (b
* 219) / 255 + (16 << 4);
984 switch (tpg
->fourcc
) {
985 case V4L2_PIX_FMT_RGB332
:
990 case V4L2_PIX_FMT_RGB565
:
991 case V4L2_PIX_FMT_RGB565X
:
996 case V4L2_PIX_FMT_RGB444
:
997 case V4L2_PIX_FMT_XRGB444
:
998 case V4L2_PIX_FMT_ARGB444
:
1003 case V4L2_PIX_FMT_RGB555
:
1004 case V4L2_PIX_FMT_XRGB555
:
1005 case V4L2_PIX_FMT_ARGB555
:
1006 case V4L2_PIX_FMT_RGB555X
:
1007 case V4L2_PIX_FMT_XRGB555X
:
1008 case V4L2_PIX_FMT_ARGB555X
:
1013 case V4L2_PIX_FMT_BGR666
:
1025 tpg
->colors
[k
][0] = r
;
1026 tpg
->colors
[k
][1] = g
;
1027 tpg
->colors
[k
][2] = b
;
1033 static void tpg_precalculate_colors(struct tpg_data
*tpg
)
1037 for (k
= 0; k
< TPG_COLOR_MAX
; k
++)
1038 precalculate_color(tpg
, k
);
1041 /* 'odd' is true for pixels 1, 3, 5, etc. and false for pixels 0, 2, 4, etc. */
1042 static void gen_twopix(struct tpg_data
*tpg
,
1043 u8 buf
[TPG_MAX_PLANES
][8], int color
, bool odd
)
1045 unsigned offset
= odd
* tpg
->twopixelsize
[0] / 2;
1046 u8 alpha
= tpg
->alpha_component
;
1047 u8 r_y_h
, g_u_s
, b_v
;
1049 if (tpg
->alpha_red_only
&& color
!= TPG_COLOR_CSC_RED
&&
1050 color
!= TPG_COLOR_100_RED
&&
1051 color
!= TPG_COLOR_75_RED
)
1053 if (color
== TPG_COLOR_RANDOM
)
1054 precalculate_color(tpg
, color
);
1055 r_y_h
= tpg
->colors
[color
][0]; /* R or precalculated Y, H */
1056 g_u_s
= tpg
->colors
[color
][1]; /* G or precalculated U, V */
1057 b_v
= tpg
->colors
[color
][2]; /* B or precalculated V */
1059 switch (tpg
->fourcc
) {
1060 case V4L2_PIX_FMT_GREY
:
1061 buf
[0][offset
] = r_y_h
;
1063 case V4L2_PIX_FMT_Y10
:
1064 buf
[0][offset
] = (r_y_h
<< 2) & 0xff;
1065 buf
[0][offset
+1] = r_y_h
>> 6;
1067 case V4L2_PIX_FMT_Y12
:
1068 buf
[0][offset
] = (r_y_h
<< 4) & 0xff;
1069 buf
[0][offset
+1] = r_y_h
>> 4;
1071 case V4L2_PIX_FMT_Y16
:
1073 * Ideally both bytes should be set to r_y_h, but then you won't
1074 * be able to detect endian problems. So keep it 0 except for
1075 * the corner case where r_y_h is 0xff so white really will be
1078 buf
[0][offset
] = r_y_h
== 0xff ? r_y_h
: 0;
1079 buf
[0][offset
+1] = r_y_h
;
1081 case V4L2_PIX_FMT_Y16_BE
:
1082 /* See comment for V4L2_PIX_FMT_Y16 above */
1083 buf
[0][offset
] = r_y_h
;
1084 buf
[0][offset
+1] = r_y_h
== 0xff ? r_y_h
: 0;
1086 case V4L2_PIX_FMT_YUV422M
:
1087 case V4L2_PIX_FMT_YUV422P
:
1088 case V4L2_PIX_FMT_YUV420
:
1089 case V4L2_PIX_FMT_YUV420M
:
1090 buf
[0][offset
] = r_y_h
;
1092 buf
[1][0] = (buf
[1][0] + g_u_s
) / 2;
1093 buf
[2][0] = (buf
[2][0] + b_v
) / 2;
1094 buf
[1][1] = buf
[1][0];
1095 buf
[2][1] = buf
[2][0];
1101 case V4L2_PIX_FMT_YVU422M
:
1102 case V4L2_PIX_FMT_YVU420
:
1103 case V4L2_PIX_FMT_YVU420M
:
1104 buf
[0][offset
] = r_y_h
;
1106 buf
[1][0] = (buf
[1][0] + b_v
) / 2;
1107 buf
[2][0] = (buf
[2][0] + g_u_s
) / 2;
1108 buf
[1][1] = buf
[1][0];
1109 buf
[2][1] = buf
[2][0];
1116 case V4L2_PIX_FMT_NV12
:
1117 case V4L2_PIX_FMT_NV12M
:
1118 case V4L2_PIX_FMT_NV16
:
1119 case V4L2_PIX_FMT_NV16M
:
1120 buf
[0][offset
] = r_y_h
;
1122 buf
[1][0] = (buf
[1][0] + g_u_s
) / 2;
1123 buf
[1][1] = (buf
[1][1] + b_v
) / 2;
1129 case V4L2_PIX_FMT_NV21
:
1130 case V4L2_PIX_FMT_NV21M
:
1131 case V4L2_PIX_FMT_NV61
:
1132 case V4L2_PIX_FMT_NV61M
:
1133 buf
[0][offset
] = r_y_h
;
1135 buf
[1][0] = (buf
[1][0] + b_v
) / 2;
1136 buf
[1][1] = (buf
[1][1] + g_u_s
) / 2;
1143 case V4L2_PIX_FMT_YUV444M
:
1144 buf
[0][offset
] = r_y_h
;
1145 buf
[1][offset
] = g_u_s
;
1146 buf
[2][offset
] = b_v
;
1149 case V4L2_PIX_FMT_YVU444M
:
1150 buf
[0][offset
] = r_y_h
;
1151 buf
[1][offset
] = b_v
;
1152 buf
[2][offset
] = g_u_s
;
1155 case V4L2_PIX_FMT_NV24
:
1156 buf
[0][offset
] = r_y_h
;
1157 buf
[1][2 * offset
] = g_u_s
;
1158 buf
[1][2 * offset
+ 1] = b_v
;
1161 case V4L2_PIX_FMT_NV42
:
1162 buf
[0][offset
] = r_y_h
;
1163 buf
[1][2 * offset
] = b_v
;
1164 buf
[1][2 * offset
+ 1] = g_u_s
;
1167 case V4L2_PIX_FMT_YUYV
:
1168 buf
[0][offset
] = r_y_h
;
1170 buf
[0][1] = (buf
[0][1] + g_u_s
) / 2;
1171 buf
[0][3] = (buf
[0][3] + b_v
) / 2;
1177 case V4L2_PIX_FMT_UYVY
:
1178 buf
[0][offset
+ 1] = r_y_h
;
1180 buf
[0][0] = (buf
[0][0] + g_u_s
) / 2;
1181 buf
[0][2] = (buf
[0][2] + b_v
) / 2;
1187 case V4L2_PIX_FMT_YVYU
:
1188 buf
[0][offset
] = r_y_h
;
1190 buf
[0][1] = (buf
[0][1] + b_v
) / 2;
1191 buf
[0][3] = (buf
[0][3] + g_u_s
) / 2;
1197 case V4L2_PIX_FMT_VYUY
:
1198 buf
[0][offset
+ 1] = r_y_h
;
1200 buf
[0][0] = (buf
[0][0] + b_v
) / 2;
1201 buf
[0][2] = (buf
[0][2] + g_u_s
) / 2;
1207 case V4L2_PIX_FMT_RGB332
:
1208 buf
[0][offset
] = (r_y_h
<< 5) | (g_u_s
<< 2) | b_v
;
1210 case V4L2_PIX_FMT_YUV565
:
1211 case V4L2_PIX_FMT_RGB565
:
1212 buf
[0][offset
] = (g_u_s
<< 5) | b_v
;
1213 buf
[0][offset
+ 1] = (r_y_h
<< 3) | (g_u_s
>> 3);
1215 case V4L2_PIX_FMT_RGB565X
:
1216 buf
[0][offset
] = (r_y_h
<< 3) | (g_u_s
>> 3);
1217 buf
[0][offset
+ 1] = (g_u_s
<< 5) | b_v
;
1219 case V4L2_PIX_FMT_RGB444
:
1220 case V4L2_PIX_FMT_XRGB444
:
1223 case V4L2_PIX_FMT_YUV444
:
1224 case V4L2_PIX_FMT_ARGB444
:
1225 buf
[0][offset
] = (g_u_s
<< 4) | b_v
;
1226 buf
[0][offset
+ 1] = (alpha
& 0xf0) | r_y_h
;
1228 case V4L2_PIX_FMT_RGB555
:
1229 case V4L2_PIX_FMT_XRGB555
:
1232 case V4L2_PIX_FMT_YUV555
:
1233 case V4L2_PIX_FMT_ARGB555
:
1234 buf
[0][offset
] = (g_u_s
<< 5) | b_v
;
1235 buf
[0][offset
+ 1] = (alpha
& 0x80) | (r_y_h
<< 2)
1238 case V4L2_PIX_FMT_RGB555X
:
1239 case V4L2_PIX_FMT_XRGB555X
:
1242 case V4L2_PIX_FMT_ARGB555X
:
1243 buf
[0][offset
] = (alpha
& 0x80) | (r_y_h
<< 2) | (g_u_s
>> 3);
1244 buf
[0][offset
+ 1] = (g_u_s
<< 5) | b_v
;
1246 case V4L2_PIX_FMT_RGB24
:
1247 case V4L2_PIX_FMT_HSV24
:
1248 buf
[0][offset
] = r_y_h
;
1249 buf
[0][offset
+ 1] = g_u_s
;
1250 buf
[0][offset
+ 2] = b_v
;
1252 case V4L2_PIX_FMT_BGR24
:
1253 buf
[0][offset
] = b_v
;
1254 buf
[0][offset
+ 1] = g_u_s
;
1255 buf
[0][offset
+ 2] = r_y_h
;
1257 case V4L2_PIX_FMT_BGR666
:
1258 buf
[0][offset
] = (b_v
<< 2) | (g_u_s
>> 4);
1259 buf
[0][offset
+ 1] = (g_u_s
<< 4) | (r_y_h
>> 2);
1260 buf
[0][offset
+ 2] = r_y_h
<< 6;
1261 buf
[0][offset
+ 3] = 0;
1263 case V4L2_PIX_FMT_RGB32
:
1264 case V4L2_PIX_FMT_XRGB32
:
1265 case V4L2_PIX_FMT_HSV32
:
1268 case V4L2_PIX_FMT_YUV32
:
1269 case V4L2_PIX_FMT_ARGB32
:
1270 buf
[0][offset
] = alpha
;
1271 buf
[0][offset
+ 1] = r_y_h
;
1272 buf
[0][offset
+ 2] = g_u_s
;
1273 buf
[0][offset
+ 3] = b_v
;
1275 case V4L2_PIX_FMT_BGR32
:
1276 case V4L2_PIX_FMT_XBGR32
:
1279 case V4L2_PIX_FMT_ABGR32
:
1280 buf
[0][offset
] = b_v
;
1281 buf
[0][offset
+ 1] = g_u_s
;
1282 buf
[0][offset
+ 2] = r_y_h
;
1283 buf
[0][offset
+ 3] = alpha
;
1285 case V4L2_PIX_FMT_SBGGR8
:
1286 buf
[0][offset
] = odd
? g_u_s
: b_v
;
1287 buf
[1][offset
] = odd
? r_y_h
: g_u_s
;
1289 case V4L2_PIX_FMT_SGBRG8
:
1290 buf
[0][offset
] = odd
? b_v
: g_u_s
;
1291 buf
[1][offset
] = odd
? g_u_s
: r_y_h
;
1293 case V4L2_PIX_FMT_SGRBG8
:
1294 buf
[0][offset
] = odd
? r_y_h
: g_u_s
;
1295 buf
[1][offset
] = odd
? g_u_s
: b_v
;
1297 case V4L2_PIX_FMT_SRGGB8
:
1298 buf
[0][offset
] = odd
? g_u_s
: r_y_h
;
1299 buf
[1][offset
] = odd
? b_v
: g_u_s
;
1301 case V4L2_PIX_FMT_SBGGR10
:
1302 buf
[0][offset
] = odd
? g_u_s
<< 2 : b_v
<< 2;
1303 buf
[0][offset
+ 1] = odd
? g_u_s
>> 6 : b_v
>> 6;
1304 buf
[1][offset
] = odd
? r_y_h
<< 2 : g_u_s
<< 2;
1305 buf
[1][offset
+ 1] = odd
? r_y_h
>> 6 : g_u_s
>> 6;
1306 buf
[0][offset
] |= (buf
[0][offset
] >> 2) & 3;
1307 buf
[1][offset
] |= (buf
[1][offset
] >> 2) & 3;
1309 case V4L2_PIX_FMT_SGBRG10
:
1310 buf
[0][offset
] = odd
? b_v
<< 2 : g_u_s
<< 2;
1311 buf
[0][offset
+ 1] = odd
? b_v
>> 6 : g_u_s
>> 6;
1312 buf
[1][offset
] = odd
? g_u_s
<< 2 : r_y_h
<< 2;
1313 buf
[1][offset
+ 1] = odd
? g_u_s
>> 6 : r_y_h
>> 6;
1314 buf
[0][offset
] |= (buf
[0][offset
] >> 2) & 3;
1315 buf
[1][offset
] |= (buf
[1][offset
] >> 2) & 3;
1317 case V4L2_PIX_FMT_SGRBG10
:
1318 buf
[0][offset
] = odd
? r_y_h
<< 2 : g_u_s
<< 2;
1319 buf
[0][offset
+ 1] = odd
? r_y_h
>> 6 : g_u_s
>> 6;
1320 buf
[1][offset
] = odd
? g_u_s
<< 2 : b_v
<< 2;
1321 buf
[1][offset
+ 1] = odd
? g_u_s
>> 6 : b_v
>> 6;
1322 buf
[0][offset
] |= (buf
[0][offset
] >> 2) & 3;
1323 buf
[1][offset
] |= (buf
[1][offset
] >> 2) & 3;
1325 case V4L2_PIX_FMT_SRGGB10
:
1326 buf
[0][offset
] = odd
? g_u_s
<< 2 : r_y_h
<< 2;
1327 buf
[0][offset
+ 1] = odd
? g_u_s
>> 6 : r_y_h
>> 6;
1328 buf
[1][offset
] = odd
? b_v
<< 2 : g_u_s
<< 2;
1329 buf
[1][offset
+ 1] = odd
? b_v
>> 6 : g_u_s
>> 6;
1330 buf
[0][offset
] |= (buf
[0][offset
] >> 2) & 3;
1331 buf
[1][offset
] |= (buf
[1][offset
] >> 2) & 3;
1333 case V4L2_PIX_FMT_SBGGR12
:
1334 buf
[0][offset
] = odd
? g_u_s
<< 4 : b_v
<< 4;
1335 buf
[0][offset
+ 1] = odd
? g_u_s
>> 4 : b_v
>> 4;
1336 buf
[1][offset
] = odd
? r_y_h
<< 4 : g_u_s
<< 4;
1337 buf
[1][offset
+ 1] = odd
? r_y_h
>> 4 : g_u_s
>> 4;
1338 buf
[0][offset
] |= (buf
[0][offset
] >> 4) & 0xf;
1339 buf
[1][offset
] |= (buf
[1][offset
] >> 4) & 0xf;
1341 case V4L2_PIX_FMT_SGBRG12
:
1342 buf
[0][offset
] = odd
? b_v
<< 4 : g_u_s
<< 4;
1343 buf
[0][offset
+ 1] = odd
? b_v
>> 4 : g_u_s
>> 4;
1344 buf
[1][offset
] = odd
? g_u_s
<< 4 : r_y_h
<< 4;
1345 buf
[1][offset
+ 1] = odd
? g_u_s
>> 4 : r_y_h
>> 4;
1346 buf
[0][offset
] |= (buf
[0][offset
] >> 4) & 0xf;
1347 buf
[1][offset
] |= (buf
[1][offset
] >> 4) & 0xf;
1349 case V4L2_PIX_FMT_SGRBG12
:
1350 buf
[0][offset
] = odd
? r_y_h
<< 4 : g_u_s
<< 4;
1351 buf
[0][offset
+ 1] = odd
? r_y_h
>> 4 : g_u_s
>> 4;
1352 buf
[1][offset
] = odd
? g_u_s
<< 4 : b_v
<< 4;
1353 buf
[1][offset
+ 1] = odd
? g_u_s
>> 4 : b_v
>> 4;
1354 buf
[0][offset
] |= (buf
[0][offset
] >> 4) & 0xf;
1355 buf
[1][offset
] |= (buf
[1][offset
] >> 4) & 0xf;
1357 case V4L2_PIX_FMT_SRGGB12
:
1358 buf
[0][offset
] = odd
? g_u_s
<< 4 : r_y_h
<< 4;
1359 buf
[0][offset
+ 1] = odd
? g_u_s
>> 4 : r_y_h
>> 4;
1360 buf
[1][offset
] = odd
? b_v
<< 4 : g_u_s
<< 4;
1361 buf
[1][offset
+ 1] = odd
? b_v
>> 4 : g_u_s
>> 4;
1362 buf
[0][offset
] |= (buf
[0][offset
] >> 4) & 0xf;
1363 buf
[1][offset
] |= (buf
[1][offset
] >> 4) & 0xf;
1368 unsigned tpg_g_interleaved_plane(const struct tpg_data
*tpg
, unsigned buf_line
)
1370 switch (tpg
->fourcc
) {
1371 case V4L2_PIX_FMT_SBGGR8
:
1372 case V4L2_PIX_FMT_SGBRG8
:
1373 case V4L2_PIX_FMT_SGRBG8
:
1374 case V4L2_PIX_FMT_SRGGB8
:
1375 case V4L2_PIX_FMT_SBGGR10
:
1376 case V4L2_PIX_FMT_SGBRG10
:
1377 case V4L2_PIX_FMT_SGRBG10
:
1378 case V4L2_PIX_FMT_SRGGB10
:
1379 case V4L2_PIX_FMT_SBGGR12
:
1380 case V4L2_PIX_FMT_SGBRG12
:
1381 case V4L2_PIX_FMT_SGRBG12
:
1382 case V4L2_PIX_FMT_SRGGB12
:
1383 return buf_line
& 1;
1388 EXPORT_SYMBOL_GPL(tpg_g_interleaved_plane
);
1390 /* Return how many pattern lines are used by the current pattern. */
1391 static unsigned tpg_get_pat_lines(const struct tpg_data
*tpg
)
1393 switch (tpg
->pattern
) {
1394 case TPG_PAT_CHECKERS_16X16
:
1395 case TPG_PAT_CHECKERS_2X2
:
1396 case TPG_PAT_CHECKERS_1X1
:
1397 case TPG_PAT_COLOR_CHECKERS_2X2
:
1398 case TPG_PAT_COLOR_CHECKERS_1X1
:
1399 case TPG_PAT_ALTERNATING_HLINES
:
1400 case TPG_PAT_CROSS_1_PIXEL
:
1401 case TPG_PAT_CROSS_2_PIXELS
:
1402 case TPG_PAT_CROSS_10_PIXELS
:
1404 case TPG_PAT_100_COLORSQUARES
:
1405 case TPG_PAT_100_HCOLORBAR
:
1412 /* Which pattern line should be used for the given frame line. */
1413 static unsigned tpg_get_pat_line(const struct tpg_data
*tpg
, unsigned line
)
1415 switch (tpg
->pattern
) {
1416 case TPG_PAT_CHECKERS_16X16
:
1417 return (line
>> 4) & 1;
1418 case TPG_PAT_CHECKERS_1X1
:
1419 case TPG_PAT_COLOR_CHECKERS_1X1
:
1420 case TPG_PAT_ALTERNATING_HLINES
:
1422 case TPG_PAT_CHECKERS_2X2
:
1423 case TPG_PAT_COLOR_CHECKERS_2X2
:
1424 return (line
& 2) >> 1;
1425 case TPG_PAT_100_COLORSQUARES
:
1426 case TPG_PAT_100_HCOLORBAR
:
1427 return (line
* 8) / tpg
->src_height
;
1428 case TPG_PAT_CROSS_1_PIXEL
:
1429 return line
== tpg
->src_height
/ 2;
1430 case TPG_PAT_CROSS_2_PIXELS
:
1431 return (line
+ 1) / 2 == tpg
->src_height
/ 4;
1432 case TPG_PAT_CROSS_10_PIXELS
:
1433 return (line
+ 10) / 20 == tpg
->src_height
/ 40;
1440 * Which color should be used for the given pattern line and X coordinate.
1441 * Note: x is in the range 0 to 2 * tpg->src_width.
1443 static enum tpg_color
tpg_get_color(const struct tpg_data
*tpg
,
1444 unsigned pat_line
, unsigned x
)
1446 /* Maximum number of bars are TPG_COLOR_MAX - otherwise, the input print code
1447 should be modified */
1448 static const enum tpg_color bars
[3][8] = {
1449 /* Standard ITU-R 75% color bar sequence */
1450 { TPG_COLOR_CSC_WHITE
, TPG_COLOR_75_YELLOW
,
1451 TPG_COLOR_75_CYAN
, TPG_COLOR_75_GREEN
,
1452 TPG_COLOR_75_MAGENTA
, TPG_COLOR_75_RED
,
1453 TPG_COLOR_75_BLUE
, TPG_COLOR_100_BLACK
, },
1454 /* Standard ITU-R 100% color bar sequence */
1455 { TPG_COLOR_100_WHITE
, TPG_COLOR_100_YELLOW
,
1456 TPG_COLOR_100_CYAN
, TPG_COLOR_100_GREEN
,
1457 TPG_COLOR_100_MAGENTA
, TPG_COLOR_100_RED
,
1458 TPG_COLOR_100_BLUE
, TPG_COLOR_100_BLACK
, },
1459 /* Color bar sequence suitable to test CSC */
1460 { TPG_COLOR_CSC_WHITE
, TPG_COLOR_CSC_YELLOW
,
1461 TPG_COLOR_CSC_CYAN
, TPG_COLOR_CSC_GREEN
,
1462 TPG_COLOR_CSC_MAGENTA
, TPG_COLOR_CSC_RED
,
1463 TPG_COLOR_CSC_BLUE
, TPG_COLOR_CSC_BLACK
, },
1466 switch (tpg
->pattern
) {
1467 case TPG_PAT_75_COLORBAR
:
1468 case TPG_PAT_100_COLORBAR
:
1469 case TPG_PAT_CSC_COLORBAR
:
1470 return bars
[tpg
->pattern
][((x
* 8) / tpg
->src_width
) % 8];
1471 case TPG_PAT_100_COLORSQUARES
:
1472 return bars
[1][(pat_line
+ (x
* 8) / tpg
->src_width
) % 8];
1473 case TPG_PAT_100_HCOLORBAR
:
1474 return bars
[1][pat_line
];
1476 return TPG_COLOR_100_BLACK
;
1478 return TPG_COLOR_100_WHITE
;
1480 return TPG_COLOR_100_RED
;
1482 return TPG_COLOR_100_GREEN
;
1484 return TPG_COLOR_100_BLUE
;
1485 case TPG_PAT_CHECKERS_16X16
:
1486 return (((x
>> 4) & 1) ^ (pat_line
& 1)) ?
1487 TPG_COLOR_100_BLACK
: TPG_COLOR_100_WHITE
;
1488 case TPG_PAT_CHECKERS_1X1
:
1489 return ((x
& 1) ^ (pat_line
& 1)) ?
1490 TPG_COLOR_100_WHITE
: TPG_COLOR_100_BLACK
;
1491 case TPG_PAT_COLOR_CHECKERS_1X1
:
1492 return ((x
& 1) ^ (pat_line
& 1)) ?
1493 TPG_COLOR_100_RED
: TPG_COLOR_100_BLUE
;
1494 case TPG_PAT_CHECKERS_2X2
:
1495 return (((x
>> 1) & 1) ^ (pat_line
& 1)) ?
1496 TPG_COLOR_100_WHITE
: TPG_COLOR_100_BLACK
;
1497 case TPG_PAT_COLOR_CHECKERS_2X2
:
1498 return (((x
>> 1) & 1) ^ (pat_line
& 1)) ?
1499 TPG_COLOR_100_RED
: TPG_COLOR_100_BLUE
;
1500 case TPG_PAT_ALTERNATING_HLINES
:
1501 return pat_line
? TPG_COLOR_100_WHITE
: TPG_COLOR_100_BLACK
;
1502 case TPG_PAT_ALTERNATING_VLINES
:
1503 return (x
& 1) ? TPG_COLOR_100_WHITE
: TPG_COLOR_100_BLACK
;
1504 case TPG_PAT_CROSS_1_PIXEL
:
1505 if (pat_line
|| (x
% tpg
->src_width
) == tpg
->src_width
/ 2)
1506 return TPG_COLOR_100_BLACK
;
1507 return TPG_COLOR_100_WHITE
;
1508 case TPG_PAT_CROSS_2_PIXELS
:
1509 if (pat_line
|| ((x
% tpg
->src_width
) + 1) / 2 == tpg
->src_width
/ 4)
1510 return TPG_COLOR_100_BLACK
;
1511 return TPG_COLOR_100_WHITE
;
1512 case TPG_PAT_CROSS_10_PIXELS
:
1513 if (pat_line
|| ((x
% tpg
->src_width
) + 10) / 20 == tpg
->src_width
/ 40)
1514 return TPG_COLOR_100_BLACK
;
1515 return TPG_COLOR_100_WHITE
;
1516 case TPG_PAT_GRAY_RAMP
:
1517 return TPG_COLOR_RAMP
+ ((x
% tpg
->src_width
) * 256) / tpg
->src_width
;
1519 return TPG_COLOR_100_RED
;
1524 * Given the pixel aspect ratio and video aspect ratio calculate the
1525 * coordinates of a centered square and the coordinates of the border of
1526 * the active video area. The coordinates are relative to the source
1529 static void tpg_calculate_square_border(struct tpg_data
*tpg
)
1531 unsigned w
= tpg
->src_width
;
1532 unsigned h
= tpg
->src_height
;
1533 unsigned sq_w
, sq_h
;
1535 sq_w
= (w
* 2 / 5) & ~1;
1536 if (((w
- sq_w
) / 2) & 1)
1539 tpg
->square
.width
= sq_w
;
1540 if (tpg
->vid_aspect
== TPG_VIDEO_ASPECT_16X9_ANAMORPHIC
) {
1541 unsigned ana_sq_w
= (sq_w
/ 4) * 3;
1543 if (((w
- ana_sq_w
) / 2) & 1)
1545 tpg
->square
.width
= ana_sq_w
;
1547 tpg
->square
.left
= (w
- tpg
->square
.width
) / 2;
1548 if (tpg
->pix_aspect
== TPG_PIXEL_ASPECT_NTSC
)
1549 sq_h
= sq_w
* 10 / 11;
1550 else if (tpg
->pix_aspect
== TPG_PIXEL_ASPECT_PAL
)
1551 sq_h
= sq_w
* 59 / 54;
1552 tpg
->square
.height
= sq_h
;
1553 tpg
->square
.top
= (h
- sq_h
) / 2;
1554 tpg
->border
.left
= 0;
1555 tpg
->border
.width
= w
;
1556 tpg
->border
.top
= 0;
1557 tpg
->border
.height
= h
;
1558 switch (tpg
->vid_aspect
) {
1559 case TPG_VIDEO_ASPECT_4X3
:
1560 if (tpg
->pix_aspect
)
1562 if (3 * w
>= 4 * h
) {
1563 tpg
->border
.width
= ((4 * h
) / 3) & ~1;
1564 if (((w
- tpg
->border
.width
) / 2) & ~1)
1565 tpg
->border
.width
-= 2;
1566 tpg
->border
.left
= (w
- tpg
->border
.width
) / 2;
1569 tpg
->border
.height
= ((3 * w
) / 4) & ~1;
1570 tpg
->border
.top
= (h
- tpg
->border
.height
) / 2;
1572 case TPG_VIDEO_ASPECT_14X9_CENTRE
:
1573 if (tpg
->pix_aspect
) {
1574 tpg
->border
.height
= tpg
->pix_aspect
== TPG_PIXEL_ASPECT_NTSC
? 420 : 506;
1575 tpg
->border
.top
= (h
- tpg
->border
.height
) / 2;
1578 if (9 * w
>= 14 * h
) {
1579 tpg
->border
.width
= ((14 * h
) / 9) & ~1;
1580 if (((w
- tpg
->border
.width
) / 2) & ~1)
1581 tpg
->border
.width
-= 2;
1582 tpg
->border
.left
= (w
- tpg
->border
.width
) / 2;
1585 tpg
->border
.height
= ((9 * w
) / 14) & ~1;
1586 tpg
->border
.top
= (h
- tpg
->border
.height
) / 2;
1588 case TPG_VIDEO_ASPECT_16X9_CENTRE
:
1589 if (tpg
->pix_aspect
) {
1590 tpg
->border
.height
= tpg
->pix_aspect
== TPG_PIXEL_ASPECT_NTSC
? 368 : 442;
1591 tpg
->border
.top
= (h
- tpg
->border
.height
) / 2;
1594 if (9 * w
>= 16 * h
) {
1595 tpg
->border
.width
= ((16 * h
) / 9) & ~1;
1596 if (((w
- tpg
->border
.width
) / 2) & ~1)
1597 tpg
->border
.width
-= 2;
1598 tpg
->border
.left
= (w
- tpg
->border
.width
) / 2;
1601 tpg
->border
.height
= ((9 * w
) / 16) & ~1;
1602 tpg
->border
.top
= (h
- tpg
->border
.height
) / 2;
1609 static void tpg_precalculate_line(struct tpg_data
*tpg
)
1611 enum tpg_color contrast
;
1612 u8 pix
[TPG_MAX_PLANES
][8];
1617 switch (tpg
->pattern
) {
1619 contrast
= TPG_COLOR_100_RED
;
1621 case TPG_PAT_CSC_COLORBAR
:
1622 contrast
= TPG_COLOR_CSC_GREEN
;
1625 contrast
= TPG_COLOR_100_GREEN
;
1629 for (pat
= 0; pat
< tpg_get_pat_lines(tpg
); pat
++) {
1630 /* Coarse scaling with Bresenham */
1631 unsigned int_part
= tpg
->src_width
/ tpg
->scaled_width
;
1632 unsigned fract_part
= tpg
->src_width
% tpg
->scaled_width
;
1636 for (x
= 0; x
< tpg
->scaled_width
* 2; x
+= 2) {
1637 unsigned real_x
= src_x
;
1638 enum tpg_color color1
, color2
;
1640 real_x
= tpg
->hflip
? tpg
->src_width
* 2 - real_x
- 2 : real_x
;
1641 color1
= tpg_get_color(tpg
, pat
, real_x
);
1644 error
+= fract_part
;
1645 if (error
>= tpg
->scaled_width
) {
1646 error
-= tpg
->scaled_width
;
1651 real_x
= tpg
->hflip
? tpg
->src_width
* 2 - real_x
- 2 : real_x
;
1652 color2
= tpg_get_color(tpg
, pat
, real_x
);
1655 error
+= fract_part
;
1656 if (error
>= tpg
->scaled_width
) {
1657 error
-= tpg
->scaled_width
;
1661 gen_twopix(tpg
, pix
, tpg
->hflip
? color2
: color1
, 0);
1662 gen_twopix(tpg
, pix
, tpg
->hflip
? color1
: color2
, 1);
1663 for (p
= 0; p
< tpg
->planes
; p
++) {
1664 unsigned twopixsize
= tpg
->twopixelsize
[p
];
1665 unsigned hdiv
= tpg
->hdownsampling
[p
];
1666 u8
*pos
= tpg
->lines
[pat
][p
] + tpg_hdiv(tpg
, p
, x
);
1668 memcpy(pos
, pix
[p
], twopixsize
/ hdiv
);
1673 if (tpg
->vdownsampling
[tpg
->planes
- 1] > 1) {
1674 unsigned pat_lines
= tpg_get_pat_lines(tpg
);
1676 for (pat
= 0; pat
< pat_lines
; pat
++) {
1677 unsigned next_pat
= (pat
+ 1) % pat_lines
;
1679 for (p
= 1; p
< tpg
->planes
; p
++) {
1680 unsigned w
= tpg_hdiv(tpg
, p
, tpg
->scaled_width
* 2);
1681 u8
*pos1
= tpg
->lines
[pat
][p
];
1682 u8
*pos2
= tpg
->lines
[next_pat
][p
];
1683 u8
*dest
= tpg
->downsampled_lines
[pat
][p
];
1685 for (x
= 0; x
< w
; x
++, pos1
++, pos2
++, dest
++)
1686 *dest
= ((u16
)*pos1
+ (u16
)*pos2
) / 2;
1691 gen_twopix(tpg
, pix
, contrast
, 0);
1692 gen_twopix(tpg
, pix
, contrast
, 1);
1693 for (p
= 0; p
< tpg
->planes
; p
++) {
1694 unsigned twopixsize
= tpg
->twopixelsize
[p
];
1695 u8
*pos
= tpg
->contrast_line
[p
];
1697 for (x
= 0; x
< tpg
->scaled_width
; x
+= 2, pos
+= twopixsize
)
1698 memcpy(pos
, pix
[p
], twopixsize
);
1701 gen_twopix(tpg
, pix
, TPG_COLOR_100_BLACK
, 0);
1702 gen_twopix(tpg
, pix
, TPG_COLOR_100_BLACK
, 1);
1703 for (p
= 0; p
< tpg
->planes
; p
++) {
1704 unsigned twopixsize
= tpg
->twopixelsize
[p
];
1705 u8
*pos
= tpg
->black_line
[p
];
1707 for (x
= 0; x
< tpg
->scaled_width
; x
+= 2, pos
+= twopixsize
)
1708 memcpy(pos
, pix
[p
], twopixsize
);
1711 for (x
= 0; x
< tpg
->scaled_width
* 2; x
+= 2) {
1712 gen_twopix(tpg
, pix
, TPG_COLOR_RANDOM
, 0);
1713 gen_twopix(tpg
, pix
, TPG_COLOR_RANDOM
, 1);
1714 for (p
= 0; p
< tpg
->planes
; p
++) {
1715 unsigned twopixsize
= tpg
->twopixelsize
[p
];
1716 u8
*pos
= tpg
->random_line
[p
] + x
* twopixsize
/ 2;
1718 memcpy(pos
, pix
[p
], twopixsize
);
1722 gen_twopix(tpg
, tpg
->textbg
, TPG_COLOR_TEXTBG
, 0);
1723 gen_twopix(tpg
, tpg
->textbg
, TPG_COLOR_TEXTBG
, 1);
1724 gen_twopix(tpg
, tpg
->textfg
, TPG_COLOR_TEXTFG
, 0);
1725 gen_twopix(tpg
, tpg
->textfg
, TPG_COLOR_TEXTFG
, 1);
1728 /* need this to do rgb24 rendering */
1729 typedef struct { u16 __
; u8 _
; } __packed x24
;
1731 #define PRINTSTR(PIXTYPE) do { \
1732 unsigned vdiv = tpg->vdownsampling[p]; \
1733 unsigned hdiv = tpg->hdownsampling[p]; \
1737 memcpy(&fg, tpg->textfg[p], sizeof(PIXTYPE)); \
1738 memcpy(&bg, tpg->textbg[p], sizeof(PIXTYPE)); \
1740 for (line = first; line < 16; line += vdiv * step) { \
1741 int l = tpg->vflip ? 15 - line : line; \
1742 PIXTYPE *pos = (PIXTYPE *)(basep[p][(line / vdiv) & 1] + \
1743 ((y * step + l) / (vdiv * div)) * tpg->bytesperline[p] + \
1744 (x / hdiv) * sizeof(PIXTYPE)); \
1747 for (s = 0; s < len; s++) { \
1748 u8 chr = font8x16[text[s] * 16 + line]; \
1750 if (hdiv == 2 && tpg->hflip) { \
1751 pos[3] = (chr & (0x01 << 6) ? fg : bg); \
1752 pos[2] = (chr & (0x01 << 4) ? fg : bg); \
1753 pos[1] = (chr & (0x01 << 2) ? fg : bg); \
1754 pos[0] = (chr & (0x01 << 0) ? fg : bg); \
1755 } else if (hdiv == 2) { \
1756 pos[0] = (chr & (0x01 << 7) ? fg : bg); \
1757 pos[1] = (chr & (0x01 << 5) ? fg : bg); \
1758 pos[2] = (chr & (0x01 << 3) ? fg : bg); \
1759 pos[3] = (chr & (0x01 << 1) ? fg : bg); \
1760 } else if (tpg->hflip) { \
1761 pos[7] = (chr & (0x01 << 7) ? fg : bg); \
1762 pos[6] = (chr & (0x01 << 6) ? fg : bg); \
1763 pos[5] = (chr & (0x01 << 5) ? fg : bg); \
1764 pos[4] = (chr & (0x01 << 4) ? fg : bg); \
1765 pos[3] = (chr & (0x01 << 3) ? fg : bg); \
1766 pos[2] = (chr & (0x01 << 2) ? fg : bg); \
1767 pos[1] = (chr & (0x01 << 1) ? fg : bg); \
1768 pos[0] = (chr & (0x01 << 0) ? fg : bg); \
1770 pos[0] = (chr & (0x01 << 7) ? fg : bg); \
1771 pos[1] = (chr & (0x01 << 6) ? fg : bg); \
1772 pos[2] = (chr & (0x01 << 5) ? fg : bg); \
1773 pos[3] = (chr & (0x01 << 4) ? fg : bg); \
1774 pos[4] = (chr & (0x01 << 3) ? fg : bg); \
1775 pos[5] = (chr & (0x01 << 2) ? fg : bg); \
1776 pos[6] = (chr & (0x01 << 1) ? fg : bg); \
1777 pos[7] = (chr & (0x01 << 0) ? fg : bg); \
1780 pos += (tpg->hflip ? -8 : 8) / hdiv; \
1785 static noinline
void tpg_print_str_2(const struct tpg_data
*tpg
, u8
*basep
[TPG_MAX_PLANES
][2],
1786 unsigned p
, unsigned first
, unsigned div
, unsigned step
,
1787 int y
, int x
, char *text
, unsigned len
)
1792 static noinline
void tpg_print_str_4(const struct tpg_data
*tpg
, u8
*basep
[TPG_MAX_PLANES
][2],
1793 unsigned p
, unsigned first
, unsigned div
, unsigned step
,
1794 int y
, int x
, char *text
, unsigned len
)
1799 static noinline
void tpg_print_str_6(const struct tpg_data
*tpg
, u8
*basep
[TPG_MAX_PLANES
][2],
1800 unsigned p
, unsigned first
, unsigned div
, unsigned step
,
1801 int y
, int x
, char *text
, unsigned len
)
1806 static noinline
void tpg_print_str_8(const struct tpg_data
*tpg
, u8
*basep
[TPG_MAX_PLANES
][2],
1807 unsigned p
, unsigned first
, unsigned div
, unsigned step
,
1808 int y
, int x
, char *text
, unsigned len
)
1813 void tpg_gen_text(const struct tpg_data
*tpg
, u8
*basep
[TPG_MAX_PLANES
][2],
1814 int y
, int x
, char *text
)
1816 unsigned step
= V4L2_FIELD_HAS_T_OR_B(tpg
->field
) ? 2 : 1;
1817 unsigned div
= step
;
1819 unsigned len
= strlen(text
);
1822 if (font8x16
== NULL
|| basep
== NULL
)
1825 /* Checks if it is possible to show string */
1826 if (y
+ 16 >= tpg
->compose
.height
|| x
+ 8 >= tpg
->compose
.width
)
1829 if (len
> (tpg
->compose
.width
- x
) / 8)
1830 len
= (tpg
->compose
.width
- x
) / 8;
1832 y
= tpg
->compose
.height
- y
- 16;
1834 x
= tpg
->compose
.width
- x
- 8;
1835 y
+= tpg
->compose
.top
;
1836 x
+= tpg
->compose
.left
;
1837 if (tpg
->field
== V4L2_FIELD_BOTTOM
)
1839 else if (tpg
->field
== V4L2_FIELD_SEQ_TB
|| tpg
->field
== V4L2_FIELD_SEQ_BT
)
1842 for (p
= 0; p
< tpg
->planes
; p
++) {
1844 switch (tpg
->twopixelsize
[p
]) {
1846 tpg_print_str_2(tpg
, basep
, p
, first
, div
, step
, y
, x
,
1850 tpg_print_str_4(tpg
, basep
, p
, first
, div
, step
, y
, x
,
1854 tpg_print_str_6(tpg
, basep
, p
, first
, div
, step
, y
, x
,
1858 tpg_print_str_8(tpg
, basep
, p
, first
, div
, step
, y
, x
,
1864 EXPORT_SYMBOL_GPL(tpg_gen_text
);
1866 void tpg_update_mv_step(struct tpg_data
*tpg
)
1868 int factor
= tpg
->mv_hor_mode
> TPG_MOVE_NONE
? -1 : 1;
1872 switch (tpg
->mv_hor_mode
) {
1873 case TPG_MOVE_NEG_FAST
:
1874 case TPG_MOVE_POS_FAST
:
1875 tpg
->mv_hor_step
= ((tpg
->src_width
+ 319) / 320) * 4;
1879 tpg
->mv_hor_step
= ((tpg
->src_width
+ 639) / 640) * 4;
1881 case TPG_MOVE_NEG_SLOW
:
1882 case TPG_MOVE_POS_SLOW
:
1883 tpg
->mv_hor_step
= 2;
1886 tpg
->mv_hor_step
= 0;
1890 tpg
->mv_hor_step
= tpg
->src_width
- tpg
->mv_hor_step
;
1892 factor
= tpg
->mv_vert_mode
> TPG_MOVE_NONE
? -1 : 1;
1893 switch (tpg
->mv_vert_mode
) {
1894 case TPG_MOVE_NEG_FAST
:
1895 case TPG_MOVE_POS_FAST
:
1896 tpg
->mv_vert_step
= ((tpg
->src_width
+ 319) / 320) * 4;
1900 tpg
->mv_vert_step
= ((tpg
->src_width
+ 639) / 640) * 4;
1902 case TPG_MOVE_NEG_SLOW
:
1903 case TPG_MOVE_POS_SLOW
:
1904 tpg
->mv_vert_step
= 1;
1907 tpg
->mv_vert_step
= 0;
1911 tpg
->mv_vert_step
= tpg
->src_height
- tpg
->mv_vert_step
;
1913 EXPORT_SYMBOL_GPL(tpg_update_mv_step
);
1915 /* Map the line number relative to the crop rectangle to a frame line number */
1916 static unsigned tpg_calc_frameline(const struct tpg_data
*tpg
, unsigned src_y
,
1920 case V4L2_FIELD_TOP
:
1921 return tpg
->crop
.top
+ src_y
* 2;
1922 case V4L2_FIELD_BOTTOM
:
1923 return tpg
->crop
.top
+ src_y
* 2 + 1;
1925 return src_y
+ tpg
->crop
.top
;
1930 * Map the line number relative to the compose rectangle to a destination
1931 * buffer line number.
1933 static unsigned tpg_calc_buffer_line(const struct tpg_data
*tpg
, unsigned y
,
1936 y
+= tpg
->compose
.top
;
1938 case V4L2_FIELD_SEQ_TB
:
1940 return tpg
->buf_height
/ 2 + y
/ 2;
1942 case V4L2_FIELD_SEQ_BT
:
1945 return tpg
->buf_height
/ 2 + y
/ 2;
1951 static void tpg_recalc(struct tpg_data
*tpg
)
1953 if (tpg
->recalc_colors
) {
1954 tpg
->recalc_colors
= false;
1955 tpg
->recalc_lines
= true;
1956 tpg
->real_xfer_func
= tpg
->xfer_func
;
1957 tpg
->real_ycbcr_enc
= tpg
->ycbcr_enc
;
1958 tpg
->real_hsv_enc
= tpg
->hsv_enc
;
1959 tpg
->real_quantization
= tpg
->quantization
;
1961 if (tpg
->xfer_func
== V4L2_XFER_FUNC_DEFAULT
)
1962 tpg
->real_xfer_func
=
1963 V4L2_MAP_XFER_FUNC_DEFAULT(tpg
->colorspace
);
1965 if (tpg
->ycbcr_enc
== V4L2_YCBCR_ENC_DEFAULT
)
1966 tpg
->real_ycbcr_enc
=
1967 V4L2_MAP_YCBCR_ENC_DEFAULT(tpg
->colorspace
);
1969 if (tpg
->quantization
== V4L2_QUANTIZATION_DEFAULT
)
1970 tpg
->real_quantization
=
1971 V4L2_MAP_QUANTIZATION_DEFAULT(
1972 tpg
->color_enc
!= TGP_COLOR_ENC_YCBCR
,
1973 tpg
->colorspace
, tpg
->real_ycbcr_enc
);
1975 tpg_precalculate_colors(tpg
);
1977 if (tpg
->recalc_square_border
) {
1978 tpg
->recalc_square_border
= false;
1979 tpg_calculate_square_border(tpg
);
1981 if (tpg
->recalc_lines
) {
1982 tpg
->recalc_lines
= false;
1983 tpg_precalculate_line(tpg
);
1987 void tpg_calc_text_basep(struct tpg_data
*tpg
,
1988 u8
*basep
[TPG_MAX_PLANES
][2], unsigned p
, u8
*vbuf
)
1990 unsigned stride
= tpg
->bytesperline
[p
];
1991 unsigned h
= tpg
->buf_height
;
1997 h
/= tpg
->vdownsampling
[p
];
1998 if (tpg
->field
== V4L2_FIELD_SEQ_TB
)
1999 basep
[p
][1] += h
* stride
/ 2;
2000 else if (tpg
->field
== V4L2_FIELD_SEQ_BT
)
2001 basep
[p
][0] += h
* stride
/ 2;
2002 if (p
== 0 && tpg
->interleaved
)
2003 tpg_calc_text_basep(tpg
, basep
, 1, vbuf
);
2005 EXPORT_SYMBOL_GPL(tpg_calc_text_basep
);
2007 static int tpg_pattern_avg(const struct tpg_data
*tpg
,
2008 unsigned pat1
, unsigned pat2
)
2010 unsigned pat_lines
= tpg_get_pat_lines(tpg
);
2012 if (pat1
== (pat2
+ 1) % pat_lines
)
2014 if (pat2
== (pat1
+ 1) % pat_lines
)
2019 static const char *tpg_color_enc_str(enum tgp_color_enc
2022 switch (color_enc
) {
2023 case TGP_COLOR_ENC_HSV
:
2025 case TGP_COLOR_ENC_YCBCR
:
2027 case TGP_COLOR_ENC_LUMA
:
2029 case TGP_COLOR_ENC_RGB
:
2036 void tpg_log_status(struct tpg_data
*tpg
)
2038 pr_info("tpg source WxH: %ux%u (%s)\n",
2039 tpg
->src_width
, tpg
->src_height
,
2040 tpg_color_enc_str(tpg
->color_enc
));
2041 pr_info("tpg field: %u\n", tpg
->field
);
2042 pr_info("tpg crop: %ux%u@%dx%d\n", tpg
->crop
.width
, tpg
->crop
.height
,
2043 tpg
->crop
.left
, tpg
->crop
.top
);
2044 pr_info("tpg compose: %ux%u@%dx%d\n", tpg
->compose
.width
, tpg
->compose
.height
,
2045 tpg
->compose
.left
, tpg
->compose
.top
);
2046 pr_info("tpg colorspace: %d\n", tpg
->colorspace
);
2047 pr_info("tpg transfer function: %d/%d\n", tpg
->xfer_func
, tpg
->real_xfer_func
);
2048 pr_info("tpg Y'CbCr encoding: %d/%d\n", tpg
->ycbcr_enc
, tpg
->real_ycbcr_enc
);
2049 pr_info("tpg HSV encoding: %d/%d\n", tpg
->hsv_enc
, tpg
->real_hsv_enc
);
2050 pr_info("tpg quantization: %d/%d\n", tpg
->quantization
, tpg
->real_quantization
);
2051 pr_info("tpg RGB range: %d/%d\n", tpg
->rgb_range
, tpg
->real_rgb_range
);
2053 EXPORT_SYMBOL_GPL(tpg_log_status
);
2056 * This struct contains common parameters used by both the drawing of the
2057 * test pattern and the drawing of the extras (borders, square, etc.)
2059 struct tpg_draw_params
{
2063 unsigned twopixsize
;
2067 unsigned frame_line
;
2068 unsigned frame_line_next
;
2071 unsigned mv_hor_old
;
2072 unsigned mv_hor_new
;
2073 unsigned mv_vert_old
;
2074 unsigned mv_vert_new
;
2078 unsigned wss_random_offset
;
2080 unsigned left_pillar_width
;
2081 unsigned right_pillar_start
;
2084 static void tpg_fill_params_pattern(const struct tpg_data
*tpg
, unsigned p
,
2085 struct tpg_draw_params
*params
)
2087 params
->mv_hor_old
=
2088 tpg_hscale_div(tpg
, p
, tpg
->mv_hor_count
% tpg
->src_width
);
2089 params
->mv_hor_new
=
2090 tpg_hscale_div(tpg
, p
, (tpg
->mv_hor_count
+ tpg
->mv_hor_step
) %
2092 params
->mv_vert_old
= tpg
->mv_vert_count
% tpg
->src_height
;
2093 params
->mv_vert_new
=
2094 (tpg
->mv_vert_count
+ tpg
->mv_vert_step
) % tpg
->src_height
;
2097 static void tpg_fill_params_extras(const struct tpg_data
*tpg
,
2099 struct tpg_draw_params
*params
)
2101 unsigned left_pillar_width
= 0;
2102 unsigned right_pillar_start
= params
->img_width
;
2104 params
->wss_width
= tpg
->crop
.left
< tpg
->src_width
/ 2 ?
2105 tpg
->src_width
/ 2 - tpg
->crop
.left
: 0;
2106 if (params
->wss_width
> tpg
->crop
.width
)
2107 params
->wss_width
= tpg
->crop
.width
;
2108 params
->wss_width
= tpg_hscale_div(tpg
, p
, params
->wss_width
);
2109 params
->wss_random_offset
=
2110 params
->twopixsize
* prandom_u32_max(tpg
->src_width
/ 2);
2112 if (tpg
->crop
.left
< tpg
->border
.left
) {
2113 left_pillar_width
= tpg
->border
.left
- tpg
->crop
.left
;
2114 if (left_pillar_width
> tpg
->crop
.width
)
2115 left_pillar_width
= tpg
->crop
.width
;
2116 left_pillar_width
= tpg_hscale_div(tpg
, p
, left_pillar_width
);
2118 params
->left_pillar_width
= left_pillar_width
;
2120 if (tpg
->crop
.left
+ tpg
->crop
.width
>
2121 tpg
->border
.left
+ tpg
->border
.width
) {
2122 right_pillar_start
=
2123 tpg
->border
.left
+ tpg
->border
.width
- tpg
->crop
.left
;
2124 right_pillar_start
=
2125 tpg_hscale_div(tpg
, p
, right_pillar_start
);
2126 if (right_pillar_start
> params
->img_width
)
2127 right_pillar_start
= params
->img_width
;
2129 params
->right_pillar_start
= right_pillar_start
;
2131 params
->sav_eav_f
= tpg
->field
==
2132 (params
->is_60hz
? V4L2_FIELD_TOP
: V4L2_FIELD_BOTTOM
);
2135 static void tpg_fill_plane_extras(const struct tpg_data
*tpg
,
2136 const struct tpg_draw_params
*params
,
2137 unsigned p
, unsigned h
, u8
*vbuf
)
2139 unsigned twopixsize
= params
->twopixsize
;
2140 unsigned img_width
= params
->img_width
;
2141 unsigned frame_line
= params
->frame_line
;
2142 const struct v4l2_rect
*sq
= &tpg
->square
;
2143 const struct v4l2_rect
*b
= &tpg
->border
;
2144 const struct v4l2_rect
*c
= &tpg
->crop
;
2146 if (params
->is_tv
&& !params
->is_60hz
&&
2147 frame_line
== 0 && params
->wss_width
) {
2149 * Replace the first half of the top line of a 50 Hz frame
2150 * with random data to simulate a WSS signal.
2152 u8
*wss
= tpg
->random_line
[p
] + params
->wss_random_offset
;
2154 memcpy(vbuf
, wss
, params
->wss_width
);
2157 if (tpg
->show_border
&& frame_line
>= b
->top
&&
2158 frame_line
< b
->top
+ b
->height
) {
2159 unsigned bottom
= b
->top
+ b
->height
- 1;
2160 unsigned left
= params
->left_pillar_width
;
2161 unsigned right
= params
->right_pillar_start
;
2163 if (frame_line
== b
->top
|| frame_line
== b
->top
+ 1 ||
2164 frame_line
== bottom
|| frame_line
== bottom
- 1) {
2165 memcpy(vbuf
+ left
, tpg
->contrast_line
[p
],
2168 if (b
->left
>= c
->left
&&
2169 b
->left
< c
->left
+ c
->width
)
2171 tpg
->contrast_line
[p
], twopixsize
);
2172 if (b
->left
+ b
->width
> c
->left
&&
2173 b
->left
+ b
->width
<= c
->left
+ c
->width
)
2174 memcpy(vbuf
+ right
- twopixsize
,
2175 tpg
->contrast_line
[p
], twopixsize
);
2178 if (tpg
->qual
!= TPG_QUAL_NOISE
&& frame_line
>= b
->top
&&
2179 frame_line
< b
->top
+ b
->height
) {
2180 memcpy(vbuf
, tpg
->black_line
[p
], params
->left_pillar_width
);
2181 memcpy(vbuf
+ params
->right_pillar_start
, tpg
->black_line
[p
],
2182 img_width
- params
->right_pillar_start
);
2184 if (tpg
->show_square
&& frame_line
>= sq
->top
&&
2185 frame_line
< sq
->top
+ sq
->height
&&
2186 sq
->left
< c
->left
+ c
->width
&&
2187 sq
->left
+ sq
->width
>= c
->left
) {
2188 unsigned left
= sq
->left
;
2189 unsigned width
= sq
->width
;
2191 if (c
->left
> left
) {
2192 width
-= c
->left
- left
;
2195 if (c
->left
+ c
->width
< left
+ width
)
2196 width
-= left
+ width
- c
->left
- c
->width
;
2198 left
= tpg_hscale_div(tpg
, p
, left
);
2199 width
= tpg_hscale_div(tpg
, p
, width
);
2200 memcpy(vbuf
+ left
, tpg
->contrast_line
[p
], width
);
2202 if (tpg
->insert_sav
) {
2203 unsigned offset
= tpg_hdiv(tpg
, p
, tpg
->compose
.width
/ 3);
2204 u8
*p
= vbuf
+ offset
;
2205 unsigned vact
= 0, hact
= 0;
2210 p
[3] = 0x80 | (params
->sav_eav_f
<< 6) |
2211 (vact
<< 5) | (hact
<< 4) |
2212 ((hact
^ vact
) << 3) |
2213 ((hact
^ params
->sav_eav_f
) << 2) |
2214 ((params
->sav_eav_f
^ vact
) << 1) |
2215 (hact
^ vact
^ params
->sav_eav_f
);
2217 if (tpg
->insert_eav
) {
2218 unsigned offset
= tpg_hdiv(tpg
, p
, tpg
->compose
.width
* 2 / 3);
2219 u8
*p
= vbuf
+ offset
;
2220 unsigned vact
= 0, hact
= 1;
2225 p
[3] = 0x80 | (params
->sav_eav_f
<< 6) |
2226 (vact
<< 5) | (hact
<< 4) |
2227 ((hact
^ vact
) << 3) |
2228 ((hact
^ params
->sav_eav_f
) << 2) |
2229 ((params
->sav_eav_f
^ vact
) << 1) |
2230 (hact
^ vact
^ params
->sav_eav_f
);
2234 static void tpg_fill_plane_pattern(const struct tpg_data
*tpg
,
2235 const struct tpg_draw_params
*params
,
2236 unsigned p
, unsigned h
, u8
*vbuf
)
2238 unsigned twopixsize
= params
->twopixsize
;
2239 unsigned img_width
= params
->img_width
;
2240 unsigned mv_hor_old
= params
->mv_hor_old
;
2241 unsigned mv_hor_new
= params
->mv_hor_new
;
2242 unsigned mv_vert_old
= params
->mv_vert_old
;
2243 unsigned mv_vert_new
= params
->mv_vert_new
;
2244 unsigned frame_line
= params
->frame_line
;
2245 unsigned frame_line_next
= params
->frame_line_next
;
2246 unsigned line_offset
= tpg_hscale_div(tpg
, p
, tpg
->crop
.left
);
2248 bool fill_blank
= false;
2249 unsigned pat_line_old
;
2250 unsigned pat_line_new
;
2251 u8
*linestart_older
;
2252 u8
*linestart_newer
;
2254 u8
*linestart_bottom
;
2256 even
= !(frame_line
& 1);
2258 if (h
>= params
->hmax
) {
2259 if (params
->hmax
== tpg
->compose
.height
)
2261 if (!tpg
->perc_fill_blank
)
2267 frame_line
= tpg
->src_height
- frame_line
- 1;
2268 frame_line_next
= tpg
->src_height
- frame_line_next
- 1;
2272 linestart_older
= tpg
->contrast_line
[p
];
2273 linestart_newer
= tpg
->contrast_line
[p
];
2274 } else if (tpg
->qual
!= TPG_QUAL_NOISE
&&
2275 (frame_line
< tpg
->border
.top
||
2276 frame_line
>= tpg
->border
.top
+ tpg
->border
.height
)) {
2277 linestart_older
= tpg
->black_line
[p
];
2278 linestart_newer
= tpg
->black_line
[p
];
2279 } else if (tpg
->pattern
== TPG_PAT_NOISE
|| tpg
->qual
== TPG_QUAL_NOISE
) {
2280 linestart_older
= tpg
->random_line
[p
] +
2281 twopixsize
* prandom_u32_max(tpg
->src_width
/ 2);
2282 linestart_newer
= tpg
->random_line
[p
] +
2283 twopixsize
* prandom_u32_max(tpg
->src_width
/ 2);
2285 unsigned frame_line_old
=
2286 (frame_line
+ mv_vert_old
) % tpg
->src_height
;
2287 unsigned frame_line_new
=
2288 (frame_line
+ mv_vert_new
) % tpg
->src_height
;
2289 unsigned pat_line_next_old
;
2290 unsigned pat_line_next_new
;
2292 pat_line_old
= tpg_get_pat_line(tpg
, frame_line_old
);
2293 pat_line_new
= tpg_get_pat_line(tpg
, frame_line_new
);
2294 linestart_older
= tpg
->lines
[pat_line_old
][p
] + mv_hor_old
;
2295 linestart_newer
= tpg
->lines
[pat_line_new
][p
] + mv_hor_new
;
2297 if (tpg
->vdownsampling
[p
] > 1 && frame_line
!= frame_line_next
) {
2301 * Now decide whether we need to use downsampled_lines[].
2302 * That's necessary if the two lines use different patterns.
2304 pat_line_next_old
= tpg_get_pat_line(tpg
,
2305 (frame_line_next
+ mv_vert_old
) % tpg
->src_height
);
2306 pat_line_next_new
= tpg_get_pat_line(tpg
,
2307 (frame_line_next
+ mv_vert_new
) % tpg
->src_height
);
2309 switch (tpg
->field
) {
2310 case V4L2_FIELD_INTERLACED
:
2311 case V4L2_FIELD_INTERLACED_BT
:
2312 case V4L2_FIELD_INTERLACED_TB
:
2313 avg_pat
= tpg_pattern_avg(tpg
, pat_line_old
, pat_line_new
);
2316 linestart_older
= tpg
->downsampled_lines
[avg_pat
][p
] + mv_hor_old
;
2317 linestart_newer
= linestart_older
;
2319 case V4L2_FIELD_NONE
:
2320 case V4L2_FIELD_TOP
:
2321 case V4L2_FIELD_BOTTOM
:
2322 case V4L2_FIELD_SEQ_BT
:
2323 case V4L2_FIELD_SEQ_TB
:
2324 avg_pat
= tpg_pattern_avg(tpg
, pat_line_old
, pat_line_next_old
);
2326 linestart_older
= tpg
->downsampled_lines
[avg_pat
][p
] +
2328 avg_pat
= tpg_pattern_avg(tpg
, pat_line_new
, pat_line_next_new
);
2330 linestart_newer
= tpg
->downsampled_lines
[avg_pat
][p
] +
2335 linestart_older
+= line_offset
;
2336 linestart_newer
+= line_offset
;
2338 if (tpg
->field_alternate
) {
2339 linestart_top
= linestart_bottom
= linestart_older
;
2340 } else if (params
->is_60hz
) {
2341 linestart_top
= linestart_newer
;
2342 linestart_bottom
= linestart_older
;
2344 linestart_top
= linestart_older
;
2345 linestart_bottom
= linestart_newer
;
2348 switch (tpg
->field
) {
2349 case V4L2_FIELD_INTERLACED
:
2350 case V4L2_FIELD_INTERLACED_TB
:
2351 case V4L2_FIELD_SEQ_TB
:
2352 case V4L2_FIELD_SEQ_BT
:
2354 memcpy(vbuf
, linestart_top
, img_width
);
2356 memcpy(vbuf
, linestart_bottom
, img_width
);
2358 case V4L2_FIELD_INTERLACED_BT
:
2360 memcpy(vbuf
, linestart_bottom
, img_width
);
2362 memcpy(vbuf
, linestart_top
, img_width
);
2364 case V4L2_FIELD_TOP
:
2365 memcpy(vbuf
, linestart_top
, img_width
);
2367 case V4L2_FIELD_BOTTOM
:
2368 memcpy(vbuf
, linestart_bottom
, img_width
);
2370 case V4L2_FIELD_NONE
:
2372 memcpy(vbuf
, linestart_older
, img_width
);
2377 void tpg_fill_plane_buffer(struct tpg_data
*tpg
, v4l2_std_id std
,
2378 unsigned p
, u8
*vbuf
)
2380 struct tpg_draw_params params
;
2381 unsigned factor
= V4L2_FIELD_HAS_T_OR_B(tpg
->field
) ? 2 : 1;
2383 /* Coarse scaling with Bresenham */
2384 unsigned int_part
= (tpg
->crop
.height
/ factor
) / tpg
->compose
.height
;
2385 unsigned fract_part
= (tpg
->crop
.height
/ factor
) % tpg
->compose
.height
;
2393 params
.is_60hz
= std
& V4L2_STD_525_60
;
2394 params
.twopixsize
= tpg
->twopixelsize
[p
];
2395 params
.img_width
= tpg_hdiv(tpg
, p
, tpg
->compose
.width
);
2396 params
.stride
= tpg
->bytesperline
[p
];
2397 params
.hmax
= (tpg
->compose
.height
* tpg
->perc_fill
) / 100;
2399 tpg_fill_params_pattern(tpg
, p
, ¶ms
);
2400 tpg_fill_params_extras(tpg
, p
, ¶ms
);
2402 vbuf
+= tpg_hdiv(tpg
, p
, tpg
->compose
.left
);
2404 for (h
= 0; h
< tpg
->compose
.height
; h
++) {
2407 params
.frame_line
= tpg_calc_frameline(tpg
, src_y
, tpg
->field
);
2408 params
.frame_line_next
= params
.frame_line
;
2409 buf_line
= tpg_calc_buffer_line(tpg
, h
, tpg
->field
);
2411 error
+= fract_part
;
2412 if (error
>= tpg
->compose
.height
) {
2413 error
-= tpg
->compose
.height
;
2418 * For line-interleaved formats determine the 'plane'
2419 * based on the buffer line.
2421 if (tpg_g_interleaved(tpg
))
2422 p
= tpg_g_interleaved_plane(tpg
, buf_line
);
2424 if (tpg
->vdownsampling
[p
] > 1) {
2426 * When doing vertical downsampling the field setting
2427 * matters: for SEQ_BT/TB we downsample each field
2428 * separately (i.e. lines 0+2 are combined, as are
2429 * lines 1+3), for the other field settings we combine
2430 * odd and even lines. Doing that for SEQ_BT/TB would
2433 if (tpg
->field
== V4L2_FIELD_SEQ_BT
||
2434 tpg
->field
== V4L2_FIELD_SEQ_TB
) {
2435 unsigned next_src_y
= src_y
;
2439 next_src_y
+= int_part
;
2440 if (error
+ fract_part
>= tpg
->compose
.height
)
2442 params
.frame_line_next
=
2443 tpg_calc_frameline(tpg
, next_src_y
, tpg
->field
);
2447 params
.frame_line_next
=
2448 tpg_calc_frameline(tpg
, src_y
, tpg
->field
);
2451 buf_line
/= tpg
->vdownsampling
[p
];
2453 tpg_fill_plane_pattern(tpg
, ¶ms
, p
, h
,
2454 vbuf
+ buf_line
* params
.stride
);
2455 tpg_fill_plane_extras(tpg
, ¶ms
, p
, h
,
2456 vbuf
+ buf_line
* params
.stride
);
2459 EXPORT_SYMBOL_GPL(tpg_fill_plane_buffer
);
2461 void tpg_fillbuffer(struct tpg_data
*tpg
, v4l2_std_id std
, unsigned p
, u8
*vbuf
)
2463 unsigned offset
= 0;
2466 if (tpg
->buffers
> 1) {
2467 tpg_fill_plane_buffer(tpg
, std
, p
, vbuf
);
2471 for (i
= 0; i
< tpg_g_planes(tpg
); i
++) {
2472 tpg_fill_plane_buffer(tpg
, std
, i
, vbuf
+ offset
);
2473 offset
+= tpg_calc_plane_size(tpg
, i
);
2476 EXPORT_SYMBOL_GPL(tpg_fillbuffer
);
2478 MODULE_DESCRIPTION("V4L2 Test Pattern Generator");
2479 MODULE_AUTHOR("Hans Verkuil");
2480 MODULE_LICENSE("GPL");