2733 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * v4l2-tpg-core.c - Test Pattern Generator4 *5 * Note: gen_twopix and tpg_gen_text are based on code from vivi.c. See the6 * vivi.c source for the copyright information of those functions.7 *8 * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.9 */10 11#include <linux/module.h>12#include <media/tpg/v4l2-tpg.h>13 14/* Must remain in sync with enum tpg_pattern */15const char * const tpg_pattern_strings[] = {16 "75% Colorbar",17 "100% Colorbar",18 "CSC Colorbar",19 "Horizontal 100% Colorbar",20 "100% Color Squares",21 "100% Black",22 "100% White",23 "100% Red",24 "100% Green",25 "100% Blue",26 "16x16 Checkers",27 "2x2 Checkers",28 "1x1 Checkers",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",36 "Gray Ramp",37 "Noise",38 NULL39};40EXPORT_SYMBOL_GPL(tpg_pattern_strings);41 42/* Must remain in sync with enum tpg_aspect */43const char * const tpg_aspect_strings[] = {44 "Source Width x Height",45 "4x3",46 "14x9",47 "16x9",48 "16x9 Anamorphic",49 NULL50};51EXPORT_SYMBOL_GPL(tpg_aspect_strings);52 53/*54 * Sine table: sin[0] = 127 * sin(-180 degrees)55 * sin[128] = 127 * sin(0 degrees)56 * sin[256] = 127 * sin(180 degrees)57 */58static 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,75 0,76};77 78#define cos(idx) sin[((idx) + 64) % sizeof(sin)]79 80/* Global font descriptor */81static const u8 *font8x16;82 83void tpg_set_font(const u8 *f)84{85 font8x16 = f;86}87EXPORT_SYMBOL_GPL(tpg_set_font);88 89void tpg_init(struct tpg_data *tpg, unsigned w, unsigned h)90{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;99 tpg->contrast = 128;100 tpg->saturation = 128;101 tpg->hue = 0;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;109}110EXPORT_SYMBOL_GPL(tpg_init);111 112int tpg_alloc(struct tpg_data *tpg, unsigned max_w)113{114 unsigned pat;115 unsigned plane;116 int ret = 0;117 118 tpg->max_line_width = max_w;119 for (pat = 0; pat < TPG_MAX_PAT_LINES; pat++) {120 for (plane = 0; plane < TPG_MAX_PLANES; plane++) {121 unsigned pixelsz = plane ? 2 : 4;122 123 tpg->lines[pat][plane] =124 vzalloc(array3_size(max_w, 2, pixelsz));125 if (!tpg->lines[pat][plane]) {126 ret = -ENOMEM;127 goto free_lines;128 }129 if (plane == 0)130 continue;131 tpg->downsampled_lines[pat][plane] =132 vzalloc(array3_size(max_w, 2, pixelsz));133 if (!tpg->downsampled_lines[pat][plane]) {134 ret = -ENOMEM;135 goto free_lines;136 }137 }138 }139 for (plane = 0; plane < TPG_MAX_PLANES; plane++) {140 unsigned pixelsz = plane ? 2 : 4;141 142 tpg->contrast_line[plane] =143 vzalloc(array_size(pixelsz, max_w));144 if (!tpg->contrast_line[plane]) {145 ret = -ENOMEM;146 goto free_contrast_line;147 }148 tpg->black_line[plane] =149 vzalloc(array_size(pixelsz, max_w));150 if (!tpg->black_line[plane]) {151 ret = -ENOMEM;152 goto free_contrast_line;153 }154 tpg->random_line[plane] =155 vzalloc(array3_size(max_w, 2, pixelsz));156 if (!tpg->random_line[plane]) {157 ret = -ENOMEM;158 goto free_contrast_line;159 }160 }161 return 0;162 163free_contrast_line:164 for (plane = 0; plane < TPG_MAX_PLANES; plane++) {165 vfree(tpg->contrast_line[plane]);166 vfree(tpg->black_line[plane]);167 vfree(tpg->random_line[plane]);168 tpg->contrast_line[plane] = NULL;169 tpg->black_line[plane] = NULL;170 tpg->random_line[plane] = NULL;171 }172free_lines:173 for (pat = 0; pat < TPG_MAX_PAT_LINES; pat++)174 for (plane = 0; plane < TPG_MAX_PLANES; plane++) {175 vfree(tpg->lines[pat][plane]);176 tpg->lines[pat][plane] = NULL;177 if (plane == 0)178 continue;179 vfree(tpg->downsampled_lines[pat][plane]);180 tpg->downsampled_lines[pat][plane] = NULL;181 }182 return ret;183}184EXPORT_SYMBOL_GPL(tpg_alloc);185 186void tpg_free(struct tpg_data *tpg)187{188 unsigned pat;189 unsigned plane;190 191 for (pat = 0; pat < TPG_MAX_PAT_LINES; pat++)192 for (plane = 0; plane < TPG_MAX_PLANES; plane++) {193 vfree(tpg->lines[pat][plane]);194 tpg->lines[pat][plane] = NULL;195 if (plane == 0)196 continue;197 vfree(tpg->downsampled_lines[pat][plane]);198 tpg->downsampled_lines[pat][plane] = NULL;199 }200 for (plane = 0; plane < TPG_MAX_PLANES; plane++) {201 vfree(tpg->contrast_line[plane]);202 vfree(tpg->black_line[plane]);203 vfree(tpg->random_line[plane]);204 tpg->contrast_line[plane] = NULL;205 tpg->black_line[plane] = NULL;206 tpg->random_line[plane] = NULL;207 }208}209EXPORT_SYMBOL_GPL(tpg_free);210 211bool tpg_s_fourcc(struct tpg_data *tpg, u32 fourcc)212{213 tpg->fourcc = fourcc;214 tpg->planes = 1;215 tpg->buffers = 1;216 tpg->recalc_colors = true;217 tpg->interleaved = false;218 tpg->vdownsampling[0] = 1;219 tpg->hdownsampling[0] = 1;220 tpg->hmask[0] = ~0;221 tpg->hmask[1] = ~0;222 tpg->hmask[2] = ~0;223 224 switch (fourcc) {225 case V4L2_PIX_FMT_SBGGR8:226 case V4L2_PIX_FMT_SGBRG8:227 case V4L2_PIX_FMT_SGRBG8:228 case V4L2_PIX_FMT_SRGGB8:229 case V4L2_PIX_FMT_SBGGR10:230 case V4L2_PIX_FMT_SGBRG10:231 case V4L2_PIX_FMT_SGRBG10:232 case V4L2_PIX_FMT_SRGGB10:233 case V4L2_PIX_FMT_SBGGR12:234 case V4L2_PIX_FMT_SGBRG12:235 case V4L2_PIX_FMT_SGRBG12:236 case V4L2_PIX_FMT_SRGGB12:237 case V4L2_PIX_FMT_SBGGR16:238 case V4L2_PIX_FMT_SGBRG16:239 case V4L2_PIX_FMT_SGRBG16:240 case V4L2_PIX_FMT_SRGGB16:241 tpg->interleaved = true;242 tpg->vdownsampling[1] = 1;243 tpg->hdownsampling[1] = 1;244 tpg->planes = 2;245 fallthrough;246 case V4L2_PIX_FMT_RGB332:247 case V4L2_PIX_FMT_RGB565:248 case V4L2_PIX_FMT_RGB565X:249 case V4L2_PIX_FMT_RGB444:250 case V4L2_PIX_FMT_XRGB444:251 case V4L2_PIX_FMT_ARGB444:252 case V4L2_PIX_FMT_RGBX444:253 case V4L2_PIX_FMT_RGBA444:254 case V4L2_PIX_FMT_XBGR444:255 case V4L2_PIX_FMT_ABGR444:256 case V4L2_PIX_FMT_BGRX444:257 case V4L2_PIX_FMT_BGRA444:258 case V4L2_PIX_FMT_RGB555:259 case V4L2_PIX_FMT_XRGB555:260 case V4L2_PIX_FMT_ARGB555:261 case V4L2_PIX_FMT_RGBX555:262 case V4L2_PIX_FMT_RGBA555:263 case V4L2_PIX_FMT_XBGR555:264 case V4L2_PIX_FMT_ABGR555:265 case V4L2_PIX_FMT_BGRX555:266 case V4L2_PIX_FMT_BGRA555:267 case V4L2_PIX_FMT_RGB555X:268 case V4L2_PIX_FMT_XRGB555X:269 case V4L2_PIX_FMT_ARGB555X:270 case V4L2_PIX_FMT_BGR666:271 case V4L2_PIX_FMT_RGB24:272 case V4L2_PIX_FMT_BGR24:273 case V4L2_PIX_FMT_RGB32:274 case V4L2_PIX_FMT_BGR32:275 case V4L2_PIX_FMT_XRGB32:276 case V4L2_PIX_FMT_XBGR32:277 case V4L2_PIX_FMT_ARGB32:278 case V4L2_PIX_FMT_ABGR32:279 case V4L2_PIX_FMT_RGBX32:280 case V4L2_PIX_FMT_BGRX32:281 case V4L2_PIX_FMT_RGBA32:282 case V4L2_PIX_FMT_BGRA32:283 tpg->color_enc = TGP_COLOR_ENC_RGB;284 break;285 case V4L2_PIX_FMT_GREY:286 case V4L2_PIX_FMT_Y10:287 case V4L2_PIX_FMT_Y12:288 case V4L2_PIX_FMT_Y16:289 case V4L2_PIX_FMT_Y16_BE:290 case V4L2_PIX_FMT_Z16:291 tpg->color_enc = TGP_COLOR_ENC_LUMA;292 break;293 case V4L2_PIX_FMT_YUV444:294 case V4L2_PIX_FMT_YUV555:295 case V4L2_PIX_FMT_YUV565:296 case V4L2_PIX_FMT_YUV32:297 case V4L2_PIX_FMT_AYUV32:298 case V4L2_PIX_FMT_XYUV32:299 case V4L2_PIX_FMT_VUYA32:300 case V4L2_PIX_FMT_VUYX32:301 case V4L2_PIX_FMT_YUVA32:302 case V4L2_PIX_FMT_YUVX32:303 tpg->color_enc = TGP_COLOR_ENC_YCBCR;304 break;305 case V4L2_PIX_FMT_YUV420M:306 case V4L2_PIX_FMT_YVU420M:307 tpg->buffers = 3;308 fallthrough;309 case V4L2_PIX_FMT_YUV420:310 case V4L2_PIX_FMT_YVU420:311 tpg->vdownsampling[1] = 2;312 tpg->vdownsampling[2] = 2;313 tpg->hdownsampling[1] = 2;314 tpg->hdownsampling[2] = 2;315 tpg->planes = 3;316 tpg->color_enc = TGP_COLOR_ENC_YCBCR;317 break;318 case V4L2_PIX_FMT_YUV422M:319 case V4L2_PIX_FMT_YVU422M:320 tpg->buffers = 3;321 fallthrough;322 case V4L2_PIX_FMT_YUV422P:323 tpg->vdownsampling[1] = 1;324 tpg->vdownsampling[2] = 1;325 tpg->hdownsampling[1] = 2;326 tpg->hdownsampling[2] = 2;327 tpg->planes = 3;328 tpg->color_enc = TGP_COLOR_ENC_YCBCR;329 break;330 case V4L2_PIX_FMT_NV16M:331 case V4L2_PIX_FMT_NV61M:332 tpg->buffers = 2;333 fallthrough;334 case V4L2_PIX_FMT_NV16:335 case V4L2_PIX_FMT_NV61:336 tpg->vdownsampling[1] = 1;337 tpg->hdownsampling[1] = 1;338 tpg->hmask[1] = ~1;339 tpg->planes = 2;340 tpg->color_enc = TGP_COLOR_ENC_YCBCR;341 break;342 case V4L2_PIX_FMT_NV12M:343 case V4L2_PIX_FMT_NV21M:344 tpg->buffers = 2;345 fallthrough;346 case V4L2_PIX_FMT_NV12:347 case V4L2_PIX_FMT_NV21:348 tpg->vdownsampling[1] = 2;349 tpg->hdownsampling[1] = 1;350 tpg->hmask[1] = ~1;351 tpg->planes = 2;352 tpg->color_enc = TGP_COLOR_ENC_YCBCR;353 break;354 case V4L2_PIX_FMT_YUV444M:355 case V4L2_PIX_FMT_YVU444M:356 tpg->buffers = 3;357 tpg->planes = 3;358 tpg->vdownsampling[1] = 1;359 tpg->vdownsampling[2] = 1;360 tpg->hdownsampling[1] = 1;361 tpg->hdownsampling[2] = 1;362 tpg->color_enc = TGP_COLOR_ENC_YCBCR;363 break;364 case V4L2_PIX_FMT_NV24:365 case V4L2_PIX_FMT_NV42:366 tpg->vdownsampling[1] = 1;367 tpg->hdownsampling[1] = 1;368 tpg->planes = 2;369 tpg->color_enc = TGP_COLOR_ENC_YCBCR;370 break;371 case V4L2_PIX_FMT_YUYV:372 case V4L2_PIX_FMT_UYVY:373 case V4L2_PIX_FMT_YVYU:374 case V4L2_PIX_FMT_VYUY:375 tpg->hmask[0] = ~1;376 tpg->color_enc = TGP_COLOR_ENC_YCBCR;377 break;378 case V4L2_PIX_FMT_HSV24:379 case V4L2_PIX_FMT_HSV32:380 tpg->color_enc = TGP_COLOR_ENC_HSV;381 break;382 default:383 return false;384 }385 386 switch (fourcc) {387 case V4L2_PIX_FMT_GREY:388 case V4L2_PIX_FMT_RGB332:389 tpg->twopixelsize[0] = 2;390 break;391 case V4L2_PIX_FMT_RGB565:392 case V4L2_PIX_FMT_RGB565X:393 case V4L2_PIX_FMT_RGB444:394 case V4L2_PIX_FMT_XRGB444:395 case V4L2_PIX_FMT_ARGB444:396 case V4L2_PIX_FMT_RGBX444:397 case V4L2_PIX_FMT_RGBA444:398 case V4L2_PIX_FMT_XBGR444:399 case V4L2_PIX_FMT_ABGR444:400 case V4L2_PIX_FMT_BGRX444:401 case V4L2_PIX_FMT_BGRA444:402 case V4L2_PIX_FMT_RGB555:403 case V4L2_PIX_FMT_XRGB555:404 case V4L2_PIX_FMT_ARGB555:405 case V4L2_PIX_FMT_RGBX555:406 case V4L2_PIX_FMT_RGBA555:407 case V4L2_PIX_FMT_XBGR555:408 case V4L2_PIX_FMT_ABGR555:409 case V4L2_PIX_FMT_BGRX555:410 case V4L2_PIX_FMT_BGRA555:411 case V4L2_PIX_FMT_RGB555X:412 case V4L2_PIX_FMT_XRGB555X:413 case V4L2_PIX_FMT_ARGB555X:414 case V4L2_PIX_FMT_YUYV:415 case V4L2_PIX_FMT_UYVY:416 case V4L2_PIX_FMT_YVYU:417 case V4L2_PIX_FMT_VYUY:418 case V4L2_PIX_FMT_YUV444:419 case V4L2_PIX_FMT_YUV555:420 case V4L2_PIX_FMT_YUV565:421 case V4L2_PIX_FMT_Y10:422 case V4L2_PIX_FMT_Y12:423 case V4L2_PIX_FMT_Y16:424 case V4L2_PIX_FMT_Y16_BE:425 case V4L2_PIX_FMT_Z16:426 tpg->twopixelsize[0] = 2 * 2;427 break;428 case V4L2_PIX_FMT_RGB24:429 case V4L2_PIX_FMT_BGR24:430 case V4L2_PIX_FMT_HSV24:431 tpg->twopixelsize[0] = 2 * 3;432 break;433 case V4L2_PIX_FMT_BGR666:434 case V4L2_PIX_FMT_RGB32:435 case V4L2_PIX_FMT_BGR32:436 case V4L2_PIX_FMT_XRGB32:437 case V4L2_PIX_FMT_XBGR32:438 case V4L2_PIX_FMT_ARGB32:439 case V4L2_PIX_FMT_ABGR32:440 case V4L2_PIX_FMT_RGBX32:441 case V4L2_PIX_FMT_BGRX32:442 case V4L2_PIX_FMT_RGBA32:443 case V4L2_PIX_FMT_BGRA32:444 case V4L2_PIX_FMT_YUV32:445 case V4L2_PIX_FMT_AYUV32:446 case V4L2_PIX_FMT_XYUV32:447 case V4L2_PIX_FMT_VUYA32:448 case V4L2_PIX_FMT_VUYX32:449 case V4L2_PIX_FMT_YUVA32:450 case V4L2_PIX_FMT_YUVX32:451 case V4L2_PIX_FMT_HSV32:452 tpg->twopixelsize[0] = 2 * 4;453 break;454 case V4L2_PIX_FMT_NV12:455 case V4L2_PIX_FMT_NV21:456 case V4L2_PIX_FMT_NV12M:457 case V4L2_PIX_FMT_NV21M:458 case V4L2_PIX_FMT_NV16:459 case V4L2_PIX_FMT_NV61:460 case V4L2_PIX_FMT_NV16M:461 case V4L2_PIX_FMT_NV61M:462 case V4L2_PIX_FMT_SBGGR8:463 case V4L2_PIX_FMT_SGBRG8:464 case V4L2_PIX_FMT_SGRBG8:465 case V4L2_PIX_FMT_SRGGB8:466 tpg->twopixelsize[0] = 2;467 tpg->twopixelsize[1] = 2;468 break;469 case V4L2_PIX_FMT_SRGGB10:470 case V4L2_PIX_FMT_SGRBG10:471 case V4L2_PIX_FMT_SGBRG10:472 case V4L2_PIX_FMT_SBGGR10:473 case V4L2_PIX_FMT_SRGGB12:474 case V4L2_PIX_FMT_SGRBG12:475 case V4L2_PIX_FMT_SGBRG12:476 case V4L2_PIX_FMT_SBGGR12:477 case V4L2_PIX_FMT_SRGGB16:478 case V4L2_PIX_FMT_SGRBG16:479 case V4L2_PIX_FMT_SGBRG16:480 case V4L2_PIX_FMT_SBGGR16:481 tpg->twopixelsize[0] = 4;482 tpg->twopixelsize[1] = 4;483 break;484 case V4L2_PIX_FMT_YUV444M:485 case V4L2_PIX_FMT_YVU444M:486 case V4L2_PIX_FMT_YUV422M:487 case V4L2_PIX_FMT_YVU422M:488 case V4L2_PIX_FMT_YUV422P:489 case V4L2_PIX_FMT_YUV420:490 case V4L2_PIX_FMT_YVU420:491 case V4L2_PIX_FMT_YUV420M:492 case V4L2_PIX_FMT_YVU420M:493 tpg->twopixelsize[0] = 2;494 tpg->twopixelsize[1] = 2;495 tpg->twopixelsize[2] = 2;496 break;497 case V4L2_PIX_FMT_NV24:498 case V4L2_PIX_FMT_NV42:499 tpg->twopixelsize[0] = 2;500 tpg->twopixelsize[1] = 4;501 break;502 }503 return true;504}505EXPORT_SYMBOL_GPL(tpg_s_fourcc);506 507void tpg_s_crop_compose(struct tpg_data *tpg, const struct v4l2_rect *crop,508 const struct v4l2_rect *compose)509{510 tpg->crop = *crop;511 tpg->compose = *compose;512 tpg->scaled_width = (tpg->src_width * tpg->compose.width +513 tpg->crop.width - 1) / tpg->crop.width;514 tpg->scaled_width &= ~1;515 if (tpg->scaled_width > tpg->max_line_width)516 tpg->scaled_width = tpg->max_line_width;517 if (tpg->scaled_width < 2)518 tpg->scaled_width = 2;519 tpg->recalc_lines = true;520}521EXPORT_SYMBOL_GPL(tpg_s_crop_compose);522 523void tpg_reset_source(struct tpg_data *tpg, unsigned width, unsigned height,524 u32 field)525{526 unsigned p;527 528 tpg->src_width = width;529 tpg->src_height = height;530 tpg->field = field;531 tpg->buf_height = height;532 if (V4L2_FIELD_HAS_T_OR_B(field))533 tpg->buf_height /= 2;534 tpg->scaled_width = width;535 tpg->crop.top = tpg->crop.left = 0;536 tpg->crop.width = width;537 tpg->crop.height = height;538 tpg->compose.top = tpg->compose.left = 0;539 tpg->compose.width = width;540 tpg->compose.height = tpg->buf_height;541 for (p = 0; p < tpg->planes; p++)542 tpg->bytesperline[p] = (width * tpg->twopixelsize[p]) /543 (2 * tpg->hdownsampling[p]);544 tpg->recalc_square_border = true;545}546EXPORT_SYMBOL_GPL(tpg_reset_source);547 548static enum tpg_color tpg_get_textbg_color(struct tpg_data *tpg)549{550 switch (tpg->pattern) {551 case TPG_PAT_BLACK:552 return TPG_COLOR_100_WHITE;553 case TPG_PAT_CSC_COLORBAR:554 return TPG_COLOR_CSC_BLACK;555 default:556 return TPG_COLOR_100_BLACK;557 }558}559 560static enum tpg_color tpg_get_textfg_color(struct tpg_data *tpg)561{562 switch (tpg->pattern) {563 case TPG_PAT_75_COLORBAR:564 case TPG_PAT_CSC_COLORBAR:565 return TPG_COLOR_CSC_WHITE;566 case TPG_PAT_BLACK:567 return TPG_COLOR_100_BLACK;568 default:569 return TPG_COLOR_100_WHITE;570 }571}572 573static inline int rec709_to_linear(int v)574{575 v = clamp(v, 0, 0xff0);576 return tpg_rec709_to_linear[v];577}578 579static inline int linear_to_rec709(int v)580{581 v = clamp(v, 0, 0xff0);582 return tpg_linear_to_rec709[v];583}584 585static void color_to_hsv(struct tpg_data *tpg, int r, int g, int b,586 int *h, int *s, int *v)587{588 int max_rgb, min_rgb, diff_rgb;589 int aux;590 int third;591 int third_size;592 593 r >>= 4;594 g >>= 4;595 b >>= 4;596 597 /* Value */598 max_rgb = max3(r, g, b);599 *v = max_rgb;600 if (!max_rgb) {601 *h = 0;602 *s = 0;603 return;604 }605 606 /* Saturation */607 min_rgb = min3(r, g, b);608 diff_rgb = max_rgb - min_rgb;609 aux = 255 * diff_rgb;610 aux += max_rgb / 2;611 aux /= max_rgb;612 *s = aux;613 if (!aux) {614 *h = 0;615 return;616 }617 618 third_size = (tpg->real_hsv_enc == V4L2_HSV_ENC_180) ? 60 : 85;619 620 /* Hue */621 if (max_rgb == r) {622 aux = g - b;623 third = 0;624 } else if (max_rgb == g) {625 aux = b - r;626 third = third_size;627 } else {628 aux = r - g;629 third = third_size * 2;630 }631 632 aux *= third_size / 2;633 aux += diff_rgb / 2;634 aux /= diff_rgb;635 aux += third;636 637 /* Clamp Hue */638 if (tpg->real_hsv_enc == V4L2_HSV_ENC_180) {639 if (aux < 0)640 aux += 180;641 else if (aux > 180)642 aux -= 180;643 } else {644 aux = aux & 0xff;645 }646 647 *h = aux;648}649 650static void rgb2ycbcr(const int m[3][3], int r, int g, int b,651 int y_offset, int *y, int *cb, int *cr)652{653 *y = ((m[0][0] * r + m[0][1] * g + m[0][2] * b) >> 16) + (y_offset << 4);654 *cb = ((m[1][0] * r + m[1][1] * g + m[1][2] * b) >> 16) + (128 << 4);655 *cr = ((m[2][0] * r + m[2][1] * g + m[2][2] * b) >> 16) + (128 << 4);656}657 658static void color_to_ycbcr(struct tpg_data *tpg, int r, int g, int b,659 int *y, int *cb, int *cr)660{661#define COEFF(v, r) ((int)(0.5 + (v) * (r) * 256.0))662 663 static const int bt601[3][3] = {664 { COEFF(0.299, 219), COEFF(0.587, 219), COEFF(0.114, 219) },665 { COEFF(-0.1687, 224), COEFF(-0.3313, 224), COEFF(0.5, 224) },666 { COEFF(0.5, 224), COEFF(-0.4187, 224), COEFF(-0.0813, 224) },667 };668 static const int bt601_full[3][3] = {669 { COEFF(0.299, 255), COEFF(0.587, 255), COEFF(0.114, 255) },670 { COEFF(-0.1687, 255), COEFF(-0.3313, 255), COEFF(0.5, 255) },671 { COEFF(0.5, 255), COEFF(-0.4187, 255), COEFF(-0.0813, 255) },672 };673 static const int rec709[3][3] = {674 { COEFF(0.2126, 219), COEFF(0.7152, 219), COEFF(0.0722, 219) },675 { COEFF(-0.1146, 224), COEFF(-0.3854, 224), COEFF(0.5, 224) },676 { COEFF(0.5, 224), COEFF(-0.4542, 224), COEFF(-0.0458, 224) },677 };678 static const int rec709_full[3][3] = {679 { COEFF(0.2126, 255), COEFF(0.7152, 255), COEFF(0.0722, 255) },680 { COEFF(-0.1146, 255), COEFF(-0.3854, 255), COEFF(0.5, 255) },681 { COEFF(0.5, 255), COEFF(-0.4542, 255), COEFF(-0.0458, 255) },682 };683 static const int smpte240m[3][3] = {684 { COEFF(0.212, 219), COEFF(0.701, 219), COEFF(0.087, 219) },685 { COEFF(-0.116, 224), COEFF(-0.384, 224), COEFF(0.5, 224) },686 { COEFF(0.5, 224), COEFF(-0.445, 224), COEFF(-0.055, 224) },687 };688 static const int smpte240m_full[3][3] = {689 { COEFF(0.212, 255), COEFF(0.701, 255), COEFF(0.087, 255) },690 { COEFF(-0.116, 255), COEFF(-0.384, 255), COEFF(0.5, 255) },691 { COEFF(0.5, 255), COEFF(-0.445, 255), COEFF(-0.055, 255) },692 };693 static const int bt2020[3][3] = {694 { COEFF(0.2627, 219), COEFF(0.6780, 219), COEFF(0.0593, 219) },695 { COEFF(-0.1396, 224), COEFF(-0.3604, 224), COEFF(0.5, 224) },696 { COEFF(0.5, 224), COEFF(-0.4598, 224), COEFF(-0.0402, 224) },697 };698 static const int bt2020_full[3][3] = {699 { COEFF(0.2627, 255), COEFF(0.6780, 255), COEFF(0.0593, 255) },700 { COEFF(-0.1396, 255), COEFF(-0.3604, 255), COEFF(0.5, 255) },701 { COEFF(0.5, 255), COEFF(-0.4598, 255), COEFF(-0.0402, 255) },702 };703 static const int bt2020c[4] = {704 COEFF(1.0 / 1.9404, 224), COEFF(1.0 / 1.5816, 224),705 COEFF(1.0 / 1.7184, 224), COEFF(1.0 / 0.9936, 224),706 };707 static const int bt2020c_full[4] = {708 COEFF(1.0 / 1.9404, 255), COEFF(1.0 / 1.5816, 255),709 COEFF(1.0 / 1.7184, 255), COEFF(1.0 / 0.9936, 255),710 };711 712 bool full = tpg->real_quantization == V4L2_QUANTIZATION_FULL_RANGE;713 unsigned y_offset = full ? 0 : 16;714 int lin_y, yc;715 716 switch (tpg->real_ycbcr_enc) {717 case V4L2_YCBCR_ENC_601:718 rgb2ycbcr(full ? bt601_full : bt601, r, g, b, y_offset, y, cb, cr);719 break;720 case V4L2_YCBCR_ENC_XV601:721 /* Ignore quantization range, there is only one possible722 * Y'CbCr encoding. */723 rgb2ycbcr(bt601, r, g, b, 16, y, cb, cr);724 break;725 case V4L2_YCBCR_ENC_XV709:726 /* Ignore quantization range, there is only one possible727 * Y'CbCr encoding. */728 rgb2ycbcr(rec709, r, g, b, 16, y, cb, cr);729 break;730 case V4L2_YCBCR_ENC_BT2020:731 rgb2ycbcr(full ? bt2020_full : bt2020, r, g, b, y_offset, y, cb, cr);732 break;733 case V4L2_YCBCR_ENC_BT2020_CONST_LUM:734 lin_y = (COEFF(0.2627, 255) * rec709_to_linear(r) +735 COEFF(0.6780, 255) * rec709_to_linear(g) +736 COEFF(0.0593, 255) * rec709_to_linear(b)) >> 16;737 yc = linear_to_rec709(lin_y);738 *y = full ? yc : (yc * 219) / 255 + (16 << 4);739 if (b <= yc)740 *cb = (((b - yc) * (full ? bt2020c_full[0] : bt2020c[0])) >> 16) + (128 << 4);741 else742 *cb = (((b - yc) * (full ? bt2020c_full[1] : bt2020c[1])) >> 16) + (128 << 4);743 if (r <= yc)744 *cr = (((r - yc) * (full ? bt2020c_full[2] : bt2020c[2])) >> 16) + (128 << 4);745 else746 *cr = (((r - yc) * (full ? bt2020c_full[3] : bt2020c[3])) >> 16) + (128 << 4);747 break;748 case V4L2_YCBCR_ENC_SMPTE240M:749 rgb2ycbcr(full ? smpte240m_full : smpte240m, r, g, b, y_offset, y, cb, cr);750 break;751 case V4L2_YCBCR_ENC_709:752 default:753 rgb2ycbcr(full ? rec709_full : rec709, r, g, b, y_offset, y, cb, cr);754 break;755 }756}757 758static void ycbcr2rgb(const int m[3][3], int y, int cb, int cr,759 int y_offset, int *r, int *g, int *b)760{761 y -= y_offset << 4;762 cb -= 128 << 4;763 cr -= 128 << 4;764 *r = m[0][0] * y + m[0][1] * cb + m[0][2] * cr;765 *g = m[1][0] * y + m[1][1] * cb + m[1][2] * cr;766 *b = m[2][0] * y + m[2][1] * cb + m[2][2] * cr;767 *r = clamp(*r >> 12, 0, 0xff0);768 *g = clamp(*g >> 12, 0, 0xff0);769 *b = clamp(*b >> 12, 0, 0xff0);770}771 772static void ycbcr_to_color(struct tpg_data *tpg, int y, int cb, int cr,773 int *r, int *g, int *b)774{775#undef COEFF776#define COEFF(v, r) ((int)(0.5 + (v) * ((255.0 * 255.0 * 16.0) / (r))))777 static const int bt601[3][3] = {778 { COEFF(1, 219), COEFF(0, 224), COEFF(1.4020, 224) },779 { COEFF(1, 219), COEFF(-0.3441, 224), COEFF(-0.7141, 224) },780 { COEFF(1, 219), COEFF(1.7720, 224), COEFF(0, 224) },781 };782 static const int bt601_full[3][3] = {783 { COEFF(1, 255), COEFF(0, 255), COEFF(1.4020, 255) },784 { COEFF(1, 255), COEFF(-0.3441, 255), COEFF(-0.7141, 255) },785 { COEFF(1, 255), COEFF(1.7720, 255), COEFF(0, 255) },786 };787 static const int rec709[3][3] = {788 { COEFF(1, 219), COEFF(0, 224), COEFF(1.5748, 224) },789 { COEFF(1, 219), COEFF(-0.1873, 224), COEFF(-0.4681, 224) },790 { COEFF(1, 219), COEFF(1.8556, 224), COEFF(0, 224) },791 };792 static const int rec709_full[3][3] = {793 { COEFF(1, 255), COEFF(0, 255), COEFF(1.5748, 255) },794 { COEFF(1, 255), COEFF(-0.1873, 255), COEFF(-0.4681, 255) },795 { COEFF(1, 255), COEFF(1.8556, 255), COEFF(0, 255) },796 };797 static const int smpte240m[3][3] = {798 { COEFF(1, 219), COEFF(0, 224), COEFF(1.5756, 224) },799 { COEFF(1, 219), COEFF(-0.2253, 224), COEFF(-0.4767, 224) },800 { COEFF(1, 219), COEFF(1.8270, 224), COEFF(0, 224) },801 };802 static const int smpte240m_full[3][3] = {803 { COEFF(1, 255), COEFF(0, 255), COEFF(1.5756, 255) },804 { COEFF(1, 255), COEFF(-0.2253, 255), COEFF(-0.4767, 255) },805 { COEFF(1, 255), COEFF(1.8270, 255), COEFF(0, 255) },806 };807 static const int bt2020[3][3] = {808 { COEFF(1, 219), COEFF(0, 224), COEFF(1.4746, 224) },809 { COEFF(1, 219), COEFF(-0.1646, 224), COEFF(-0.5714, 224) },810 { COEFF(1, 219), COEFF(1.8814, 224), COEFF(0, 224) },811 };812 static const int bt2020_full[3][3] = {813 { COEFF(1, 255), COEFF(0, 255), COEFF(1.4746, 255) },814 { COEFF(1, 255), COEFF(-0.1646, 255), COEFF(-0.5714, 255) },815 { COEFF(1, 255), COEFF(1.8814, 255), COEFF(0, 255) },816 };817 static const int bt2020c[4] = {818 COEFF(1.9404, 224), COEFF(1.5816, 224),819 COEFF(1.7184, 224), COEFF(0.9936, 224),820 };821 static const int bt2020c_full[4] = {822 COEFF(1.9404, 255), COEFF(1.5816, 255),823 COEFF(1.7184, 255), COEFF(0.9936, 255),824 };825 826 bool full = tpg->real_quantization == V4L2_QUANTIZATION_FULL_RANGE;827 unsigned y_offset = full ? 0 : 16;828 int y_fac = full ? COEFF(1.0, 255) : COEFF(1.0, 219);829 int lin_r, lin_g, lin_b, lin_y;830 831 switch (tpg->real_ycbcr_enc) {832 case V4L2_YCBCR_ENC_601:833 ycbcr2rgb(full ? bt601_full : bt601, y, cb, cr, y_offset, r, g, b);834 break;835 case V4L2_YCBCR_ENC_XV601:836 /* Ignore quantization range, there is only one possible837 * Y'CbCr encoding. */838 ycbcr2rgb(bt601, y, cb, cr, 16, r, g, b);839 break;840 case V4L2_YCBCR_ENC_XV709:841 /* Ignore quantization range, there is only one possible842 * Y'CbCr encoding. */843 ycbcr2rgb(rec709, y, cb, cr, 16, r, g, b);844 break;845 case V4L2_YCBCR_ENC_BT2020:846 ycbcr2rgb(full ? bt2020_full : bt2020, y, cb, cr, y_offset, r, g, b);847 break;848 case V4L2_YCBCR_ENC_BT2020_CONST_LUM:849 y -= full ? 0 : 16 << 4;850 cb -= 128 << 4;851 cr -= 128 << 4;852 853 if (cb <= 0)854 *b = y_fac * y + (full ? bt2020c_full[0] : bt2020c[0]) * cb;855 else856 *b = y_fac * y + (full ? bt2020c_full[1] : bt2020c[1]) * cb;857 *b = *b >> 12;858 if (cr <= 0)859 *r = y_fac * y + (full ? bt2020c_full[2] : bt2020c[2]) * cr;860 else861 *r = y_fac * y + (full ? bt2020c_full[3] : bt2020c[3]) * cr;862 *r = *r >> 12;863 lin_r = rec709_to_linear(*r);864 lin_b = rec709_to_linear(*b);865 lin_y = rec709_to_linear((y * 255) / (full ? 255 : 219));866 867 lin_g = COEFF(1.0 / 0.6780, 255) * lin_y -868 COEFF(0.2627 / 0.6780, 255) * lin_r -869 COEFF(0.0593 / 0.6780, 255) * lin_b;870 *g = linear_to_rec709(lin_g >> 12);871 break;872 case V4L2_YCBCR_ENC_SMPTE240M:873 ycbcr2rgb(full ? smpte240m_full : smpte240m, y, cb, cr, y_offset, r, g, b);874 break;875 case V4L2_YCBCR_ENC_709:876 default:877 ycbcr2rgb(full ? rec709_full : rec709, y, cb, cr, y_offset, r, g, b);878 break;879 }880}881 882/* precalculate color bar values to speed up rendering */883static void precalculate_color(struct tpg_data *tpg, int k)884{885 int col = k;886 int r = tpg_colors[col].r;887 int g = tpg_colors[col].g;888 int b = tpg_colors[col].b;889 int y, cb, cr;890 bool ycbcr_valid = false;891 892 if (k == TPG_COLOR_TEXTBG) {893 col = tpg_get_textbg_color(tpg);894 895 r = tpg_colors[col].r;896 g = tpg_colors[col].g;897 b = tpg_colors[col].b;898 } else if (k == TPG_COLOR_TEXTFG) {899 col = tpg_get_textfg_color(tpg);900 901 r = tpg_colors[col].r;902 g = tpg_colors[col].g;903 b = tpg_colors[col].b;904 } else if (tpg->pattern == TPG_PAT_NOISE) {905 r = g = b = get_random_u8();906 } else if (k == TPG_COLOR_RANDOM) {907 r = g = b = tpg->qual_offset + get_random_u32_below(196);908 } else if (k >= TPG_COLOR_RAMP) {909 r = g = b = k - TPG_COLOR_RAMP;910 }911 912 if (tpg->pattern == TPG_PAT_CSC_COLORBAR && col <= TPG_COLOR_CSC_BLACK) {913 r = tpg_csc_colors[tpg->colorspace][tpg->real_xfer_func][col].r;914 g = tpg_csc_colors[tpg->colorspace][tpg->real_xfer_func][col].g;915 b = tpg_csc_colors[tpg->colorspace][tpg->real_xfer_func][col].b;916 } else {917 r <<= 4;918 g <<= 4;919 b <<= 4;920 }921 922 if (tpg->qual == TPG_QUAL_GRAY ||923 tpg->color_enc == TGP_COLOR_ENC_LUMA) {924 /* Rec. 709 Luma function */925 /* (0.2126, 0.7152, 0.0722) * (255 * 256) */926 r = g = b = (13879 * r + 46688 * g + 4713 * b) >> 16;927 }928 929 /*930 * The assumption is that the RGB output is always full range,931 * so only if the rgb_range overrides the 'real' rgb range do932 * we need to convert the RGB values.933 *934 * Remember that r, g and b are still in the 0 - 0xff0 range.935 */936 if (tpg->real_rgb_range == V4L2_DV_RGB_RANGE_LIMITED &&937 tpg->rgb_range == V4L2_DV_RGB_RANGE_FULL &&938 tpg->color_enc == TGP_COLOR_ENC_RGB) {939 /*940 * Convert from full range (which is what r, g and b are)941 * to limited range (which is the 'real' RGB range), which942 * is then interpreted as full range.943 */944 r = (r * 219) / 255 + (16 << 4);945 g = (g * 219) / 255 + (16 << 4);946 b = (b * 219) / 255 + (16 << 4);947 } else if (tpg->real_rgb_range != V4L2_DV_RGB_RANGE_LIMITED &&948 tpg->rgb_range == V4L2_DV_RGB_RANGE_LIMITED &&949 tpg->color_enc == TGP_COLOR_ENC_RGB) {950 951 /*952 * Clamp r, g and b to the limited range and convert to full953 * range since that's what we deliver.954 */955 r = clamp(r, 16 << 4, 235 << 4);956 g = clamp(g, 16 << 4, 235 << 4);957 b = clamp(b, 16 << 4, 235 << 4);958 r = (r - (16 << 4)) * 255 / 219;959 g = (g - (16 << 4)) * 255 / 219;960 b = (b - (16 << 4)) * 255 / 219;961 }962 963 if ((tpg->brightness != 128 || tpg->contrast != 128 ||964 tpg->saturation != 128 || tpg->hue) &&965 tpg->color_enc != TGP_COLOR_ENC_LUMA) {966 /* Implement these operations */967 int tmp_cb, tmp_cr;968 969 /* First convert to YCbCr */970 971 color_to_ycbcr(tpg, r, g, b, &y, &cb, &cr);972 973 y = (16 << 4) + ((y - (16 << 4)) * tpg->contrast) / 128;974 y += (tpg->brightness << 4) - (128 << 4);975 976 cb -= 128 << 4;977 cr -= 128 << 4;978 tmp_cb = (cb * cos(128 + tpg->hue)) / 127 + (cr * sin[128 + tpg->hue]) / 127;979 tmp_cr = (cr * cos(128 + tpg->hue)) / 127 - (cb * sin[128 + tpg->hue]) / 127;980 981 cb = (128 << 4) + (tmp_cb * tpg->contrast * tpg->saturation) / (128 * 128);982 cr = (128 << 4) + (tmp_cr * tpg->contrast * tpg->saturation) / (128 * 128);983 if (tpg->color_enc == TGP_COLOR_ENC_YCBCR)984 ycbcr_valid = true;985 else986 ycbcr_to_color(tpg, y, cb, cr, &r, &g, &b);987 } else if ((tpg->brightness != 128 || tpg->contrast != 128) &&988 tpg->color_enc == TGP_COLOR_ENC_LUMA) {989 r = (16 << 4) + ((r - (16 << 4)) * tpg->contrast) / 128;990 r += (tpg->brightness << 4) - (128 << 4);991 }992 993 switch (tpg->color_enc) {994 case TGP_COLOR_ENC_HSV:995 {996 int h, s, v;997 998 color_to_hsv(tpg, r, g, b, &h, &s, &v);999 tpg->colors[k][0] = h;1000 tpg->colors[k][1] = s;1001 tpg->colors[k][2] = v;1002 break;1003 }1004 case TGP_COLOR_ENC_YCBCR:1005 {1006 /* Convert to YCbCr */1007 if (!ycbcr_valid)1008 color_to_ycbcr(tpg, r, g, b, &y, &cb, &cr);1009 1010 y >>= 4;1011 cb >>= 4;1012 cr >>= 4;1013 /*1014 * XV601/709 use the header/footer margins to encode R', G'1015 * and B' values outside the range [0-1]. So do not clamp1016 * XV601/709 values.1017 */1018 if (tpg->real_quantization == V4L2_QUANTIZATION_LIM_RANGE &&1019 tpg->real_ycbcr_enc != V4L2_YCBCR_ENC_XV601 &&1020 tpg->real_ycbcr_enc != V4L2_YCBCR_ENC_XV709) {1021 y = clamp(y, 16, 235);1022 cb = clamp(cb, 16, 240);1023 cr = clamp(cr, 16, 240);1024 } else {1025 y = clamp(y, 1, 254);1026 cb = clamp(cb, 1, 254);1027 cr = clamp(cr, 1, 254);1028 }1029 switch (tpg->fourcc) {1030 case V4L2_PIX_FMT_YUV444:1031 y >>= 4;1032 cb >>= 4;1033 cr >>= 4;1034 break;1035 case V4L2_PIX_FMT_YUV555:1036 y >>= 3;1037 cb >>= 3;1038 cr >>= 3;1039 break;1040 case V4L2_PIX_FMT_YUV565:1041 y >>= 3;1042 cb >>= 2;1043 cr >>= 3;1044 break;1045 }1046 tpg->colors[k][0] = y;1047 tpg->colors[k][1] = cb;1048 tpg->colors[k][2] = cr;1049 break;1050 }1051 case TGP_COLOR_ENC_LUMA:1052 {1053 tpg->colors[k][0] = r >> 4;1054 break;1055 }1056 case TGP_COLOR_ENC_RGB:1057 {1058 if (tpg->real_quantization == V4L2_QUANTIZATION_LIM_RANGE) {1059 r = (r * 219) / 255 + (16 << 4);1060 g = (g * 219) / 255 + (16 << 4);1061 b = (b * 219) / 255 + (16 << 4);1062 }1063 switch (tpg->fourcc) {1064 case V4L2_PIX_FMT_RGB332:1065 r >>= 9;1066 g >>= 9;1067 b >>= 10;1068 break;1069 case V4L2_PIX_FMT_RGB565:1070 case V4L2_PIX_FMT_RGB565X:1071 r >>= 7;1072 g >>= 6;1073 b >>= 7;1074 break;1075 case V4L2_PIX_FMT_RGB444:1076 case V4L2_PIX_FMT_XRGB444:1077 case V4L2_PIX_FMT_ARGB444:1078 case V4L2_PIX_FMT_RGBX444:1079 case V4L2_PIX_FMT_RGBA444:1080 case V4L2_PIX_FMT_XBGR444:1081 case V4L2_PIX_FMT_ABGR444:1082 case V4L2_PIX_FMT_BGRX444:1083 case V4L2_PIX_FMT_BGRA444:1084 r >>= 8;1085 g >>= 8;1086 b >>= 8;1087 break;1088 case V4L2_PIX_FMT_RGB555:1089 case V4L2_PIX_FMT_XRGB555:1090 case V4L2_PIX_FMT_ARGB555:1091 case V4L2_PIX_FMT_RGBX555:1092 case V4L2_PIX_FMT_RGBA555:1093 case V4L2_PIX_FMT_XBGR555:1094 case V4L2_PIX_FMT_ABGR555:1095 case V4L2_PIX_FMT_BGRX555:1096 case V4L2_PIX_FMT_BGRA555:1097 case V4L2_PIX_FMT_RGB555X:1098 case V4L2_PIX_FMT_XRGB555X:1099 case V4L2_PIX_FMT_ARGB555X:1100 r >>= 7;1101 g >>= 7;1102 b >>= 7;1103 break;1104 case V4L2_PIX_FMT_BGR666:1105 r >>= 6;1106 g >>= 6;1107 b >>= 6;1108 break;1109 default:1110 r >>= 4;1111 g >>= 4;1112 b >>= 4;1113 break;1114 }1115 1116 tpg->colors[k][0] = r;1117 tpg->colors[k][1] = g;1118 tpg->colors[k][2] = b;1119 break;1120 }1121 }1122}1123 1124static void tpg_precalculate_colors(struct tpg_data *tpg)1125{1126 int k;1127 1128 for (k = 0; k < TPG_COLOR_MAX; k++)1129 precalculate_color(tpg, k);1130}1131 1132/* 'odd' is true for pixels 1, 3, 5, etc. and false for pixels 0, 2, 4, etc. */1133static void gen_twopix(struct tpg_data *tpg,1134 u8 buf[TPG_MAX_PLANES][8], int color, bool odd)1135{1136 unsigned offset = odd * tpg->twopixelsize[0] / 2;1137 u8 alpha = tpg->alpha_component;1138 u8 r_y_h, g_u_s, b_v;1139 1140 if (tpg->alpha_red_only && color != TPG_COLOR_CSC_RED &&1141 color != TPG_COLOR_100_RED &&1142 color != TPG_COLOR_75_RED)1143 alpha = 0;1144 if (color == TPG_COLOR_RANDOM)1145 precalculate_color(tpg, color);1146 r_y_h = tpg->colors[color][0]; /* R or precalculated Y, H */1147 g_u_s = tpg->colors[color][1]; /* G or precalculated U, V */1148 b_v = tpg->colors[color][2]; /* B or precalculated V */1149 1150 switch (tpg->fourcc) {1151 case V4L2_PIX_FMT_GREY:1152 buf[0][offset] = r_y_h;1153 break;1154 case V4L2_PIX_FMT_Y10:1155 buf[0][offset] = (r_y_h << 2) & 0xff;1156 buf[0][offset+1] = r_y_h >> 6;1157 break;1158 case V4L2_PIX_FMT_Y12:1159 buf[0][offset] = (r_y_h << 4) & 0xff;1160 buf[0][offset+1] = r_y_h >> 4;1161 break;1162 case V4L2_PIX_FMT_Y16:1163 case V4L2_PIX_FMT_Z16:1164 /*1165 * Ideally both bytes should be set to r_y_h, but then you won't1166 * be able to detect endian problems. So keep it 0 except for1167 * the corner case where r_y_h is 0xff so white really will be1168 * white (0xffff).1169 */1170 buf[0][offset] = r_y_h == 0xff ? r_y_h : 0;1171 buf[0][offset+1] = r_y_h;1172 break;1173 case V4L2_PIX_FMT_Y16_BE:1174 /* See comment for V4L2_PIX_FMT_Y16 above */1175 buf[0][offset] = r_y_h;1176 buf[0][offset+1] = r_y_h == 0xff ? r_y_h : 0;1177 break;1178 case V4L2_PIX_FMT_YUV422M:1179 case V4L2_PIX_FMT_YUV422P:1180 case V4L2_PIX_FMT_YUV420:1181 case V4L2_PIX_FMT_YUV420M:1182 buf[0][offset] = r_y_h;1183 if (odd) {1184 buf[1][0] = (buf[1][0] + g_u_s) / 2;1185 buf[2][0] = (buf[2][0] + b_v) / 2;1186 buf[1][1] = buf[1][0];1187 buf[2][1] = buf[2][0];1188 break;1189 }1190 buf[1][0] = g_u_s;1191 buf[2][0] = b_v;1192 break;1193 case V4L2_PIX_FMT_YVU422M:1194 case V4L2_PIX_FMT_YVU420:1195 case V4L2_PIX_FMT_YVU420M:1196 buf[0][offset] = r_y_h;1197 if (odd) {1198 buf[1][0] = (buf[1][0] + b_v) / 2;1199 buf[2][0] = (buf[2][0] + g_u_s) / 2;1200 buf[1][1] = buf[1][0];1201 buf[2][1] = buf[2][0];1202 break;1203 }1204 buf[1][0] = b_v;1205 buf[2][0] = g_u_s;1206 break;1207 1208 case V4L2_PIX_FMT_NV12:1209 case V4L2_PIX_FMT_NV12M:1210 case V4L2_PIX_FMT_NV16:1211 case V4L2_PIX_FMT_NV16M:1212 buf[0][offset] = r_y_h;1213 if (odd) {1214 buf[1][0] = (buf[1][0] + g_u_s) / 2;1215 buf[1][1] = (buf[1][1] + b_v) / 2;1216 break;1217 }1218 buf[1][0] = g_u_s;1219 buf[1][1] = b_v;1220 break;1221 case V4L2_PIX_FMT_NV21:1222 case V4L2_PIX_FMT_NV21M:1223 case V4L2_PIX_FMT_NV61:1224 case V4L2_PIX_FMT_NV61M:1225 buf[0][offset] = r_y_h;1226 if (odd) {1227 buf[1][0] = (buf[1][0] + b_v) / 2;1228 buf[1][1] = (buf[1][1] + g_u_s) / 2;1229 break;1230 }1231 buf[1][0] = b_v;1232 buf[1][1] = g_u_s;1233 break;1234 1235 case V4L2_PIX_FMT_YUV444M:1236 buf[0][offset] = r_y_h;1237 buf[1][offset] = g_u_s;1238 buf[2][offset] = b_v;1239 break;1240 1241 case V4L2_PIX_FMT_YVU444M:1242 buf[0][offset] = r_y_h;1243 buf[1][offset] = b_v;1244 buf[2][offset] = g_u_s;1245 break;1246 1247 case V4L2_PIX_FMT_NV24:1248 buf[0][offset] = r_y_h;1249 buf[1][2 * offset] = g_u_s;1250 buf[1][(2 * offset + 1) % 8] = b_v;1251 break;1252 1253 case V4L2_PIX_FMT_NV42:1254 buf[0][offset] = r_y_h;1255 buf[1][2 * offset] = b_v;1256 buf[1][(2 * offset + 1) % 8] = g_u_s;1257 break;1258 1259 case V4L2_PIX_FMT_YUYV:1260 buf[0][offset] = r_y_h;1261 if (odd) {1262 buf[0][1] = (buf[0][1] + g_u_s) / 2;1263 buf[0][3] = (buf[0][3] + b_v) / 2;1264 break;1265 }1266 buf[0][1] = g_u_s;1267 buf[0][3] = b_v;1268 break;1269 case V4L2_PIX_FMT_UYVY:1270 buf[0][offset + 1] = r_y_h;1271 if (odd) {1272 buf[0][0] = (buf[0][0] + g_u_s) / 2;1273 buf[0][2] = (buf[0][2] + b_v) / 2;1274 break;1275 }1276 buf[0][0] = g_u_s;1277 buf[0][2] = b_v;1278 break;1279 case V4L2_PIX_FMT_YVYU:1280 buf[0][offset] = r_y_h;1281 if (odd) {1282 buf[0][1] = (buf[0][1] + b_v) / 2;1283 buf[0][3] = (buf[0][3] + g_u_s) / 2;1284 break;1285 }1286 buf[0][1] = b_v;1287 buf[0][3] = g_u_s;1288 break;1289 case V4L2_PIX_FMT_VYUY:1290 buf[0][offset + 1] = r_y_h;1291 if (odd) {1292 buf[0][0] = (buf[0][0] + b_v) / 2;1293 buf[0][2] = (buf[0][2] + g_u_s) / 2;1294 break;1295 }1296 buf[0][0] = b_v;1297 buf[0][2] = g_u_s;1298 break;1299 case V4L2_PIX_FMT_RGB332:1300 buf[0][offset] = (r_y_h << 5) | (g_u_s << 2) | b_v;1301 break;1302 case V4L2_PIX_FMT_YUV565:1303 case V4L2_PIX_FMT_RGB565:1304 buf[0][offset] = (g_u_s << 5) | b_v;1305 buf[0][offset + 1] = (r_y_h << 3) | (g_u_s >> 3);1306 break;1307 case V4L2_PIX_FMT_RGB565X:1308 buf[0][offset] = (r_y_h << 3) | (g_u_s >> 3);1309 buf[0][offset + 1] = (g_u_s << 5) | b_v;1310 break;1311 case V4L2_PIX_FMT_RGB444:1312 case V4L2_PIX_FMT_XRGB444:1313 alpha = 0;1314 fallthrough;1315 case V4L2_PIX_FMT_YUV444:1316 case V4L2_PIX_FMT_ARGB444:1317 buf[0][offset] = (g_u_s << 4) | b_v;1318 buf[0][offset + 1] = (alpha & 0xf0) | r_y_h;1319 break;1320 case V4L2_PIX_FMT_RGBX444:1321 alpha = 0;1322 fallthrough;1323 case V4L2_PIX_FMT_RGBA444:1324 buf[0][offset] = (b_v << 4) | (alpha >> 4);1325 buf[0][offset + 1] = (r_y_h << 4) | g_u_s;1326 break;1327 case V4L2_PIX_FMT_XBGR444:1328 alpha = 0;1329 fallthrough;1330 case V4L2_PIX_FMT_ABGR444:1331 buf[0][offset] = (g_u_s << 4) | r_y_h;1332 buf[0][offset + 1] = (alpha & 0xf0) | b_v;1333 break;1334 case V4L2_PIX_FMT_BGRX444:1335 alpha = 0;1336 fallthrough;1337 case V4L2_PIX_FMT_BGRA444:1338 buf[0][offset] = (r_y_h << 4) | (alpha >> 4);1339 buf[0][offset + 1] = (b_v << 4) | g_u_s;1340 break;1341 case V4L2_PIX_FMT_RGB555:1342 case V4L2_PIX_FMT_XRGB555:1343 alpha = 0;1344 fallthrough;1345 case V4L2_PIX_FMT_YUV555:1346 case V4L2_PIX_FMT_ARGB555:1347 buf[0][offset] = (g_u_s << 5) | b_v;1348 buf[0][offset + 1] = (alpha & 0x80) | (r_y_h << 2)1349 | (g_u_s >> 3);1350 break;1351 case V4L2_PIX_FMT_RGBX555:1352 alpha = 0;1353 fallthrough;1354 case V4L2_PIX_FMT_RGBA555:1355 buf[0][offset] = (g_u_s << 6) | (b_v << 1) |1356 ((alpha & 0x80) >> 7);1357 buf[0][offset + 1] = (r_y_h << 3) | (g_u_s >> 2);1358 break;1359 case V4L2_PIX_FMT_XBGR555:1360 alpha = 0;1361 fallthrough;1362 case V4L2_PIX_FMT_ABGR555:1363 buf[0][offset] = (g_u_s << 5) | r_y_h;1364 buf[0][offset + 1] = (alpha & 0x80) | (b_v << 2)1365 | (g_u_s >> 3);1366 break;1367 case V4L2_PIX_FMT_BGRX555:1368 alpha = 0;1369 fallthrough;1370 case V4L2_PIX_FMT_BGRA555:1371 buf[0][offset] = (g_u_s << 6) | (r_y_h << 1) |1372 ((alpha & 0x80) >> 7);1373 buf[0][offset + 1] = (b_v << 3) | (g_u_s >> 2);1374 break;1375 case V4L2_PIX_FMT_RGB555X:1376 case V4L2_PIX_FMT_XRGB555X:1377 alpha = 0;1378 fallthrough;1379 case V4L2_PIX_FMT_ARGB555X:1380 buf[0][offset] = (alpha & 0x80) | (r_y_h << 2) | (g_u_s >> 3);1381 buf[0][offset + 1] = (g_u_s << 5) | b_v;1382 break;1383 case V4L2_PIX_FMT_RGB24:1384 case V4L2_PIX_FMT_HSV24:1385 buf[0][offset] = r_y_h;1386 buf[0][offset + 1] = g_u_s;1387 buf[0][offset + 2] = b_v;1388 break;1389 case V4L2_PIX_FMT_BGR24:1390 buf[0][offset] = b_v;1391 buf[0][offset + 1] = g_u_s;1392 buf[0][offset + 2] = r_y_h;1393 break;1394 case V4L2_PIX_FMT_BGR666:1395 buf[0][offset] = (b_v << 2) | (g_u_s >> 4);1396 buf[0][offset + 1] = (g_u_s << 4) | (r_y_h >> 2);1397 buf[0][offset + 2] = r_y_h << 6;1398 buf[0][offset + 3] = 0;1399 break;1400 case V4L2_PIX_FMT_RGB32:1401 case V4L2_PIX_FMT_XRGB32:1402 case V4L2_PIX_FMT_HSV32:1403 case V4L2_PIX_FMT_XYUV32:1404 alpha = 0;1405 fallthrough;1406 case V4L2_PIX_FMT_YUV32:1407 case V4L2_PIX_FMT_ARGB32:1408 case V4L2_PIX_FMT_AYUV32:1409 buf[0][offset] = alpha;1410 buf[0][offset + 1] = r_y_h;1411 buf[0][offset + 2] = g_u_s;1412 buf[0][offset + 3] = b_v;1413 break;1414 case V4L2_PIX_FMT_RGBX32:1415 case V4L2_PIX_FMT_YUVX32:1416 alpha = 0;1417 fallthrough;1418 case V4L2_PIX_FMT_RGBA32:1419 case V4L2_PIX_FMT_YUVA32:1420 buf[0][offset] = r_y_h;1421 buf[0][offset + 1] = g_u_s;1422 buf[0][offset + 2] = b_v;1423 buf[0][offset + 3] = alpha;1424 break;1425 case V4L2_PIX_FMT_BGR32:1426 case V4L2_PIX_FMT_XBGR32:1427 case V4L2_PIX_FMT_VUYX32:1428 alpha = 0;1429 fallthrough;1430 case V4L2_PIX_FMT_ABGR32:1431 case V4L2_PIX_FMT_VUYA32:1432 buf[0][offset] = b_v;1433 buf[0][offset + 1] = g_u_s;1434 buf[0][offset + 2] = r_y_h;1435 buf[0][offset + 3] = alpha;1436 break;1437 case V4L2_PIX_FMT_BGRX32:1438 alpha = 0;1439 fallthrough;1440 case V4L2_PIX_FMT_BGRA32:1441 buf[0][offset] = alpha;1442 buf[0][offset + 1] = b_v;1443 buf[0][offset + 2] = g_u_s;1444 buf[0][offset + 3] = r_y_h;1445 break;1446 case V4L2_PIX_FMT_SBGGR8:1447 buf[0][offset] = odd ? g_u_s : b_v;1448 buf[1][offset] = odd ? r_y_h : g_u_s;1449 break;1450 case V4L2_PIX_FMT_SGBRG8:1451 buf[0][offset] = odd ? b_v : g_u_s;1452 buf[1][offset] = odd ? g_u_s : r_y_h;1453 break;1454 case V4L2_PIX_FMT_SGRBG8:1455 buf[0][offset] = odd ? r_y_h : g_u_s;1456 buf[1][offset] = odd ? g_u_s : b_v;1457 break;1458 case V4L2_PIX_FMT_SRGGB8:1459 buf[0][offset] = odd ? g_u_s : r_y_h;1460 buf[1][offset] = odd ? b_v : g_u_s;1461 break;1462 case V4L2_PIX_FMT_SBGGR10:1463 buf[0][offset] = odd ? g_u_s << 2 : b_v << 2;1464 buf[0][offset + 1] = odd ? g_u_s >> 6 : b_v >> 6;1465 buf[1][offset] = odd ? r_y_h << 2 : g_u_s << 2;1466 buf[1][offset + 1] = odd ? r_y_h >> 6 : g_u_s >> 6;1467 buf[0][offset] |= (buf[0][offset] >> 2) & 3;1468 buf[1][offset] |= (buf[1][offset] >> 2) & 3;1469 break;1470 case V4L2_PIX_FMT_SGBRG10:1471 buf[0][offset] = odd ? b_v << 2 : g_u_s << 2;1472 buf[0][offset + 1] = odd ? b_v >> 6 : g_u_s >> 6;1473 buf[1][offset] = odd ? g_u_s << 2 : r_y_h << 2;1474 buf[1][offset + 1] = odd ? g_u_s >> 6 : r_y_h >> 6;1475 buf[0][offset] |= (buf[0][offset] >> 2) & 3;1476 buf[1][offset] |= (buf[1][offset] >> 2) & 3;1477 break;1478 case V4L2_PIX_FMT_SGRBG10:1479 buf[0][offset] = odd ? r_y_h << 2 : g_u_s << 2;1480 buf[0][offset + 1] = odd ? r_y_h >> 6 : g_u_s >> 6;1481 buf[1][offset] = odd ? g_u_s << 2 : b_v << 2;1482 buf[1][offset + 1] = odd ? g_u_s >> 6 : b_v >> 6;1483 buf[0][offset] |= (buf[0][offset] >> 2) & 3;1484 buf[1][offset] |= (buf[1][offset] >> 2) & 3;1485 break;1486 case V4L2_PIX_FMT_SRGGB10:1487 buf[0][offset] = odd ? g_u_s << 2 : r_y_h << 2;1488 buf[0][offset + 1] = odd ? g_u_s >> 6 : r_y_h >> 6;1489 buf[1][offset] = odd ? b_v << 2 : g_u_s << 2;1490 buf[1][offset + 1] = odd ? b_v >> 6 : g_u_s >> 6;1491 buf[0][offset] |= (buf[0][offset] >> 2) & 3;1492 buf[1][offset] |= (buf[1][offset] >> 2) & 3;1493 break;1494 case V4L2_PIX_FMT_SBGGR12:1495 buf[0][offset] = odd ? g_u_s << 4 : b_v << 4;1496 buf[0][offset + 1] = odd ? g_u_s >> 4 : b_v >> 4;1497 buf[1][offset] = odd ? r_y_h << 4 : g_u_s << 4;1498 buf[1][offset + 1] = odd ? r_y_h >> 4 : g_u_s >> 4;1499 buf[0][offset] |= (buf[0][offset] >> 4) & 0xf;1500 buf[1][offset] |= (buf[1][offset] >> 4) & 0xf;1501 break;1502 case V4L2_PIX_FMT_SGBRG12:1503 buf[0][offset] = odd ? b_v << 4 : g_u_s << 4;1504 buf[0][offset + 1] = odd ? b_v >> 4 : g_u_s >> 4;1505 buf[1][offset] = odd ? g_u_s << 4 : r_y_h << 4;1506 buf[1][offset + 1] = odd ? g_u_s >> 4 : r_y_h >> 4;1507 buf[0][offset] |= (buf[0][offset] >> 4) & 0xf;1508 buf[1][offset] |= (buf[1][offset] >> 4) & 0xf;1509 break;1510 case V4L2_PIX_FMT_SGRBG12:1511 buf[0][offset] = odd ? r_y_h << 4 : g_u_s << 4;1512 buf[0][offset + 1] = odd ? r_y_h >> 4 : g_u_s >> 4;1513 buf[1][offset] = odd ? g_u_s << 4 : b_v << 4;1514 buf[1][offset + 1] = odd ? g_u_s >> 4 : b_v >> 4;1515 buf[0][offset] |= (buf[0][offset] >> 4) & 0xf;1516 buf[1][offset] |= (buf[1][offset] >> 4) & 0xf;1517 break;1518 case V4L2_PIX_FMT_SRGGB12:1519 buf[0][offset] = odd ? g_u_s << 4 : r_y_h << 4;1520 buf[0][offset + 1] = odd ? g_u_s >> 4 : r_y_h >> 4;1521 buf[1][offset] = odd ? b_v << 4 : g_u_s << 4;1522 buf[1][offset + 1] = odd ? b_v >> 4 : g_u_s >> 4;1523 buf[0][offset] |= (buf[0][offset] >> 4) & 0xf;1524 buf[1][offset] |= (buf[1][offset] >> 4) & 0xf;1525 break;1526 case V4L2_PIX_FMT_SBGGR16:1527 buf[0][offset] = buf[0][offset + 1] = odd ? g_u_s : b_v;1528 buf[1][offset] = buf[1][offset + 1] = odd ? r_y_h : g_u_s;1529 break;1530 case V4L2_PIX_FMT_SGBRG16:1531 buf[0][offset] = buf[0][offset + 1] = odd ? b_v : g_u_s;1532 buf[1][offset] = buf[1][offset + 1] = odd ? g_u_s : r_y_h;1533 break;1534 case V4L2_PIX_FMT_SGRBG16:1535 buf[0][offset] = buf[0][offset + 1] = odd ? r_y_h : g_u_s;1536 buf[1][offset] = buf[1][offset + 1] = odd ? g_u_s : b_v;1537 break;1538 case V4L2_PIX_FMT_SRGGB16:1539 buf[0][offset] = buf[0][offset + 1] = odd ? g_u_s : r_y_h;1540 buf[1][offset] = buf[1][offset + 1] = odd ? b_v : g_u_s;1541 break;1542 }1543}1544 1545unsigned tpg_g_interleaved_plane(const struct tpg_data *tpg, unsigned buf_line)1546{1547 switch (tpg->fourcc) {1548 case V4L2_PIX_FMT_SBGGR8:1549 case V4L2_PIX_FMT_SGBRG8:1550 case V4L2_PIX_FMT_SGRBG8:1551 case V4L2_PIX_FMT_SRGGB8:1552 case V4L2_PIX_FMT_SBGGR10:1553 case V4L2_PIX_FMT_SGBRG10:1554 case V4L2_PIX_FMT_SGRBG10:1555 case V4L2_PIX_FMT_SRGGB10:1556 case V4L2_PIX_FMT_SBGGR12:1557 case V4L2_PIX_FMT_SGBRG12:1558 case V4L2_PIX_FMT_SGRBG12:1559 case V4L2_PIX_FMT_SRGGB12:1560 case V4L2_PIX_FMT_SBGGR16:1561 case V4L2_PIX_FMT_SGBRG16:1562 case V4L2_PIX_FMT_SGRBG16:1563 case V4L2_PIX_FMT_SRGGB16:1564 return buf_line & 1;1565 default:1566 return 0;1567 }1568}1569EXPORT_SYMBOL_GPL(tpg_g_interleaved_plane);1570 1571/* Return how many pattern lines are used by the current pattern. */1572static unsigned tpg_get_pat_lines(const struct tpg_data *tpg)1573{1574 switch (tpg->pattern) {1575 case TPG_PAT_CHECKERS_16X16:1576 case TPG_PAT_CHECKERS_2X2:1577 case TPG_PAT_CHECKERS_1X1:1578 case TPG_PAT_COLOR_CHECKERS_2X2:1579 case TPG_PAT_COLOR_CHECKERS_1X1:1580 case TPG_PAT_ALTERNATING_HLINES:1581 case TPG_PAT_CROSS_1_PIXEL:1582 case TPG_PAT_CROSS_2_PIXELS:1583 case TPG_PAT_CROSS_10_PIXELS:1584 return 2;1585 case TPG_PAT_100_COLORSQUARES:1586 case TPG_PAT_100_HCOLORBAR:1587 return 8;1588 default:1589 return 1;1590 }1591}1592 1593/* Which pattern line should be used for the given frame line. */1594static unsigned tpg_get_pat_line(const struct tpg_data *tpg, unsigned line)1595{1596 switch (tpg->pattern) {1597 case TPG_PAT_CHECKERS_16X16:1598 return (line >> 4) & 1;1599 case TPG_PAT_CHECKERS_1X1:1600 case TPG_PAT_COLOR_CHECKERS_1X1:1601 case TPG_PAT_ALTERNATING_HLINES:1602 return line & 1;1603 case TPG_PAT_CHECKERS_2X2:1604 case TPG_PAT_COLOR_CHECKERS_2X2:1605 return (line & 2) >> 1;1606 case TPG_PAT_100_COLORSQUARES:1607 case TPG_PAT_100_HCOLORBAR:1608 return (line * 8) / tpg->src_height;1609 case TPG_PAT_CROSS_1_PIXEL:1610 return line == tpg->src_height / 2;1611 case TPG_PAT_CROSS_2_PIXELS:1612 return (line + 1) / 2 == tpg->src_height / 4;1613 case TPG_PAT_CROSS_10_PIXELS:1614 return (line + 10) / 20 == tpg->src_height / 40;1615 default:1616 return 0;1617 }1618}1619 1620/*1621 * Which color should be used for the given pattern line and X coordinate.1622 * Note: x is in the range 0 to 2 * tpg->src_width.1623 */1624static enum tpg_color tpg_get_color(const struct tpg_data *tpg,1625 unsigned pat_line, unsigned x)1626{1627 /* Maximum number of bars are TPG_COLOR_MAX - otherwise, the input print code1628 should be modified */1629 static const enum tpg_color bars[3][8] = {1630 /* Standard ITU-R 75% color bar sequence */1631 { TPG_COLOR_CSC_WHITE, TPG_COLOR_75_YELLOW,1632 TPG_COLOR_75_CYAN, TPG_COLOR_75_GREEN,1633 TPG_COLOR_75_MAGENTA, TPG_COLOR_75_RED,1634 TPG_COLOR_75_BLUE, TPG_COLOR_100_BLACK, },1635 /* Standard ITU-R 100% color bar sequence */1636 { TPG_COLOR_100_WHITE, TPG_COLOR_100_YELLOW,1637 TPG_COLOR_100_CYAN, TPG_COLOR_100_GREEN,1638 TPG_COLOR_100_MAGENTA, TPG_COLOR_100_RED,1639 TPG_COLOR_100_BLUE, TPG_COLOR_100_BLACK, },1640 /* Color bar sequence suitable to test CSC */1641 { TPG_COLOR_CSC_WHITE, TPG_COLOR_CSC_YELLOW,1642 TPG_COLOR_CSC_CYAN, TPG_COLOR_CSC_GREEN,1643 TPG_COLOR_CSC_MAGENTA, TPG_COLOR_CSC_RED,1644 TPG_COLOR_CSC_BLUE, TPG_COLOR_CSC_BLACK, },1645 };1646 1647 switch (tpg->pattern) {1648 case TPG_PAT_75_COLORBAR:1649 case TPG_PAT_100_COLORBAR:1650 case TPG_PAT_CSC_COLORBAR:1651 return bars[tpg->pattern][((x * 8) / tpg->src_width) % 8];1652 case TPG_PAT_100_COLORSQUARES:1653 return bars[1][(pat_line + (x * 8) / tpg->src_width) % 8];1654 case TPG_PAT_100_HCOLORBAR:1655 return bars[1][pat_line];1656 case TPG_PAT_BLACK:1657 return TPG_COLOR_100_BLACK;1658 case TPG_PAT_WHITE:1659 return TPG_COLOR_100_WHITE;1660 case TPG_PAT_RED:1661 return TPG_COLOR_100_RED;1662 case TPG_PAT_GREEN:1663 return TPG_COLOR_100_GREEN;1664 case TPG_PAT_BLUE:1665 return TPG_COLOR_100_BLUE;1666 case TPG_PAT_CHECKERS_16X16:1667 return (((x >> 4) & 1) ^ (pat_line & 1)) ?1668 TPG_COLOR_100_BLACK : TPG_COLOR_100_WHITE;1669 case TPG_PAT_CHECKERS_1X1:1670 return ((x & 1) ^ (pat_line & 1)) ?1671 TPG_COLOR_100_WHITE : TPG_COLOR_100_BLACK;1672 case TPG_PAT_COLOR_CHECKERS_1X1:1673 return ((x & 1) ^ (pat_line & 1)) ?1674 TPG_COLOR_100_RED : TPG_COLOR_100_BLUE;1675 case TPG_PAT_CHECKERS_2X2:1676 return (((x >> 1) & 1) ^ (pat_line & 1)) ?1677 TPG_COLOR_100_WHITE : TPG_COLOR_100_BLACK;1678 case TPG_PAT_COLOR_CHECKERS_2X2:1679 return (((x >> 1) & 1) ^ (pat_line & 1)) ?1680 TPG_COLOR_100_RED : TPG_COLOR_100_BLUE;1681 case TPG_PAT_ALTERNATING_HLINES:1682 return pat_line ? TPG_COLOR_100_WHITE : TPG_COLOR_100_BLACK;1683 case TPG_PAT_ALTERNATING_VLINES:1684 return (x & 1) ? TPG_COLOR_100_WHITE : TPG_COLOR_100_BLACK;1685 case TPG_PAT_CROSS_1_PIXEL:1686 if (pat_line || (x % tpg->src_width) == tpg->src_width / 2)1687 return TPG_COLOR_100_BLACK;1688 return TPG_COLOR_100_WHITE;1689 case TPG_PAT_CROSS_2_PIXELS:1690 if (pat_line || ((x % tpg->src_width) + 1) / 2 == tpg->src_width / 4)1691 return TPG_COLOR_100_BLACK;1692 return TPG_COLOR_100_WHITE;1693 case TPG_PAT_CROSS_10_PIXELS:1694 if (pat_line || ((x % tpg->src_width) + 10) / 20 == tpg->src_width / 40)1695 return TPG_COLOR_100_BLACK;1696 return TPG_COLOR_100_WHITE;1697 case TPG_PAT_GRAY_RAMP:1698 return TPG_COLOR_RAMP + ((x % tpg->src_width) * 256) / tpg->src_width;1699 default:1700 return TPG_COLOR_100_RED;1701 }1702}1703 1704/*1705 * Given the pixel aspect ratio and video aspect ratio calculate the1706 * coordinates of a centered square and the coordinates of the border of1707 * the active video area. The coordinates are relative to the source1708 * frame rectangle.1709 */1710static void tpg_calculate_square_border(struct tpg_data *tpg)1711{1712 unsigned w = tpg->src_width;1713 unsigned h = tpg->src_height;1714 unsigned sq_w, sq_h;1715 1716 sq_w = (w * 2 / 5) & ~1;1717 if (((w - sq_w) / 2) & 1)1718 sq_w += 2;1719 sq_h = sq_w;1720 tpg->square.width = sq_w;1721 if (tpg->vid_aspect == TPG_VIDEO_ASPECT_16X9_ANAMORPHIC) {1722 unsigned ana_sq_w = (sq_w / 4) * 3;1723 1724 if (((w - ana_sq_w) / 2) & 1)1725 ana_sq_w += 2;1726 tpg->square.width = ana_sq_w;1727 }1728 tpg->square.left = (w - tpg->square.width) / 2;1729 if (tpg->pix_aspect == TPG_PIXEL_ASPECT_NTSC)1730 sq_h = sq_w * 10 / 11;1731 else if (tpg->pix_aspect == TPG_PIXEL_ASPECT_PAL)1732 sq_h = sq_w * 59 / 54;1733 tpg->square.height = sq_h;1734 tpg->square.top = (h - sq_h) / 2;1735 tpg->border.left = 0;1736 tpg->border.width = w;1737 tpg->border.top = 0;1738 tpg->border.height = h;1739 switch (tpg->vid_aspect) {1740 case TPG_VIDEO_ASPECT_4X3:1741 if (tpg->pix_aspect)1742 return;1743 if (3 * w >= 4 * h) {1744 tpg->border.width = ((4 * h) / 3) & ~1;1745 if (((w - tpg->border.width) / 2) & ~1)1746 tpg->border.width -= 2;1747 tpg->border.left = (w - tpg->border.width) / 2;1748 break;1749 }1750 tpg->border.height = ((3 * w) / 4) & ~1;1751 tpg->border.top = (h - tpg->border.height) / 2;1752 break;1753 case TPG_VIDEO_ASPECT_14X9_CENTRE:1754 if (tpg->pix_aspect) {1755 tpg->border.height = tpg->pix_aspect == TPG_PIXEL_ASPECT_NTSC ? 420 : 506;1756 tpg->border.top = (h - tpg->border.height) / 2;1757 break;1758 }1759 if (9 * w >= 14 * h) {1760 tpg->border.width = ((14 * h) / 9) & ~1;1761 if (((w - tpg->border.width) / 2) & ~1)1762 tpg->border.width -= 2;1763 tpg->border.left = (w - tpg->border.width) / 2;1764 break;1765 }1766 tpg->border.height = ((9 * w) / 14) & ~1;1767 tpg->border.top = (h - tpg->border.height) / 2;1768 break;1769 case TPG_VIDEO_ASPECT_16X9_CENTRE:1770 if (tpg->pix_aspect) {1771 tpg->border.height = tpg->pix_aspect == TPG_PIXEL_ASPECT_NTSC ? 368 : 442;1772 tpg->border.top = (h - tpg->border.height) / 2;1773 break;1774 }1775 if (9 * w >= 16 * h) {1776 tpg->border.width = ((16 * h) / 9) & ~1;1777 if (((w - tpg->border.width) / 2) & ~1)1778 tpg->border.width -= 2;1779 tpg->border.left = (w - tpg->border.width) / 2;1780 break;1781 }1782 tpg->border.height = ((9 * w) / 16) & ~1;1783 tpg->border.top = (h - tpg->border.height) / 2;1784 break;1785 default:1786 break;1787 }1788}1789 1790static void tpg_precalculate_line(struct tpg_data *tpg)1791{1792 enum tpg_color contrast;1793 u8 pix[TPG_MAX_PLANES][8];1794 unsigned pat;1795 unsigned p;1796 unsigned x;1797 1798 if (WARN_ON_ONCE(!tpg->src_width || !tpg->scaled_width))1799 return;1800 1801 switch (tpg->pattern) {1802 case TPG_PAT_GREEN:1803 contrast = TPG_COLOR_100_RED;1804 break;1805 case TPG_PAT_CSC_COLORBAR:1806 contrast = TPG_COLOR_CSC_GREEN;1807 break;1808 default:1809 contrast = TPG_COLOR_100_GREEN;1810 break;1811 }1812 1813 for (pat = 0; pat < tpg_get_pat_lines(tpg); pat++) {1814 /* Coarse scaling with Bresenham */1815 unsigned int_part = tpg->src_width / tpg->scaled_width;1816 unsigned fract_part = tpg->src_width % tpg->scaled_width;1817 unsigned src_x = 0;1818 unsigned error = 0;1819 1820 for (x = 0; x < tpg->scaled_width * 2; x += 2) {1821 unsigned real_x = src_x;1822 enum tpg_color color1, color2;1823 1824 real_x = tpg->hflip ? tpg->src_width * 2 - real_x - 2 : real_x;1825 color1 = tpg_get_color(tpg, pat, real_x);1826 1827 src_x += int_part;1828 error += fract_part;1829 if (error >= tpg->scaled_width) {1830 error -= tpg->scaled_width;1831 src_x++;1832 }1833 1834 real_x = src_x;1835 real_x = tpg->hflip ? tpg->src_width * 2 - real_x - 2 : real_x;1836 color2 = tpg_get_color(tpg, pat, real_x);1837 1838 src_x += int_part;1839 error += fract_part;1840 if (error >= tpg->scaled_width) {1841 error -= tpg->scaled_width;1842 src_x++;1843 }1844 1845 gen_twopix(tpg, pix, tpg->hflip ? color2 : color1, 0);1846 gen_twopix(tpg, pix, tpg->hflip ? color1 : color2, 1);1847 for (p = 0; p < tpg->planes; p++) {1848 unsigned twopixsize = tpg->twopixelsize[p];1849 unsigned hdiv = tpg->hdownsampling[p];1850 u8 *pos = tpg->lines[pat][p] + tpg_hdiv(tpg, p, x);1851 1852 memcpy(pos, pix[p], twopixsize / hdiv);1853 }1854 }1855 }1856 1857 if (tpg->vdownsampling[tpg->planes - 1] > 1) {1858 unsigned pat_lines = tpg_get_pat_lines(tpg);1859 1860 for (pat = 0; pat < pat_lines; pat++) {1861 unsigned next_pat = (pat + 1) % pat_lines;1862 1863 for (p = 1; p < tpg->planes; p++) {1864 unsigned w = tpg_hdiv(tpg, p, tpg->scaled_width * 2);1865 u8 *pos1 = tpg->lines[pat][p];1866 u8 *pos2 = tpg->lines[next_pat][p];1867 u8 *dest = tpg->downsampled_lines[pat][p];1868 1869 for (x = 0; x < w; x++, pos1++, pos2++, dest++)1870 *dest = ((u16)*pos1 + (u16)*pos2) / 2;1871 }1872 }1873 }1874 1875 gen_twopix(tpg, pix, contrast, 0);1876 gen_twopix(tpg, pix, contrast, 1);1877 for (p = 0; p < tpg->planes; p++) {1878 unsigned twopixsize = tpg->twopixelsize[p];1879 u8 *pos = tpg->contrast_line[p];1880 1881 for (x = 0; x < tpg->scaled_width; x += 2, pos += twopixsize)1882 memcpy(pos, pix[p], twopixsize);1883 }1884 1885 gen_twopix(tpg, pix, TPG_COLOR_100_BLACK, 0);1886 gen_twopix(tpg, pix, TPG_COLOR_100_BLACK, 1);1887 for (p = 0; p < tpg->planes; p++) {1888 unsigned twopixsize = tpg->twopixelsize[p];1889 u8 *pos = tpg->black_line[p];1890 1891 for (x = 0; x < tpg->scaled_width; x += 2, pos += twopixsize)1892 memcpy(pos, pix[p], twopixsize);1893 }1894 1895 for (x = 0; x < tpg->scaled_width * 2; x += 2) {1896 gen_twopix(tpg, pix, TPG_COLOR_RANDOM, 0);1897 gen_twopix(tpg, pix, TPG_COLOR_RANDOM, 1);1898 for (p = 0; p < tpg->planes; p++) {1899 unsigned twopixsize = tpg->twopixelsize[p];1900 u8 *pos = tpg->random_line[p] + x * twopixsize / 2;1901 1902 memcpy(pos, pix[p], twopixsize);1903 }1904 }1905 1906 gen_twopix(tpg, tpg->textbg, TPG_COLOR_TEXTBG, 0);1907 gen_twopix(tpg, tpg->textbg, TPG_COLOR_TEXTBG, 1);1908 gen_twopix(tpg, tpg->textfg, TPG_COLOR_TEXTFG, 0);1909 gen_twopix(tpg, tpg->textfg, TPG_COLOR_TEXTFG, 1);1910}1911 1912/* need this to do rgb24 rendering */1913typedef struct { u16 __; u8 _; } __packed x24;1914 1915#define PRINTSTR(PIXTYPE) do { \1916 unsigned vdiv = tpg->vdownsampling[p]; \1917 unsigned hdiv = tpg->hdownsampling[p]; \1918 int line; \1919 PIXTYPE fg; \1920 PIXTYPE bg; \1921 memcpy(&fg, tpg->textfg[p], sizeof(PIXTYPE)); \1922 memcpy(&bg, tpg->textbg[p], sizeof(PIXTYPE)); \1923 \1924 for (line = first; line < 16; line += vdiv * step) { \1925 int l = tpg->vflip ? 15 - line : line; \1926 PIXTYPE *pos = (PIXTYPE *)(basep[p][(line / vdiv) & 1] + \1927 ((y * step + l) / (vdiv * div)) * tpg->bytesperline[p] + \1928 (x / hdiv) * sizeof(PIXTYPE)); \1929 unsigned s; \1930 \1931 for (s = 0; s < len; s++) { \1932 u8 chr = font8x16[(u8)text[s] * 16 + line]; \1933 \1934 if (hdiv == 2 && tpg->hflip) { \1935 pos[3] = (chr & (0x01 << 6) ? fg : bg); \1936 pos[2] = (chr & (0x01 << 4) ? fg : bg); \1937 pos[1] = (chr & (0x01 << 2) ? fg : bg); \1938 pos[0] = (chr & (0x01 << 0) ? fg : bg); \1939 } else if (hdiv == 2) { \1940 pos[0] = (chr & (0x01 << 7) ? fg : bg); \1941 pos[1] = (chr & (0x01 << 5) ? fg : bg); \1942 pos[2] = (chr & (0x01 << 3) ? fg : bg); \1943 pos[3] = (chr & (0x01 << 1) ? fg : bg); \1944 } else if (tpg->hflip) { \1945 pos[7] = (chr & (0x01 << 7) ? fg : bg); \1946 pos[6] = (chr & (0x01 << 6) ? fg : bg); \1947 pos[5] = (chr & (0x01 << 5) ? fg : bg); \1948 pos[4] = (chr & (0x01 << 4) ? fg : bg); \1949 pos[3] = (chr & (0x01 << 3) ? fg : bg); \1950 pos[2] = (chr & (0x01 << 2) ? fg : bg); \1951 pos[1] = (chr & (0x01 << 1) ? fg : bg); \1952 pos[0] = (chr & (0x01 << 0) ? fg : bg); \1953 } else { \1954 pos[0] = (chr & (0x01 << 7) ? fg : bg); \1955 pos[1] = (chr & (0x01 << 6) ? fg : bg); \1956 pos[2] = (chr & (0x01 << 5) ? fg : bg); \1957 pos[3] = (chr & (0x01 << 4) ? fg : bg); \1958 pos[4] = (chr & (0x01 << 3) ? fg : bg); \1959 pos[5] = (chr & (0x01 << 2) ? fg : bg); \1960 pos[6] = (chr & (0x01 << 1) ? fg : bg); \1961 pos[7] = (chr & (0x01 << 0) ? fg : bg); \1962 } \1963 \1964 pos += (tpg->hflip ? -8 : 8) / (int)hdiv; \1965 } \1966 } \1967} while (0)1968 1969static noinline void tpg_print_str_2(const struct tpg_data *tpg, u8 *basep[TPG_MAX_PLANES][2],1970 unsigned p, unsigned first, unsigned div, unsigned step,1971 int y, int x, const char *text, unsigned len)1972{1973 PRINTSTR(u8);1974}1975 1976static noinline void tpg_print_str_4(const struct tpg_data *tpg, u8 *basep[TPG_MAX_PLANES][2],1977 unsigned p, unsigned first, unsigned div, unsigned step,1978 int y, int x, const char *text, unsigned len)1979{1980 PRINTSTR(u16);1981}1982 1983static noinline void tpg_print_str_6(const struct tpg_data *tpg, u8 *basep[TPG_MAX_PLANES][2],1984 unsigned p, unsigned first, unsigned div, unsigned step,1985 int y, int x, const char *text, unsigned len)1986{1987 PRINTSTR(x24);1988}1989 1990static noinline void tpg_print_str_8(const struct tpg_data *tpg, u8 *basep[TPG_MAX_PLANES][2],1991 unsigned p, unsigned first, unsigned div, unsigned step,1992 int y, int x, const char *text, unsigned len)1993{1994 PRINTSTR(u32);1995}1996 1997void tpg_gen_text(const struct tpg_data *tpg, u8 *basep[TPG_MAX_PLANES][2],1998 int y, int x, const char *text)1999{2000 unsigned step = V4L2_FIELD_HAS_T_OR_B(tpg->field) ? 2 : 1;2001 unsigned div = step;2002 unsigned first = 0;2003 unsigned len;2004 unsigned p;2005 2006 if (font8x16 == NULL || basep == NULL || text == NULL)2007 return;2008 2009 len = strlen(text);2010 2011 /* Checks if it is possible to show string */2012 if (y + 16 >= tpg->compose.height || x + 8 >= tpg->compose.width)2013 return;2014 2015 if (len > (tpg->compose.width - x) / 8)2016 len = (tpg->compose.width - x) / 8;2017 if (tpg->vflip)2018 y = tpg->compose.height - y - 16;2019 if (tpg->hflip)2020 x = tpg->compose.width - x - 8;2021 y += tpg->compose.top;2022 x += tpg->compose.left;2023 if (tpg->field == V4L2_FIELD_BOTTOM)2024 first = 1;2025 else if (tpg->field == V4L2_FIELD_SEQ_TB || tpg->field == V4L2_FIELD_SEQ_BT)2026 div = 2;2027 2028 for (p = 0; p < tpg->planes; p++) {2029 /* Print text */2030 switch (tpg->twopixelsize[p]) {2031 case 2:2032 tpg_print_str_2(tpg, basep, p, first, div, step, y, x,2033 text, len);2034 break;2035 case 4:2036 tpg_print_str_4(tpg, basep, p, first, div, step, y, x,2037 text, len);2038 break;2039 case 6:2040 tpg_print_str_6(tpg, basep, p, first, div, step, y, x,2041 text, len);2042 break;2043 case 8:2044 tpg_print_str_8(tpg, basep, p, first, div, step, y, x,2045 text, len);2046 break;2047 }2048 }2049}2050EXPORT_SYMBOL_GPL(tpg_gen_text);2051 2052const char *tpg_g_color_order(const struct tpg_data *tpg)2053{2054 switch (tpg->pattern) {2055 case TPG_PAT_75_COLORBAR:2056 case TPG_PAT_100_COLORBAR:2057 case TPG_PAT_CSC_COLORBAR:2058 case TPG_PAT_100_HCOLORBAR:2059 return "White, yellow, cyan, green, magenta, red, blue, black";2060 case TPG_PAT_BLACK:2061 return "Black";2062 case TPG_PAT_WHITE:2063 return "White";2064 case TPG_PAT_RED:2065 return "Red";2066 case TPG_PAT_GREEN:2067 return "Green";2068 case TPG_PAT_BLUE:2069 return "Blue";2070 default:2071 return NULL;2072 }2073}2074EXPORT_SYMBOL_GPL(tpg_g_color_order);2075 2076void tpg_update_mv_step(struct tpg_data *tpg)2077{2078 int factor = tpg->mv_hor_mode > TPG_MOVE_NONE ? -1 : 1;2079 2080 if (tpg->hflip)2081 factor = -factor;2082 switch (tpg->mv_hor_mode) {2083 case TPG_MOVE_NEG_FAST:2084 case TPG_MOVE_POS_FAST:2085 tpg->mv_hor_step = ((tpg->src_width + 319) / 320) * 4;2086 break;2087 case TPG_MOVE_NEG:2088 case TPG_MOVE_POS:2089 tpg->mv_hor_step = ((tpg->src_width + 639) / 640) * 4;2090 break;2091 case TPG_MOVE_NEG_SLOW:2092 case TPG_MOVE_POS_SLOW:2093 tpg->mv_hor_step = 2;2094 break;2095 case TPG_MOVE_NONE:2096 tpg->mv_hor_step = 0;2097 break;2098 }2099 if (factor < 0)2100 tpg->mv_hor_step = tpg->src_width - tpg->mv_hor_step;2101 2102 factor = tpg->mv_vert_mode > TPG_MOVE_NONE ? -1 : 1;2103 switch (tpg->mv_vert_mode) {2104 case TPG_MOVE_NEG_FAST:2105 case TPG_MOVE_POS_FAST:2106 tpg->mv_vert_step = ((tpg->src_width + 319) / 320) * 4;2107 break;2108 case TPG_MOVE_NEG:2109 case TPG_MOVE_POS:2110 tpg->mv_vert_step = ((tpg->src_width + 639) / 640) * 4;2111 break;2112 case TPG_MOVE_NEG_SLOW:2113 case TPG_MOVE_POS_SLOW:2114 tpg->mv_vert_step = 1;2115 break;2116 case TPG_MOVE_NONE:2117 tpg->mv_vert_step = 0;2118 break;2119 }2120 if (factor < 0)2121 tpg->mv_vert_step = tpg->src_height - tpg->mv_vert_step;2122}2123EXPORT_SYMBOL_GPL(tpg_update_mv_step);2124 2125/* Map the line number relative to the crop rectangle to a frame line number */2126static unsigned tpg_calc_frameline(const struct tpg_data *tpg, unsigned src_y,2127 unsigned field)2128{2129 switch (field) {2130 case V4L2_FIELD_TOP:2131 return tpg->crop.top + src_y * 2;2132 case V4L2_FIELD_BOTTOM:2133 return tpg->crop.top + src_y * 2 + 1;2134 default:2135 return src_y + tpg->crop.top;2136 }2137}2138 2139/*2140 * Map the line number relative to the compose rectangle to a destination2141 * buffer line number.2142 */2143static unsigned tpg_calc_buffer_line(const struct tpg_data *tpg, unsigned y,2144 unsigned field)2145{2146 y += tpg->compose.top;2147 switch (field) {2148 case V4L2_FIELD_SEQ_TB:2149 if (y & 1)2150 return tpg->buf_height / 2 + y / 2;2151 return y / 2;2152 case V4L2_FIELD_SEQ_BT:2153 if (y & 1)2154 return y / 2;2155 return tpg->buf_height / 2 + y / 2;2156 default:2157 return y;2158 }2159}2160 2161static void tpg_recalc(struct tpg_data *tpg)2162{2163 if (tpg->recalc_colors) {2164 tpg->recalc_colors = false;2165 tpg->recalc_lines = true;2166 tpg->real_xfer_func = tpg->xfer_func;2167 tpg->real_ycbcr_enc = tpg->ycbcr_enc;2168 tpg->real_hsv_enc = tpg->hsv_enc;2169 tpg->real_quantization = tpg->quantization;2170 2171 if (tpg->xfer_func == V4L2_XFER_FUNC_DEFAULT)2172 tpg->real_xfer_func =2173 V4L2_MAP_XFER_FUNC_DEFAULT(tpg->colorspace);2174 2175 if (tpg->ycbcr_enc == V4L2_YCBCR_ENC_DEFAULT)2176 tpg->real_ycbcr_enc =2177 V4L2_MAP_YCBCR_ENC_DEFAULT(tpg->colorspace);2178 2179 if (tpg->quantization == V4L2_QUANTIZATION_DEFAULT)2180 tpg->real_quantization =2181 V4L2_MAP_QUANTIZATION_DEFAULT(2182 tpg->color_enc != TGP_COLOR_ENC_YCBCR,2183 tpg->colorspace, tpg->real_ycbcr_enc);2184 2185 tpg_precalculate_colors(tpg);2186 }2187 if (tpg->recalc_square_border) {2188 tpg->recalc_square_border = false;2189 tpg_calculate_square_border(tpg);2190 }2191 if (tpg->recalc_lines) {2192 tpg->recalc_lines = false;2193 tpg_precalculate_line(tpg);2194 }2195}2196 2197void tpg_calc_text_basep(struct tpg_data *tpg,2198 u8 *basep[TPG_MAX_PLANES][2], unsigned p, u8 *vbuf)2199{2200 unsigned stride = tpg->bytesperline[p];2201 unsigned h = tpg->buf_height;2202 2203 tpg_recalc(tpg);2204 2205 basep[p][0] = vbuf;2206 basep[p][1] = vbuf;2207 h /= tpg->vdownsampling[p];2208 if (tpg->field == V4L2_FIELD_SEQ_TB)2209 basep[p][1] += h * stride / 2;2210 else if (tpg->field == V4L2_FIELD_SEQ_BT)2211 basep[p][0] += h * stride / 2;2212 if (p == 0 && tpg->interleaved)2213 tpg_calc_text_basep(tpg, basep, 1, vbuf);2214}2215EXPORT_SYMBOL_GPL(tpg_calc_text_basep);2216 2217static int tpg_pattern_avg(const struct tpg_data *tpg,2218 unsigned pat1, unsigned pat2)2219{2220 unsigned pat_lines = tpg_get_pat_lines(tpg);2221 2222 if (pat1 == (pat2 + 1) % pat_lines)2223 return pat2;2224 if (pat2 == (pat1 + 1) % pat_lines)2225 return pat1;2226 return -1;2227}2228 2229static const char *tpg_color_enc_str(enum tgp_color_enc2230 color_enc)2231{2232 switch (color_enc) {2233 case TGP_COLOR_ENC_HSV:2234 return "HSV";2235 case TGP_COLOR_ENC_YCBCR:2236 return "Y'CbCr";2237 case TGP_COLOR_ENC_LUMA:2238 return "Luma";2239 case TGP_COLOR_ENC_RGB:2240 default:2241 return "R'G'B";2242 2243 }2244}2245 2246void tpg_log_status(struct tpg_data *tpg)2247{2248 pr_info("tpg source WxH: %ux%u (%s)\n",2249 tpg->src_width, tpg->src_height,2250 tpg_color_enc_str(tpg->color_enc));2251 pr_info("tpg field: %u\n", tpg->field);2252 pr_info("tpg crop: %ux%u@%dx%d\n", tpg->crop.width, tpg->crop.height,2253 tpg->crop.left, tpg->crop.top);2254 pr_info("tpg compose: %ux%u@%dx%d\n", tpg->compose.width, tpg->compose.height,2255 tpg->compose.left, tpg->compose.top);2256 pr_info("tpg colorspace: %d\n", tpg->colorspace);2257 pr_info("tpg transfer function: %d/%d\n", tpg->xfer_func, tpg->real_xfer_func);2258 if (tpg->color_enc == TGP_COLOR_ENC_HSV)2259 pr_info("tpg HSV encoding: %d/%d\n",2260 tpg->hsv_enc, tpg->real_hsv_enc);2261 else if (tpg->color_enc == TGP_COLOR_ENC_YCBCR)2262 pr_info("tpg Y'CbCr encoding: %d/%d\n",2263 tpg->ycbcr_enc, tpg->real_ycbcr_enc);2264 pr_info("tpg quantization: %d/%d\n", tpg->quantization, tpg->real_quantization);2265 pr_info("tpg RGB range: %d/%d\n", tpg->rgb_range, tpg->real_rgb_range);2266}2267EXPORT_SYMBOL_GPL(tpg_log_status);2268 2269/*2270 * This struct contains common parameters used by both the drawing of the2271 * test pattern and the drawing of the extras (borders, square, etc.)2272 */2273struct tpg_draw_params {2274 /* common data */2275 bool is_tv;2276 bool is_60hz;2277 unsigned twopixsize;2278 unsigned img_width;2279 unsigned stride;2280 unsigned hmax;2281 unsigned frame_line;2282 unsigned frame_line_next;2283 2284 /* test pattern */2285 unsigned mv_hor_old;2286 unsigned mv_hor_new;2287 unsigned mv_vert_old;2288 unsigned mv_vert_new;2289 2290 /* extras */2291 unsigned wss_width;2292 unsigned wss_random_offset;2293 unsigned sav_eav_f;2294 unsigned left_pillar_width;2295 unsigned right_pillar_start;2296};2297 2298static void tpg_fill_params_pattern(const struct tpg_data *tpg, unsigned p,2299 struct tpg_draw_params *params)2300{2301 params->mv_hor_old =2302 tpg_hscale_div(tpg, p, tpg->mv_hor_count % tpg->src_width);2303 params->mv_hor_new =2304 tpg_hscale_div(tpg, p, (tpg->mv_hor_count + tpg->mv_hor_step) %2305 tpg->src_width);2306 params->mv_vert_old = tpg->mv_vert_count % tpg->src_height;2307 params->mv_vert_new =2308 (tpg->mv_vert_count + tpg->mv_vert_step) % tpg->src_height;2309}2310 2311static void tpg_fill_params_extras(const struct tpg_data *tpg,2312 unsigned p,2313 struct tpg_draw_params *params)2314{2315 unsigned left_pillar_width = 0;2316 unsigned right_pillar_start = params->img_width;2317 2318 params->wss_width = tpg->crop.left < tpg->src_width / 2 ?2319 tpg->src_width / 2 - tpg->crop.left : 0;2320 if (params->wss_width > tpg->crop.width)2321 params->wss_width = tpg->crop.width;2322 params->wss_width = tpg_hscale_div(tpg, p, params->wss_width);2323 params->wss_random_offset =2324 params->twopixsize * get_random_u32_below(tpg->src_width / 2);2325 2326 if (tpg->crop.left < tpg->border.left) {2327 left_pillar_width = tpg->border.left - tpg->crop.left;2328 if (left_pillar_width > tpg->crop.width)2329 left_pillar_width = tpg->crop.width;2330 left_pillar_width = tpg_hscale_div(tpg, p, left_pillar_width);2331 }2332 params->left_pillar_width = left_pillar_width;2333 2334 if (tpg->crop.left + tpg->crop.width >2335 tpg->border.left + tpg->border.width) {2336 right_pillar_start =2337 tpg->border.left + tpg->border.width - tpg->crop.left;2338 right_pillar_start =2339 tpg_hscale_div(tpg, p, right_pillar_start);2340 if (right_pillar_start > params->img_width)2341 right_pillar_start = params->img_width;2342 }2343 params->right_pillar_start = right_pillar_start;2344 2345 params->sav_eav_f = tpg->field ==2346 (params->is_60hz ? V4L2_FIELD_TOP : V4L2_FIELD_BOTTOM);2347}2348 2349static void tpg_fill_plane_extras(const struct tpg_data *tpg,2350 const struct tpg_draw_params *params,2351 unsigned p, unsigned h, u8 *vbuf)2352{2353 unsigned twopixsize = params->twopixsize;2354 unsigned img_width = params->img_width;2355 unsigned frame_line = params->frame_line;2356 const struct v4l2_rect *sq = &tpg->square;2357 const struct v4l2_rect *b = &tpg->border;2358 const struct v4l2_rect *c = &tpg->crop;2359 2360 if (params->is_tv && !params->is_60hz &&2361 frame_line == 0 && params->wss_width) {2362 /*2363 * Replace the first half of the top line of a 50 Hz frame2364 * with random data to simulate a WSS signal.2365 */2366 u8 *wss = tpg->random_line[p] + params->wss_random_offset;2367 2368 memcpy(vbuf, wss, params->wss_width);2369 }2370 2371 if (tpg->show_border && frame_line >= b->top &&2372 frame_line < b->top + b->height) {2373 unsigned bottom = b->top + b->height - 1;2374 unsigned left = params->left_pillar_width;2375 unsigned right = params->right_pillar_start;2376 2377 if (frame_line == b->top || frame_line == b->top + 1 ||2378 frame_line == bottom || frame_line == bottom - 1) {2379 memcpy(vbuf + left, tpg->contrast_line[p],2380 right - left);2381 } else {2382 if (b->left >= c->left &&2383 b->left < c->left + c->width)2384 memcpy(vbuf + left,2385 tpg->contrast_line[p], twopixsize);2386 if (b->left + b->width > c->left &&2387 b->left + b->width <= c->left + c->width)2388 memcpy(vbuf + right - twopixsize,2389 tpg->contrast_line[p], twopixsize);2390 }2391 }2392 if (tpg->qual != TPG_QUAL_NOISE && frame_line >= b->top &&2393 frame_line < b->top + b->height) {2394 memcpy(vbuf, tpg->black_line[p], params->left_pillar_width);2395 memcpy(vbuf + params->right_pillar_start, tpg->black_line[p],2396 img_width - params->right_pillar_start);2397 }2398 if (tpg->show_square && frame_line >= sq->top &&2399 frame_line < sq->top + sq->height &&2400 sq->left < c->left + c->width &&2401 sq->left + sq->width >= c->left) {2402 unsigned left = sq->left;2403 unsigned width = sq->width;2404 2405 if (c->left > left) {2406 width -= c->left - left;2407 left = c->left;2408 }2409 if (c->left + c->width < left + width)2410 width -= left + width - c->left - c->width;2411 left -= c->left;2412 left = tpg_hscale_div(tpg, p, left);2413 width = tpg_hscale_div(tpg, p, width);2414 memcpy(vbuf + left, tpg->contrast_line[p], width);2415 }2416 if (tpg->insert_sav) {2417 unsigned offset = tpg_hdiv(tpg, p, tpg->compose.width / 3);2418 u8 *p = vbuf + offset;2419 unsigned vact = 0, hact = 0;2420 2421 p[0] = 0xff;2422 p[1] = 0;2423 p[2] = 0;2424 p[3] = 0x80 | (params->sav_eav_f << 6) |2425 (vact << 5) | (hact << 4) |2426 ((hact ^ vact) << 3) |2427 ((hact ^ params->sav_eav_f) << 2) |2428 ((params->sav_eav_f ^ vact) << 1) |2429 (hact ^ vact ^ params->sav_eav_f);2430 }2431 if (tpg->insert_eav) {2432 unsigned offset = tpg_hdiv(tpg, p, tpg->compose.width * 2 / 3);2433 u8 *p = vbuf + offset;2434 unsigned vact = 0, hact = 1;2435 2436 p[0] = 0xff;2437 p[1] = 0;2438 p[2] = 0;2439 p[3] = 0x80 | (params->sav_eav_f << 6) |2440 (vact << 5) | (hact << 4) |2441 ((hact ^ vact) << 3) |2442 ((hact ^ params->sav_eav_f) << 2) |2443 ((params->sav_eav_f ^ vact) << 1) |2444 (hact ^ vact ^ params->sav_eav_f);2445 }2446 if (tpg->insert_hdmi_video_guard_band) {2447 unsigned int i;2448 2449 switch (tpg->fourcc) {2450 case V4L2_PIX_FMT_BGR24:2451 case V4L2_PIX_FMT_RGB24:2452 for (i = 0; i < 3 * 4; i += 3) {2453 vbuf[i] = 0xab;2454 vbuf[i + 1] = 0x55;2455 vbuf[i + 2] = 0xab;2456 }2457 break;2458 case V4L2_PIX_FMT_RGB32:2459 case V4L2_PIX_FMT_ARGB32:2460 case V4L2_PIX_FMT_XRGB32:2461 case V4L2_PIX_FMT_BGRX32:2462 case V4L2_PIX_FMT_BGRA32:2463 for (i = 0; i < 4 * 4; i += 4) {2464 vbuf[i] = 0x00;2465 vbuf[i + 1] = 0xab;2466 vbuf[i + 2] = 0x55;2467 vbuf[i + 3] = 0xab;2468 }2469 break;2470 case V4L2_PIX_FMT_BGR32:2471 case V4L2_PIX_FMT_XBGR32:2472 case V4L2_PIX_FMT_ABGR32:2473 case V4L2_PIX_FMT_RGBX32:2474 case V4L2_PIX_FMT_RGBA32:2475 for (i = 0; i < 4 * 4; i += 4) {2476 vbuf[i] = 0xab;2477 vbuf[i + 1] = 0x55;2478 vbuf[i + 2] = 0xab;2479 vbuf[i + 3] = 0x00;2480 }2481 break;2482 }2483 }2484}2485 2486static void tpg_fill_plane_pattern(const struct tpg_data *tpg,2487 const struct tpg_draw_params *params,2488 unsigned p, unsigned h, u8 *vbuf)2489{2490 unsigned twopixsize = params->twopixsize;2491 unsigned img_width = params->img_width;2492 unsigned mv_hor_old = params->mv_hor_old;2493 unsigned mv_hor_new = params->mv_hor_new;2494 unsigned mv_vert_old = params->mv_vert_old;2495 unsigned mv_vert_new = params->mv_vert_new;2496 unsigned frame_line = params->frame_line;2497 unsigned frame_line_next = params->frame_line_next;2498 unsigned line_offset = tpg_hscale_div(tpg, p, tpg->crop.left);2499 bool even;2500 bool fill_blank = false;2501 unsigned pat_line_old;2502 unsigned pat_line_new;2503 u8 *linestart_older;2504 u8 *linestart_newer;2505 u8 *linestart_top;2506 u8 *linestart_bottom;2507 2508 even = !(frame_line & 1);2509 2510 if (h >= params->hmax) {2511 if (params->hmax == tpg->compose.height)2512 return;2513 if (!tpg->perc_fill_blank)2514 return;2515 fill_blank = true;2516 }2517 2518 if (tpg->vflip) {2519 frame_line = tpg->src_height - frame_line - 1;2520 frame_line_next = tpg->src_height - frame_line_next - 1;2521 }2522 2523 if (fill_blank) {2524 linestart_older = tpg->contrast_line[p];2525 linestart_newer = tpg->contrast_line[p];2526 } else if (tpg->qual != TPG_QUAL_NOISE &&2527 (frame_line < tpg->border.top ||2528 frame_line >= tpg->border.top + tpg->border.height)) {2529 linestart_older = tpg->black_line[p];2530 linestart_newer = tpg->black_line[p];2531 } else if (tpg->pattern == TPG_PAT_NOISE || tpg->qual == TPG_QUAL_NOISE) {2532 linestart_older = tpg->random_line[p] +2533 twopixsize * get_random_u32_below(tpg->src_width / 2);2534 linestart_newer = tpg->random_line[p] +2535 twopixsize * get_random_u32_below(tpg->src_width / 2);2536 } else {2537 unsigned frame_line_old =2538 (frame_line + mv_vert_old) % tpg->src_height;2539 unsigned frame_line_new =2540 (frame_line + mv_vert_new) % tpg->src_height;2541 unsigned pat_line_next_old;2542 unsigned pat_line_next_new;2543 2544 pat_line_old = tpg_get_pat_line(tpg, frame_line_old);2545 pat_line_new = tpg_get_pat_line(tpg, frame_line_new);2546 linestart_older = tpg->lines[pat_line_old][p] + mv_hor_old;2547 linestart_newer = tpg->lines[pat_line_new][p] + mv_hor_new;2548 2549 if (tpg->vdownsampling[p] > 1 && frame_line != frame_line_next) {2550 int avg_pat;2551 2552 /*2553 * Now decide whether we need to use downsampled_lines[].2554 * That's necessary if the two lines use different patterns.2555 */2556 pat_line_next_old = tpg_get_pat_line(tpg,2557 (frame_line_next + mv_vert_old) % tpg->src_height);2558 pat_line_next_new = tpg_get_pat_line(tpg,2559 (frame_line_next + mv_vert_new) % tpg->src_height);2560 2561 switch (tpg->field) {2562 case V4L2_FIELD_INTERLACED:2563 case V4L2_FIELD_INTERLACED_BT:2564 case V4L2_FIELD_INTERLACED_TB:2565 avg_pat = tpg_pattern_avg(tpg, pat_line_old, pat_line_new);2566 if (avg_pat < 0)2567 break;2568 linestart_older = tpg->downsampled_lines[avg_pat][p] + mv_hor_old;2569 linestart_newer = linestart_older;2570 break;2571 case V4L2_FIELD_NONE:2572 case V4L2_FIELD_TOP:2573 case V4L2_FIELD_BOTTOM:2574 case V4L2_FIELD_SEQ_BT:2575 case V4L2_FIELD_SEQ_TB:2576 avg_pat = tpg_pattern_avg(tpg, pat_line_old, pat_line_next_old);2577 if (avg_pat >= 0)2578 linestart_older = tpg->downsampled_lines[avg_pat][p] +2579 mv_hor_old;2580 avg_pat = tpg_pattern_avg(tpg, pat_line_new, pat_line_next_new);2581 if (avg_pat >= 0)2582 linestart_newer = tpg->downsampled_lines[avg_pat][p] +2583 mv_hor_new;2584 break;2585 }2586 }2587 linestart_older += line_offset;2588 linestart_newer += line_offset;2589 }2590 if (tpg->field_alternate) {2591 linestart_top = linestart_bottom = linestart_older;2592 } else if (params->is_60hz) {2593 linestart_top = linestart_newer;2594 linestart_bottom = linestart_older;2595 } else {2596 linestart_top = linestart_older;2597 linestart_bottom = linestart_newer;2598 }2599 2600 switch (tpg->field) {2601 case V4L2_FIELD_INTERLACED:2602 case V4L2_FIELD_INTERLACED_TB:2603 case V4L2_FIELD_SEQ_TB:2604 case V4L2_FIELD_SEQ_BT:2605 if (even)2606 memcpy(vbuf, linestart_top, img_width);2607 else2608 memcpy(vbuf, linestart_bottom, img_width);2609 break;2610 case V4L2_FIELD_INTERLACED_BT:2611 if (even)2612 memcpy(vbuf, linestart_bottom, img_width);2613 else2614 memcpy(vbuf, linestart_top, img_width);2615 break;2616 case V4L2_FIELD_TOP:2617 memcpy(vbuf, linestart_top, img_width);2618 break;2619 case V4L2_FIELD_BOTTOM:2620 memcpy(vbuf, linestart_bottom, img_width);2621 break;2622 case V4L2_FIELD_NONE:2623 default:2624 memcpy(vbuf, linestart_older, img_width);2625 break;2626 }2627}2628 2629void tpg_fill_plane_buffer(struct tpg_data *tpg, v4l2_std_id std,2630 unsigned p, u8 *vbuf)2631{2632 struct tpg_draw_params params;2633 unsigned factor = V4L2_FIELD_HAS_T_OR_B(tpg->field) ? 2 : 1;2634 2635 /* Coarse scaling with Bresenham */2636 unsigned int_part = (tpg->crop.height / factor) / tpg->compose.height;2637 unsigned fract_part = (tpg->crop.height / factor) % tpg->compose.height;2638 unsigned src_y = 0;2639 unsigned error = 0;2640 unsigned h;2641 2642 tpg_recalc(tpg);2643 2644 params.is_tv = std;2645 params.is_60hz = std & V4L2_STD_525_60;2646 params.twopixsize = tpg->twopixelsize[p];2647 params.img_width = tpg_hdiv(tpg, p, tpg->compose.width);2648 params.stride = tpg->bytesperline[p];2649 params.hmax = (tpg->compose.height * tpg->perc_fill) / 100;2650 2651 tpg_fill_params_pattern(tpg, p, ¶ms);2652 tpg_fill_params_extras(tpg, p, ¶ms);2653 2654 vbuf += tpg_hdiv(tpg, p, tpg->compose.left);2655 2656 for (h = 0; h < tpg->compose.height; h++) {2657 unsigned buf_line;2658 2659 params.frame_line = tpg_calc_frameline(tpg, src_y, tpg->field);2660 params.frame_line_next = params.frame_line;2661 buf_line = tpg_calc_buffer_line(tpg, h, tpg->field);2662 src_y += int_part;2663 error += fract_part;2664 if (error >= tpg->compose.height) {2665 error -= tpg->compose.height;2666 src_y++;2667 }2668 2669 /*2670 * For line-interleaved formats determine the 'plane'2671 * based on the buffer line.2672 */2673 if (tpg_g_interleaved(tpg))2674 p = tpg_g_interleaved_plane(tpg, buf_line);2675 2676 if (tpg->vdownsampling[p] > 1) {2677 /*2678 * When doing vertical downsampling the field setting2679 * matters: for SEQ_BT/TB we downsample each field2680 * separately (i.e. lines 0+2 are combined, as are2681 * lines 1+3), for the other field settings we combine2682 * odd and even lines. Doing that for SEQ_BT/TB would2683 * be really weird.2684 */2685 if (tpg->field == V4L2_FIELD_SEQ_BT ||2686 tpg->field == V4L2_FIELD_SEQ_TB) {2687 unsigned next_src_y = src_y;2688 2689 if ((h & 3) >= 2)2690 continue;2691 next_src_y += int_part;2692 if (error + fract_part >= tpg->compose.height)2693 next_src_y++;2694 params.frame_line_next =2695 tpg_calc_frameline(tpg, next_src_y, tpg->field);2696 } else {2697 if (h & 1)2698 continue;2699 params.frame_line_next =2700 tpg_calc_frameline(tpg, src_y, tpg->field);2701 }2702 2703 buf_line /= tpg->vdownsampling[p];2704 }2705 tpg_fill_plane_pattern(tpg, ¶ms, p, h,2706 vbuf + buf_line * params.stride);2707 tpg_fill_plane_extras(tpg, ¶ms, p, h,2708 vbuf + buf_line * params.stride);2709 }2710}2711EXPORT_SYMBOL_GPL(tpg_fill_plane_buffer);2712 2713void tpg_fillbuffer(struct tpg_data *tpg, v4l2_std_id std, unsigned p, u8 *vbuf)2714{2715 unsigned offset = 0;2716 unsigned i;2717 2718 if (tpg->buffers > 1) {2719 tpg_fill_plane_buffer(tpg, std, p, vbuf);2720 return;2721 }2722 2723 for (i = 0; i < tpg_g_planes(tpg); i++) {2724 tpg_fill_plane_buffer(tpg, std, i, vbuf + offset);2725 offset += tpg_calc_plane_size(tpg, i);2726 }2727}2728EXPORT_SYMBOL_GPL(tpg_fillbuffer);2729 2730MODULE_DESCRIPTION("V4L2 Test Pattern Generator");2731MODULE_AUTHOR("Hans Verkuil");2732MODULE_LICENSE("GPL");2733