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